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, pass `NULL` if not needed), see `DMCreateInterpolationScale()` 1202 1203 Level: developer 1204 1205 Notes: 1206 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1207 DMCoarsen(). The coordinates set into the `DMDA` are completely ignored in computing the interpolation. 1208 1209 For `DMDA` objects you can use this interpolation (more precisely the interpolation from the `DMGetCoordinateDM()`) to interpolate the mesh coordinate 1210 vectors EXCEPT in the periodic case where it does not make sense since the coordinate vectors are not periodic. 1211 1212 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateRestriction()`, `DMCreateInterpolationScale()` 1213 @*/ 1214 PetscErrorCode DMCreateInterpolation(DM dmc, DM dmf, Mat *mat, Vec *vec) 1215 { 1216 PetscFunctionBegin; 1217 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1218 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1219 PetscAssertPointer(mat, 3); 1220 PetscCall(PetscLogEventBegin(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1221 PetscUseTypeMethod(dmc, createinterpolation, dmf, mat, vec); 1222 PetscCall(PetscLogEventEnd(DM_CreateInterpolation, dmc, dmf, 0, 0)); 1223 PetscFunctionReturn(PETSC_SUCCESS); 1224 } 1225 1226 /*@ 1227 DMCreateInterpolationScale - Forms L = 1/(R*1) where 1 is the vector of all ones, and R is 1228 the transpose of the interpolation between the `DM`. 1229 1230 Input Parameters: 1231 + dac - `DM` that defines a coarse mesh 1232 . daf - `DM` that defines a fine mesh 1233 - mat - the restriction (or interpolation operator) from fine to coarse 1234 1235 Output Parameter: 1236 . scale - the scaled vector 1237 1238 Level: advanced 1239 1240 Note: 1241 xcoarse = diag(L)*R*xfine preserves scale and is thus suitable for state (versus residual) 1242 restriction. In other words xcoarse is the coarse representation of xfine. 1243 1244 Developer Note: 1245 If the fine-scale `DMDA` has the -dm_bind_below option set to true, then `DMCreateInterpolationScale()` calls `MatSetBindingPropagates()` 1246 on the restriction/interpolation operator to set the bindingpropagates flag to true. 1247 1248 .seealso: [](ch_dmbase), `DM`, `MatRestrict()`, `MatInterpolate()`, `DMCreateInterpolation()`, `DMCreateRestriction()`, `DMCreateGlobalVector()` 1249 @*/ 1250 PetscErrorCode DMCreateInterpolationScale(DM dac, DM daf, Mat mat, Vec *scale) 1251 { 1252 Vec fine; 1253 PetscScalar one = 1.0; 1254 #if defined(PETSC_HAVE_CUDA) 1255 PetscBool bindingpropagates, isbound; 1256 #endif 1257 1258 PetscFunctionBegin; 1259 PetscCall(DMCreateGlobalVector(daf, &fine)); 1260 PetscCall(DMCreateGlobalVector(dac, scale)); 1261 PetscCall(VecSet(fine, one)); 1262 #if defined(PETSC_HAVE_CUDA) 1263 /* If the 'fine' Vec is bound to the CPU, it makes sense to bind 'mat' as well. 1264 * Note that we only do this for the CUDA case, right now, but if we add support for MatMultTranspose() via ViennaCL, 1265 * we'll need to do it for that case, too.*/ 1266 PetscCall(VecGetBindingPropagates(fine, &bindingpropagates)); 1267 if (bindingpropagates) { 1268 PetscCall(MatSetBindingPropagates(mat, PETSC_TRUE)); 1269 PetscCall(VecBoundToCPU(fine, &isbound)); 1270 PetscCall(MatBindToCPU(mat, isbound)); 1271 } 1272 #endif 1273 PetscCall(MatRestrict(mat, fine, *scale)); 1274 PetscCall(VecDestroy(&fine)); 1275 PetscCall(VecReciprocal(*scale)); 1276 PetscFunctionReturn(PETSC_SUCCESS); 1277 } 1278 1279 /*@ 1280 DMCreateRestriction - Gets restriction matrix between two `DM` objects. The resulting matrix map degrees of freedom in the vector obtained by 1281 `DMCreateGlobalVector()` on the fine `DM` to similar vectors on the coarse grid `DM`. 1282 1283 Collective 1284 1285 Input Parameters: 1286 + dmc - the `DM` object 1287 - dmf - the second, finer `DM` object 1288 1289 Output Parameter: 1290 . mat - the restriction 1291 1292 Level: developer 1293 1294 Note: 1295 This only works for `DMSTAG`. For many situations either the transpose of the operator obtained with `DMCreateInterpolation()` or that 1296 matrix multiplied by the vector obtained with `DMCreateInterpolationScale()` provides the desired object. 1297 1298 .seealso: [](ch_dmbase), `DM`, `DMRestrict()`, `DMInterpolate()`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMRefine()`, `DMCoarsen()`, `DMCreateInterpolation()` 1299 @*/ 1300 PetscErrorCode DMCreateRestriction(DM dmc, DM dmf, Mat *mat) 1301 { 1302 PetscFunctionBegin; 1303 PetscValidHeaderSpecific(dmc, DM_CLASSID, 1); 1304 PetscValidHeaderSpecific(dmf, DM_CLASSID, 2); 1305 PetscAssertPointer(mat, 3); 1306 PetscCall(PetscLogEventBegin(DM_CreateRestriction, dmc, dmf, 0, 0)); 1307 PetscUseTypeMethod(dmc, createrestriction, dmf, mat); 1308 PetscCall(PetscLogEventEnd(DM_CreateRestriction, dmc, dmf, 0, 0)); 1309 PetscFunctionReturn(PETSC_SUCCESS); 1310 } 1311 1312 /*@ 1313 DMCreateInjection - Gets injection matrix between two `DM` objects. 1314 1315 Collective 1316 1317 Input Parameters: 1318 + dac - the `DM` object 1319 - daf - the second, finer `DM` object 1320 1321 Output Parameter: 1322 . mat - the injection 1323 1324 Level: developer 1325 1326 Notes: 1327 This is an operator that applied to a vector obtained with `DMCreateGlobalVector()` on the 1328 fine grid maps the values to a vector on the vector on the coarse `DM` by simply selecting 1329 the values on the coarse grid points. This compares to the operator obtained by 1330 `DMCreateRestriction()` or the transpose of the operator obtained by 1331 `DMCreateInterpolation()` that uses a "local weighted average" of the values around the 1332 coarse grid point as the coarse grid value. 1333 1334 For `DMDA` objects this only works for "uniform refinement", that is the refined mesh was obtained `DMRefine()` or the coarse mesh was obtained by 1335 `DMCoarsen()`. The coordinates set into the `DMDA` are completely ignored in computing the injection. 1336 1337 .seealso: [](ch_dmbase), `DM`, `DMDestroy()`, `DMView()`, `DMCreateGlobalVector()`, `DMCreateColoring()`, `DMCreateMatrix()`, `DMCreateMassMatrix()`, `DMCreateInterpolation()`, 1338 `DMCreateRestriction()`, `MatRestrict()`, `MatInterpolate()` 1339 @*/ 1340 PetscErrorCode DMCreateInjection(DM dac, DM daf, Mat *mat) 1341 { 1342 PetscFunctionBegin; 1343 PetscValidHeaderSpecific(dac, DM_CLASSID, 1); 1344 PetscValidHeaderSpecific(daf, DM_CLASSID, 2); 1345 PetscAssertPointer(mat, 3); 1346 PetscCall(PetscLogEventBegin(DM_CreateInjection, dac, daf, 0, 0)); 1347 PetscUseTypeMethod(dac, createinjection, daf, mat); 1348 PetscCall(PetscLogEventEnd(DM_CreateInjection, dac, daf, 0, 0)); 1349 PetscFunctionReturn(PETSC_SUCCESS); 1350 } 1351 1352 /*@ 1353 DMCreateMassMatrix - Gets the mass matrix between two `DM` objects, M_ij = \int \phi_i \psi_j where the \phi are Galerkin basis functions for a 1354 a Galerkin finite element model on the `DM` 1355 1356 Collective 1357 1358 Input Parameters: 1359 + dmc - the target `DM` object 1360 - dmf - the source `DM` object 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`, use `NULL` if not needed 2101 - subdm - The `DM` for the subproblem, use `NULL` if not needed 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`? Plus PETSc creation functions return the thing 4757 they create, this returns nothing 4758 4759 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 4760 @*/ 4761 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection) 4762 { 4763 PetscFunctionBegin; 4764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4765 PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection)); 4766 PetscFunctionReturn(PETSC_SUCCESS); 4767 } 4768 4769 /*@ 4770 DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`. 4771 4772 Not collective but the resulting `PetscSF` is collective 4773 4774 Input Parameter: 4775 . dm - The `DM` 4776 4777 Output Parameter: 4778 . sf - The `PetscSF` 4779 4780 Level: intermediate 4781 4782 Note: 4783 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4784 4785 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4786 @*/ 4787 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf) 4788 { 4789 PetscFunctionBegin; 4790 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4791 PetscAssertPointer(sf, 2); 4792 *sf = dm->sf; 4793 PetscFunctionReturn(PETSC_SUCCESS); 4794 } 4795 4796 /*@ 4797 DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`. 4798 4799 Collective 4800 4801 Input Parameters: 4802 + dm - The `DM` 4803 - sf - The `PetscSF` 4804 4805 Level: intermediate 4806 4807 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4808 @*/ 4809 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf) 4810 { 4811 PetscFunctionBegin; 4812 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4813 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4814 PetscCall(PetscObjectReference((PetscObject)sf)); 4815 PetscCall(PetscSFDestroy(&dm->sf)); 4816 dm->sf = sf; 4817 PetscFunctionReturn(PETSC_SUCCESS); 4818 } 4819 4820 /*@ 4821 DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering 4822 4823 Input Parameter: 4824 . dm - The `DM` 4825 4826 Output Parameter: 4827 . sf - The `PetscSF` 4828 4829 Level: intermediate 4830 4831 Note: 4832 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4833 4834 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4835 @*/ 4836 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf) 4837 { 4838 PetscFunctionBegin; 4839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4840 PetscAssertPointer(sf, 2); 4841 *sf = dm->sfNatural; 4842 PetscFunctionReturn(PETSC_SUCCESS); 4843 } 4844 4845 /*@ 4846 DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering 4847 4848 Input Parameters: 4849 + dm - The DM 4850 - sf - The PetscSF 4851 4852 Level: intermediate 4853 4854 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4855 @*/ 4856 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf) 4857 { 4858 PetscFunctionBegin; 4859 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4860 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4861 PetscCall(PetscObjectReference((PetscObject)sf)); 4862 PetscCall(PetscSFDestroy(&dm->sfNatural)); 4863 dm->sfNatural = sf; 4864 PetscFunctionReturn(PETSC_SUCCESS); 4865 } 4866 4867 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc) 4868 { 4869 PetscClassId id; 4870 4871 PetscFunctionBegin; 4872 PetscCall(PetscObjectGetClassId(disc, &id)); 4873 if (id == PETSCFE_CLASSID) { 4874 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4875 } else if (id == PETSCFV_CLASSID) { 4876 PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE)); 4877 } else { 4878 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4879 } 4880 PetscFunctionReturn(PETSC_SUCCESS); 4881 } 4882 4883 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew) 4884 { 4885 RegionField *tmpr; 4886 PetscInt Nf = dm->Nf, f; 4887 4888 PetscFunctionBegin; 4889 if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS); 4890 PetscCall(PetscMalloc1(NfNew, &tmpr)); 4891 for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f]; 4892 for (f = Nf; f < NfNew; ++f) { 4893 tmpr[f].disc = NULL; 4894 tmpr[f].label = NULL; 4895 tmpr[f].avoidTensor = PETSC_FALSE; 4896 } 4897 PetscCall(PetscFree(dm->fields)); 4898 dm->Nf = NfNew; 4899 dm->fields = tmpr; 4900 PetscFunctionReturn(PETSC_SUCCESS); 4901 } 4902 4903 /*@ 4904 DMClearFields - Remove all fields from the `DM` 4905 4906 Logically Collective 4907 4908 Input Parameter: 4909 . dm - The `DM` 4910 4911 Level: intermediate 4912 4913 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()` 4914 @*/ 4915 PetscErrorCode DMClearFields(DM dm) 4916 { 4917 PetscInt f; 4918 4919 PetscFunctionBegin; 4920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4921 for (f = 0; f < dm->Nf; ++f) { 4922 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4923 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4924 } 4925 PetscCall(PetscFree(dm->fields)); 4926 dm->fields = NULL; 4927 dm->Nf = 0; 4928 PetscFunctionReturn(PETSC_SUCCESS); 4929 } 4930 4931 /*@ 4932 DMGetNumFields - Get the number of fields in the `DM` 4933 4934 Not Collective 4935 4936 Input Parameter: 4937 . dm - The `DM` 4938 4939 Output Parameter: 4940 . numFields - The number of fields 4941 4942 Level: intermediate 4943 4944 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()` 4945 @*/ 4946 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields) 4947 { 4948 PetscFunctionBegin; 4949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4950 PetscAssertPointer(numFields, 2); 4951 *numFields = dm->Nf; 4952 PetscFunctionReturn(PETSC_SUCCESS); 4953 } 4954 4955 /*@ 4956 DMSetNumFields - Set the number of fields in the `DM` 4957 4958 Logically Collective 4959 4960 Input Parameters: 4961 + dm - The `DM` 4962 - numFields - The number of fields 4963 4964 Level: intermediate 4965 4966 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()` 4967 @*/ 4968 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields) 4969 { 4970 PetscInt Nf, f; 4971 4972 PetscFunctionBegin; 4973 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4974 PetscCall(DMGetNumFields(dm, &Nf)); 4975 for (f = Nf; f < numFields; ++f) { 4976 PetscContainer obj; 4977 4978 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj)); 4979 PetscCall(DMAddField(dm, NULL, (PetscObject)obj)); 4980 PetscCall(PetscContainerDestroy(&obj)); 4981 } 4982 PetscFunctionReturn(PETSC_SUCCESS); 4983 } 4984 4985 /*@ 4986 DMGetField - Return the `DMLabel` and discretization object for a given `DM` field 4987 4988 Not Collective 4989 4990 Input Parameters: 4991 + dm - The `DM` 4992 - f - The field number 4993 4994 Output Parameters: 4995 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed) 4996 - disc - The discretization object (pass in `NULL` if not needed) 4997 4998 Level: intermediate 4999 5000 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()` 5001 @*/ 5002 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc) 5003 { 5004 PetscFunctionBegin; 5005 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5006 PetscAssertPointer(disc, 4); 5007 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); 5008 if (label) *label = dm->fields[f].label; 5009 if (disc) *disc = dm->fields[f].disc; 5010 PetscFunctionReturn(PETSC_SUCCESS); 5011 } 5012 5013 /* Does not clear the DS */ 5014 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc) 5015 { 5016 PetscFunctionBegin; 5017 PetscCall(DMFieldEnlarge_Static(dm, f + 1)); 5018 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 5019 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 5020 dm->fields[f].label = label; 5021 dm->fields[f].disc = disc; 5022 PetscCall(PetscObjectReference((PetscObject)label)); 5023 PetscCall(PetscObjectReference((PetscObject)disc)); 5024 PetscFunctionReturn(PETSC_SUCCESS); 5025 } 5026 5027 /*@C 5028 DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles 5029 the field numbering. 5030 5031 Logically Collective 5032 5033 Input Parameters: 5034 + dm - The `DM` 5035 . f - The field number 5036 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5037 - disc - The discretization object 5038 5039 Level: intermediate 5040 5041 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()` 5042 @*/ 5043 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc) 5044 { 5045 PetscFunctionBegin; 5046 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5047 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5048 PetscValidHeader(disc, 4); 5049 PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f); 5050 PetscCall(DMSetField_Internal(dm, f, label, disc)); 5051 PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc)); 5052 PetscCall(DMClearDS(dm)); 5053 PetscFunctionReturn(PETSC_SUCCESS); 5054 } 5055 5056 /*@C 5057 DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities) 5058 and a discretization object that defines the function space associated with those points. 5059 5060 Logically Collective 5061 5062 Input Parameters: 5063 + dm - The `DM` 5064 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5065 - disc - The discretization object 5066 5067 Level: intermediate 5068 5069 Notes: 5070 The label already exists or will be added to the `DM` with `DMSetLabel()`. 5071 5072 For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions 5073 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 5074 geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`. 5075 5076 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE` 5077 @*/ 5078 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc) 5079 { 5080 PetscInt Nf = dm->Nf; 5081 5082 PetscFunctionBegin; 5083 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5084 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5085 PetscValidHeader(disc, 3); 5086 PetscCall(DMFieldEnlarge_Static(dm, Nf + 1)); 5087 dm->fields[Nf].label = label; 5088 dm->fields[Nf].disc = disc; 5089 PetscCall(PetscObjectReference((PetscObject)label)); 5090 PetscCall(PetscObjectReference((PetscObject)disc)); 5091 PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc)); 5092 PetscCall(DMClearDS(dm)); 5093 PetscFunctionReturn(PETSC_SUCCESS); 5094 } 5095 5096 /*@ 5097 DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells 5098 5099 Logically Collective 5100 5101 Input Parameters: 5102 + dm - The `DM` 5103 . f - The field index 5104 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells 5105 5106 Level: intermediate 5107 5108 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()` 5109 @*/ 5110 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor) 5111 { 5112 PetscFunctionBegin; 5113 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); 5114 dm->fields[f].avoidTensor = avoidTensor; 5115 PetscFunctionReturn(PETSC_SUCCESS); 5116 } 5117 5118 /*@ 5119 DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells 5120 5121 Not Collective 5122 5123 Input Parameters: 5124 + dm - The `DM` 5125 - f - The field index 5126 5127 Output Parameter: 5128 . avoidTensor - The flag to avoid defining the field on tensor cells 5129 5130 Level: intermediate 5131 5132 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()` 5133 @*/ 5134 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor) 5135 { 5136 PetscFunctionBegin; 5137 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); 5138 *avoidTensor = dm->fields[f].avoidTensor; 5139 PetscFunctionReturn(PETSC_SUCCESS); 5140 } 5141 5142 /*@ 5143 DMCopyFields - Copy the discretizations for the `DM` into another `DM` 5144 5145 Collective 5146 5147 Input Parameter: 5148 . dm - The `DM` 5149 5150 Output Parameter: 5151 . newdm - The `DM` 5152 5153 Level: advanced 5154 5155 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()` 5156 @*/ 5157 PetscErrorCode DMCopyFields(DM dm, DM newdm) 5158 { 5159 PetscInt Nf, f; 5160 5161 PetscFunctionBegin; 5162 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 5163 PetscCall(DMGetNumFields(dm, &Nf)); 5164 PetscCall(DMClearFields(newdm)); 5165 for (f = 0; f < Nf; ++f) { 5166 DMLabel label; 5167 PetscObject field; 5168 PetscBool useCone, useClosure; 5169 5170 PetscCall(DMGetField(dm, f, &label, &field)); 5171 PetscCall(DMSetField(newdm, f, label, field)); 5172 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure)); 5173 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure)); 5174 } 5175 PetscFunctionReturn(PETSC_SUCCESS); 5176 } 5177 5178 /*@ 5179 DMGetAdjacency - Returns the flags for determining variable influence 5180 5181 Not Collective 5182 5183 Input Parameters: 5184 + dm - The `DM` object 5185 - f - The field number, or `PETSC_DEFAULT` for the default adjacency 5186 5187 Output Parameters: 5188 + useCone - Flag for variable influence starting with the cone operation 5189 - useClosure - Flag for variable influence using transitive closure 5190 5191 Level: developer 5192 5193 Notes: 5194 .vb 5195 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5196 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5197 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5198 .ve 5199 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5200 5201 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()` 5202 @*/ 5203 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure) 5204 { 5205 PetscFunctionBegin; 5206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5207 if (useCone) PetscAssertPointer(useCone, 3); 5208 if (useClosure) PetscAssertPointer(useClosure, 4); 5209 if (f < 0) { 5210 if (useCone) *useCone = dm->adjacency[0]; 5211 if (useClosure) *useClosure = dm->adjacency[1]; 5212 } else { 5213 PetscInt Nf; 5214 5215 PetscCall(DMGetNumFields(dm, &Nf)); 5216 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5217 if (useCone) *useCone = dm->fields[f].adjacency[0]; 5218 if (useClosure) *useClosure = dm->fields[f].adjacency[1]; 5219 } 5220 PetscFunctionReturn(PETSC_SUCCESS); 5221 } 5222 5223 /*@ 5224 DMSetAdjacency - Set the flags for determining variable influence 5225 5226 Not Collective 5227 5228 Input Parameters: 5229 + dm - The `DM` object 5230 . f - The field number 5231 . useCone - Flag for variable influence starting with the cone operation 5232 - useClosure - Flag for variable influence using transitive closure 5233 5234 Level: developer 5235 5236 Notes: 5237 .vb 5238 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5239 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5240 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5241 .ve 5242 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5243 5244 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()` 5245 @*/ 5246 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure) 5247 { 5248 PetscFunctionBegin; 5249 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5250 if (f < 0) { 5251 dm->adjacency[0] = useCone; 5252 dm->adjacency[1] = useClosure; 5253 } else { 5254 PetscInt Nf; 5255 5256 PetscCall(DMGetNumFields(dm, &Nf)); 5257 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5258 dm->fields[f].adjacency[0] = useCone; 5259 dm->fields[f].adjacency[1] = useClosure; 5260 } 5261 PetscFunctionReturn(PETSC_SUCCESS); 5262 } 5263 5264 /*@ 5265 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined 5266 5267 Not collective 5268 5269 Input Parameter: 5270 . dm - The `DM` object 5271 5272 Output Parameters: 5273 + useCone - Flag for variable influence starting with the cone operation 5274 - useClosure - Flag for variable influence using transitive closure 5275 5276 Level: developer 5277 5278 Notes: 5279 .vb 5280 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5281 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5282 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5283 .ve 5284 5285 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5286 @*/ 5287 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure) 5288 { 5289 PetscInt Nf; 5290 5291 PetscFunctionBegin; 5292 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5293 if (useCone) PetscAssertPointer(useCone, 2); 5294 if (useClosure) PetscAssertPointer(useClosure, 3); 5295 PetscCall(DMGetNumFields(dm, &Nf)); 5296 if (!Nf) { 5297 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5298 } else { 5299 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure)); 5300 } 5301 PetscFunctionReturn(PETSC_SUCCESS); 5302 } 5303 5304 /*@ 5305 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined 5306 5307 Not Collective 5308 5309 Input Parameters: 5310 + dm - The `DM` object 5311 . useCone - Flag for variable influence starting with the cone operation 5312 - useClosure - Flag for variable influence using transitive closure 5313 5314 Level: developer 5315 5316 Notes: 5317 .vb 5318 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5319 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5320 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5321 .ve 5322 5323 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5324 @*/ 5325 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure) 5326 { 5327 PetscInt Nf; 5328 5329 PetscFunctionBegin; 5330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5331 PetscCall(DMGetNumFields(dm, &Nf)); 5332 if (!Nf) { 5333 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5334 } else { 5335 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure)); 5336 } 5337 PetscFunctionReturn(PETSC_SUCCESS); 5338 } 5339 5340 PetscErrorCode DMCompleteBCLabels_Internal(DM dm) 5341 { 5342 DM plex; 5343 DMLabel *labels, *glabels; 5344 const char **names; 5345 char *sendNames, *recvNames; 5346 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m; 5347 size_t len; 5348 MPI_Comm comm; 5349 PetscMPIInt rank, size, p, *counts, *displs; 5350 5351 PetscFunctionBegin; 5352 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5353 PetscCallMPI(MPI_Comm_size(comm, &size)); 5354 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5355 PetscCall(DMGetNumDS(dm, &Nds)); 5356 for (s = 0; s < Nds; ++s) { 5357 PetscDS dsBC; 5358 PetscInt numBd; 5359 5360 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5361 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5362 maxLabels += numBd; 5363 } 5364 PetscCall(PetscCalloc1(maxLabels, &labels)); 5365 /* Get list of labels to be completed */ 5366 for (s = 0; s < Nds; ++s) { 5367 PetscDS dsBC; 5368 PetscInt numBd, bd; 5369 5370 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5371 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5372 for (bd = 0; bd < numBd; ++bd) { 5373 DMLabel label; 5374 PetscInt field; 5375 PetscObject obj; 5376 PetscClassId id; 5377 5378 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5379 PetscCall(DMGetField(dm, field, NULL, &obj)); 5380 PetscCall(PetscObjectGetClassId(obj, &id)); 5381 if (!(id == PETSCFE_CLASSID) || !label) continue; 5382 for (l = 0; l < Nl; ++l) 5383 if (labels[l] == label) break; 5384 if (l == Nl) labels[Nl++] = label; 5385 } 5386 } 5387 /* Get label names */ 5388 PetscCall(PetscMalloc1(Nl, &names)); 5389 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l])); 5390 for (l = 0; l < Nl; ++l) { 5391 PetscCall(PetscStrlen(names[l], &len)); 5392 maxLen = PetscMax(maxLen, (PetscInt)len + 2); 5393 } 5394 PetscCall(PetscFree(labels)); 5395 PetscCall(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm)); 5396 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames)); 5397 for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen)); 5398 PetscCall(PetscFree(names)); 5399 /* Put all names on all processes */ 5400 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs)); 5401 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm)); 5402 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p]; 5403 gNl = displs[size]; 5404 for (p = 0; p < size; ++p) { 5405 counts[p] *= gmaxLen; 5406 displs[p] *= gmaxLen; 5407 } 5408 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels)); 5409 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm)); 5410 PetscCall(PetscFree2(counts, displs)); 5411 PetscCall(PetscFree(sendNames)); 5412 for (l = 0, gl = 0; l < gNl; ++l) { 5413 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl])); 5414 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank); 5415 for (m = 0; m < gl; ++m) 5416 if (glabels[m] == glabels[gl]) continue; 5417 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5418 PetscCall(DMPlexLabelComplete(plex, glabels[gl])); 5419 PetscCall(DMDestroy(&plex)); 5420 ++gl; 5421 } 5422 PetscCall(PetscFree2(recvNames, glabels)); 5423 PetscFunctionReturn(PETSC_SUCCESS); 5424 } 5425 5426 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5427 { 5428 DMSpace *tmpd; 5429 PetscInt Nds = dm->Nds, s; 5430 5431 PetscFunctionBegin; 5432 if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS); 5433 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5434 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5435 for (s = Nds; s < NdsNew; ++s) { 5436 tmpd[s].ds = NULL; 5437 tmpd[s].label = NULL; 5438 tmpd[s].fields = NULL; 5439 } 5440 PetscCall(PetscFree(dm->probs)); 5441 dm->Nds = NdsNew; 5442 dm->probs = tmpd; 5443 PetscFunctionReturn(PETSC_SUCCESS); 5444 } 5445 5446 /*@ 5447 DMGetNumDS - Get the number of discrete systems in the `DM` 5448 5449 Not Collective 5450 5451 Input Parameter: 5452 . dm - The `DM` 5453 5454 Output Parameter: 5455 . Nds - The number of `PetscDS` objects 5456 5457 Level: intermediate 5458 5459 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()` 5460 @*/ 5461 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5462 { 5463 PetscFunctionBegin; 5464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5465 PetscAssertPointer(Nds, 2); 5466 *Nds = dm->Nds; 5467 PetscFunctionReturn(PETSC_SUCCESS); 5468 } 5469 5470 /*@ 5471 DMClearDS - Remove all discrete systems from the `DM` 5472 5473 Logically Collective 5474 5475 Input Parameter: 5476 . dm - The `DM` 5477 5478 Level: intermediate 5479 5480 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()` 5481 @*/ 5482 PetscErrorCode DMClearDS(DM dm) 5483 { 5484 PetscInt s; 5485 5486 PetscFunctionBegin; 5487 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5488 for (s = 0; s < dm->Nds; ++s) { 5489 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5490 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5491 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5492 PetscCall(ISDestroy(&dm->probs[s].fields)); 5493 } 5494 PetscCall(PetscFree(dm->probs)); 5495 dm->probs = NULL; 5496 dm->Nds = 0; 5497 PetscFunctionReturn(PETSC_SUCCESS); 5498 } 5499 5500 /*@ 5501 DMGetDS - Get the default `PetscDS` 5502 5503 Not Collective 5504 5505 Input Parameter: 5506 . dm - The `DM` 5507 5508 Output Parameter: 5509 . ds - The default `PetscDS` 5510 5511 Level: intermediate 5512 5513 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()` 5514 @*/ 5515 PetscErrorCode DMGetDS(DM dm, PetscDS *ds) 5516 { 5517 PetscFunctionBeginHot; 5518 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5519 PetscAssertPointer(ds, 2); 5520 PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()"); 5521 *ds = dm->probs[0].ds; 5522 PetscFunctionReturn(PETSC_SUCCESS); 5523 } 5524 5525 /*@ 5526 DMGetCellDS - Get the `PetscDS` defined on a given cell 5527 5528 Not Collective 5529 5530 Input Parameters: 5531 + dm - The `DM` 5532 - point - Cell for the `PetscDS` 5533 5534 Output Parameters: 5535 + ds - The `PetscDS` defined on the given cell 5536 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds 5537 5538 Level: developer 5539 5540 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()` 5541 @*/ 5542 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn) 5543 { 5544 PetscDS dsDef = NULL; 5545 PetscInt s; 5546 5547 PetscFunctionBeginHot; 5548 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5549 if (ds) PetscAssertPointer(ds, 3); 5550 if (dsIn) PetscAssertPointer(dsIn, 4); 5551 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5552 if (ds) *ds = NULL; 5553 if (dsIn) *dsIn = NULL; 5554 for (s = 0; s < dm->Nds; ++s) { 5555 PetscInt val; 5556 5557 if (!dm->probs[s].label) { 5558 dsDef = dm->probs[s].ds; 5559 } else { 5560 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5561 if (val >= 0) { 5562 if (ds) *ds = dm->probs[s].ds; 5563 if (dsIn) *dsIn = dm->probs[s].dsIn; 5564 break; 5565 } 5566 } 5567 } 5568 if (ds && !*ds) *ds = dsDef; 5569 PetscFunctionReturn(PETSC_SUCCESS); 5570 } 5571 5572 /*@ 5573 DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel` 5574 5575 Not Collective 5576 5577 Input Parameters: 5578 + dm - The `DM` 5579 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5580 5581 Output Parameters: 5582 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5583 . ds - The `PetscDS` defined on the given region, or `NULL` 5584 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5585 5586 Level: advanced 5587 5588 Note: 5589 If a non-`NULL` label is given, but there is no `PetscDS` on that specific label, 5590 the `PetscDS` for the full domain (if present) is returned. Returns with 5591 fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain. 5592 5593 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5594 @*/ 5595 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5596 { 5597 PetscInt Nds = dm->Nds, s; 5598 5599 PetscFunctionBegin; 5600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5601 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5602 if (fields) { 5603 PetscAssertPointer(fields, 3); 5604 *fields = NULL; 5605 } 5606 if (ds) { 5607 PetscAssertPointer(ds, 4); 5608 *ds = NULL; 5609 } 5610 if (dsIn) { 5611 PetscAssertPointer(dsIn, 5); 5612 *dsIn = NULL; 5613 } 5614 for (s = 0; s < Nds; ++s) { 5615 if (dm->probs[s].label == label || !dm->probs[s].label) { 5616 if (fields) *fields = dm->probs[s].fields; 5617 if (ds) *ds = dm->probs[s].ds; 5618 if (dsIn) *dsIn = dm->probs[s].dsIn; 5619 if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS); 5620 } 5621 } 5622 PetscFunctionReturn(PETSC_SUCCESS); 5623 } 5624 5625 /*@ 5626 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel` 5627 5628 Collective 5629 5630 Input Parameters: 5631 + dm - The `DM` 5632 . label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5633 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields 5634 . ds - The `PetscDS` defined on the given region 5635 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5636 5637 Level: advanced 5638 5639 Note: 5640 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced, 5641 the fields argument is ignored. 5642 5643 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()` 5644 @*/ 5645 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5646 { 5647 PetscInt Nds = dm->Nds, s; 5648 5649 PetscFunctionBegin; 5650 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5651 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5652 if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3); 5653 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5654 if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5); 5655 for (s = 0; s < Nds; ++s) { 5656 if (dm->probs[s].label == label) { 5657 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5658 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5659 dm->probs[s].ds = ds; 5660 dm->probs[s].dsIn = dsIn; 5661 PetscFunctionReturn(PETSC_SUCCESS); 5662 } 5663 } 5664 PetscCall(DMDSEnlarge_Static(dm, Nds + 1)); 5665 PetscCall(PetscObjectReference((PetscObject)label)); 5666 PetscCall(PetscObjectReference((PetscObject)fields)); 5667 PetscCall(PetscObjectReference((PetscObject)ds)); 5668 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5669 if (!label) { 5670 /* Put the NULL label at the front, so it is returned as the default */ 5671 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s]; 5672 Nds = 0; 5673 } 5674 dm->probs[Nds].label = label; 5675 dm->probs[Nds].fields = fields; 5676 dm->probs[Nds].ds = ds; 5677 dm->probs[Nds].dsIn = dsIn; 5678 PetscFunctionReturn(PETSC_SUCCESS); 5679 } 5680 5681 /*@ 5682 DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number 5683 5684 Not Collective 5685 5686 Input Parameters: 5687 + dm - The `DM` 5688 - num - The region number, in [0, Nds) 5689 5690 Output Parameters: 5691 + label - The region label, or `NULL` 5692 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5693 . ds - The `PetscDS` defined on the given region, or `NULL` 5694 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5695 5696 Level: advanced 5697 5698 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5699 @*/ 5700 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5701 { 5702 PetscInt Nds; 5703 5704 PetscFunctionBegin; 5705 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5706 PetscCall(DMGetNumDS(dm, &Nds)); 5707 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5708 if (label) { 5709 PetscAssertPointer(label, 3); 5710 *label = dm->probs[num].label; 5711 } 5712 if (fields) { 5713 PetscAssertPointer(fields, 4); 5714 *fields = dm->probs[num].fields; 5715 } 5716 if (ds) { 5717 PetscAssertPointer(ds, 5); 5718 *ds = dm->probs[num].ds; 5719 } 5720 if (dsIn) { 5721 PetscAssertPointer(dsIn, 6); 5722 *dsIn = dm->probs[num].dsIn; 5723 } 5724 PetscFunctionReturn(PETSC_SUCCESS); 5725 } 5726 5727 /*@ 5728 DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number 5729 5730 Not Collective 5731 5732 Input Parameters: 5733 + dm - The `DM` 5734 . num - The region number, in [0, Nds) 5735 . label - The region label, or `NULL` 5736 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting 5737 . ds - The `PetscDS` defined on the given region, or `NULL` to prevent setting 5738 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5739 5740 Level: advanced 5741 5742 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5743 @*/ 5744 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5745 { 5746 PetscInt Nds; 5747 5748 PetscFunctionBegin; 5749 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5750 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5751 PetscCall(DMGetNumDS(dm, &Nds)); 5752 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5753 PetscCall(PetscObjectReference((PetscObject)label)); 5754 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5755 dm->probs[num].label = label; 5756 if (fields) { 5757 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5758 PetscCall(PetscObjectReference((PetscObject)fields)); 5759 PetscCall(ISDestroy(&dm->probs[num].fields)); 5760 dm->probs[num].fields = fields; 5761 } 5762 if (ds) { 5763 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5764 PetscCall(PetscObjectReference((PetscObject)ds)); 5765 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5766 dm->probs[num].ds = ds; 5767 } 5768 if (dsIn) { 5769 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6); 5770 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5771 PetscCall(PetscDSDestroy(&dm->probs[num].dsIn)); 5772 dm->probs[num].dsIn = dsIn; 5773 } 5774 PetscFunctionReturn(PETSC_SUCCESS); 5775 } 5776 5777 /*@ 5778 DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found. 5779 5780 Not Collective 5781 5782 Input Parameters: 5783 + dm - The `DM` 5784 - ds - The `PetscDS` defined on the given region 5785 5786 Output Parameter: 5787 . num - The region number, in [0, Nds), or -1 if not found 5788 5789 Level: advanced 5790 5791 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5792 @*/ 5793 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5794 { 5795 PetscInt Nds, n; 5796 5797 PetscFunctionBegin; 5798 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5799 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5800 PetscAssertPointer(num, 3); 5801 PetscCall(DMGetNumDS(dm, &Nds)); 5802 for (n = 0; n < Nds; ++n) 5803 if (ds == dm->probs[n].ds) break; 5804 if (n >= Nds) *num = -1; 5805 else *num = n; 5806 PetscFunctionReturn(PETSC_SUCCESS); 5807 } 5808 5809 /*@C 5810 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh 5811 5812 Not Collective 5813 5814 Input Parameters: 5815 + dm - The `DM` 5816 . Nc - The number of components for the field 5817 . prefix - The options prefix for the output `PetscFE`, or `NULL` 5818 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree 5819 5820 Output Parameter: 5821 . fem - The `PetscFE` 5822 5823 Level: intermediate 5824 5825 Note: 5826 This is a convenience method that just calls `PetscFECreateByCell()` underneath. 5827 5828 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()` 5829 @*/ 5830 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5831 { 5832 DMPolytopeType ct; 5833 PetscInt dim, cStart; 5834 5835 PetscFunctionBegin; 5836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5837 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5838 if (prefix) PetscAssertPointer(prefix, 3); 5839 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5840 PetscAssertPointer(fem, 5); 5841 PetscCall(DMGetDimension(dm, &dim)); 5842 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5843 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5844 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5845 PetscFunctionReturn(PETSC_SUCCESS); 5846 } 5847 5848 /*@ 5849 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM` 5850 5851 Collective 5852 5853 Input Parameter: 5854 . dm - The `DM` 5855 5856 Options Database Key: 5857 . -dm_petscds_view - View all the `PetscDS` objects in this `DM` 5858 5859 Level: intermediate 5860 5861 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 5862 @*/ 5863 PetscErrorCode DMCreateDS(DM dm) 5864 { 5865 MPI_Comm comm; 5866 PetscDS dsDef; 5867 DMLabel *labelSet; 5868 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5869 PetscBool doSetup = PETSC_TRUE, flg; 5870 5871 PetscFunctionBegin; 5872 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5873 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); 5874 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5875 PetscCall(DMGetCoordinateDim(dm, &dE)); 5876 /* Determine how many regions we have */ 5877 PetscCall(PetscMalloc1(Nf, &labelSet)); 5878 Nl = 0; 5879 Ndef = 0; 5880 for (f = 0; f < Nf; ++f) { 5881 DMLabel label = dm->fields[f].label; 5882 PetscInt l; 5883 5884 #ifdef PETSC_HAVE_LIBCEED 5885 /* Move CEED context to discretizations */ 5886 { 5887 PetscClassId id; 5888 5889 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5890 if (id == PETSCFE_CLASSID) { 5891 Ceed ceed; 5892 5893 PetscCall(DMGetCeed(dm, &ceed)); 5894 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed)); 5895 } 5896 } 5897 #endif 5898 if (!label) { 5899 ++Ndef; 5900 continue; 5901 } 5902 for (l = 0; l < Nl; ++l) 5903 if (label == labelSet[l]) break; 5904 if (l < Nl) continue; 5905 labelSet[Nl++] = label; 5906 } 5907 /* Create default DS if there are no labels to intersect with */ 5908 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5909 if (!dsDef && Ndef && !Nl) { 5910 IS fields; 5911 PetscInt *fld, nf; 5912 5913 for (f = 0, nf = 0; f < Nf; ++f) 5914 if (!dm->fields[f].label) ++nf; 5915 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5916 PetscCall(PetscMalloc1(nf, &fld)); 5917 for (f = 0, nf = 0; f < Nf; ++f) 5918 if (!dm->fields[f].label) fld[nf++] = f; 5919 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5920 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5921 PetscCall(ISSetType(fields, ISGENERAL)); 5922 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5923 5924 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5925 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL)); 5926 PetscCall(PetscDSDestroy(&dsDef)); 5927 PetscCall(ISDestroy(&fields)); 5928 } 5929 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5930 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5931 /* Intersect labels with default fields */ 5932 if (Ndef && Nl) { 5933 DM plex; 5934 DMLabel cellLabel; 5935 IS fieldIS, allcellIS, defcellIS = NULL; 5936 PetscInt *fields; 5937 const PetscInt *cells; 5938 PetscInt depth, nf = 0, n, c; 5939 5940 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5941 PetscCall(DMPlexGetDepth(plex, &depth)); 5942 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 5943 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 5944 /* TODO This looks like it only works for one label */ 5945 for (l = 0; l < Nl; ++l) { 5946 DMLabel label = labelSet[l]; 5947 IS pointIS; 5948 5949 PetscCall(ISDestroy(&defcellIS)); 5950 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 5951 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 5952 PetscCall(ISDestroy(&pointIS)); 5953 } 5954 PetscCall(ISDestroy(&allcellIS)); 5955 5956 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 5957 PetscCall(ISGetLocalSize(defcellIS, &n)); 5958 PetscCall(ISGetIndices(defcellIS, &cells)); 5959 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 5960 PetscCall(ISRestoreIndices(defcellIS, &cells)); 5961 PetscCall(ISDestroy(&defcellIS)); 5962 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 5963 5964 PetscCall(PetscMalloc1(Ndef, &fields)); 5965 for (f = 0; f < Nf; ++f) 5966 if (!dm->fields[f].label) fields[nf++] = f; 5967 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 5968 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_")); 5969 PetscCall(ISSetType(fieldIS, ISGENERAL)); 5970 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 5971 5972 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5973 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL)); 5974 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5975 PetscCall(DMLabelDestroy(&cellLabel)); 5976 PetscCall(PetscDSDestroy(&dsDef)); 5977 PetscCall(ISDestroy(&fieldIS)); 5978 PetscCall(DMDestroy(&plex)); 5979 } 5980 /* Create label DSes 5981 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 5982 */ 5983 /* TODO Should check that labels are disjoint */ 5984 for (l = 0; l < Nl; ++l) { 5985 DMLabel label = labelSet[l]; 5986 PetscDS ds, dsIn = NULL; 5987 IS fields; 5988 PetscInt *fld, nf; 5989 5990 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5991 for (f = 0, nf = 0; f < Nf; ++f) 5992 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 5993 PetscCall(PetscMalloc1(nf, &fld)); 5994 for (f = 0, nf = 0; f < Nf; ++f) 5995 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 5996 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5997 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5998 PetscCall(ISSetType(fields, ISGENERAL)); 5999 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 6000 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 6001 { 6002 DMPolytopeType ct; 6003 PetscInt lStart, lEnd; 6004 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 6005 6006 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 6007 if (lStart >= 0) { 6008 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 6009 switch (ct) { 6010 case DM_POLYTOPE_POINT_PRISM_TENSOR: 6011 case DM_POLYTOPE_SEG_PRISM_TENSOR: 6012 case DM_POLYTOPE_TRI_PRISM_TENSOR: 6013 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 6014 isCohesiveLocal = PETSC_TRUE; 6015 break; 6016 default: 6017 break; 6018 } 6019 } 6020 PetscCall(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 6021 if (isCohesive) { 6022 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn)); 6023 PetscCall(PetscDSSetCoordinateDimension(dsIn, dE)); 6024 } 6025 for (f = 0, nf = 0; f < Nf; ++f) { 6026 if (label == dm->fields[f].label || !dm->fields[f].label) { 6027 if (label == dm->fields[f].label) { 6028 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 6029 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 6030 if (dsIn) { 6031 PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL)); 6032 PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive)); 6033 } 6034 } 6035 ++nf; 6036 } 6037 } 6038 } 6039 PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn)); 6040 PetscCall(ISDestroy(&fields)); 6041 PetscCall(PetscDSDestroy(&ds)); 6042 PetscCall(PetscDSDestroy(&dsIn)); 6043 } 6044 PetscCall(PetscFree(labelSet)); 6045 /* Set fields in DSes */ 6046 for (s = 0; s < dm->Nds; ++s) { 6047 PetscDS ds = dm->probs[s].ds; 6048 PetscDS dsIn = dm->probs[s].dsIn; 6049 IS fields = dm->probs[s].fields; 6050 const PetscInt *fld; 6051 PetscInt nf, dsnf; 6052 PetscBool isCohesive; 6053 6054 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 6055 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 6056 PetscCall(ISGetLocalSize(fields, &nf)); 6057 PetscCall(ISGetIndices(fields, &fld)); 6058 for (f = 0; f < nf; ++f) { 6059 PetscObject disc = dm->fields[fld[f]].disc; 6060 PetscBool isCohesiveField; 6061 PetscClassId id; 6062 6063 /* Handle DS with no fields */ 6064 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 6065 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 6066 if (isCohesive) { 6067 if (!isCohesiveField) { 6068 PetscObject bdDisc; 6069 6070 PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc)); 6071 PetscCall(PetscDSSetDiscretization(ds, f, bdDisc)); 6072 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6073 } else { 6074 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6075 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6076 } 6077 } else { 6078 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6079 } 6080 /* We allow people to have placeholder fields and construct the Section by hand */ 6081 PetscCall(PetscObjectGetClassId(disc, &id)); 6082 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 6083 } 6084 PetscCall(ISRestoreIndices(fields, &fld)); 6085 } 6086 /* Allow k-jet tabulation */ 6087 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 6088 if (flg) { 6089 for (s = 0; s < dm->Nds; ++s) { 6090 PetscDS ds = dm->probs[s].ds; 6091 PetscDS dsIn = dm->probs[s].dsIn; 6092 PetscInt Nf, f; 6093 6094 PetscCall(PetscDSGetNumFields(ds, &Nf)); 6095 for (f = 0; f < Nf; ++f) { 6096 PetscCall(PetscDSSetJetDegree(ds, f, k)); 6097 if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k)); 6098 } 6099 } 6100 } 6101 /* Setup DSes */ 6102 if (doSetup) { 6103 for (s = 0; s < dm->Nds; ++s) { 6104 if (dm->setfromoptionscalled) { 6105 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds)); 6106 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn)); 6107 } 6108 PetscCall(PetscDSSetUp(dm->probs[s].ds)); 6109 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn)); 6110 } 6111 } 6112 PetscFunctionReturn(PETSC_SUCCESS); 6113 } 6114 6115 /*@ 6116 DMUseTensorOrder - Use a tensor product closure ordering for the default section 6117 6118 Input Parameters: 6119 + dm - The DM 6120 - tensor - Flag for tensor order 6121 6122 Level: developer 6123 6124 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()` 6125 @*/ 6126 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor) 6127 { 6128 PetscInt Nf; 6129 PetscBool reorder = PETSC_TRUE, isPlex; 6130 6131 PetscFunctionBegin; 6132 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 6133 PetscCall(DMGetNumFields(dm, &Nf)); 6134 for (PetscInt f = 0; f < Nf; ++f) { 6135 PetscObject obj; 6136 PetscClassId id; 6137 6138 PetscCall(DMGetField(dm, f, NULL, &obj)); 6139 PetscCall(PetscObjectGetClassId(obj, &id)); 6140 if (id == PETSCFE_CLASSID) { 6141 PetscSpace sp; 6142 PetscBool tensor; 6143 6144 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp)); 6145 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor)); 6146 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE; 6147 } else reorder = PETSC_FALSE; 6148 } 6149 if (tensor) { 6150 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 6151 } else { 6152 PetscSection s; 6153 6154 PetscCall(DMGetLocalSection(dm, &s)); 6155 if (s) PetscCall(PetscSectionResetClosurePermutation(s)); 6156 } 6157 PetscFunctionReturn(PETSC_SUCCESS); 6158 } 6159 6160 /*@ 6161 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 6162 6163 Collective 6164 6165 Input Parameters: 6166 + dm - The `DM` 6167 - time - The time 6168 6169 Output Parameters: 6170 + u - The vector will be filled with exact solution values, or `NULL` 6171 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL` 6172 6173 Level: developer 6174 6175 Note: 6176 The user must call `PetscDSSetExactSolution()` before using this routine 6177 6178 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()` 6179 @*/ 6180 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 6181 { 6182 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 6183 void **ectxs; 6184 Vec locu, locu_t; 6185 PetscInt Nf, Nds, s; 6186 6187 PetscFunctionBegin; 6188 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6189 if (u) { 6190 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 6191 PetscCall(DMGetLocalVector(dm, &locu)); 6192 PetscCall(VecSet(locu, 0.)); 6193 } 6194 if (u_t) { 6195 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 6196 PetscCall(DMGetLocalVector(dm, &locu_t)); 6197 PetscCall(VecSet(locu_t, 0.)); 6198 } 6199 PetscCall(DMGetNumFields(dm, &Nf)); 6200 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 6201 PetscCall(DMGetNumDS(dm, &Nds)); 6202 for (s = 0; s < Nds; ++s) { 6203 PetscDS ds; 6204 DMLabel label; 6205 IS fieldIS; 6206 const PetscInt *fields, id = 1; 6207 PetscInt dsNf, f; 6208 6209 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 6210 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6211 PetscCall(ISGetIndices(fieldIS, &fields)); 6212 PetscCall(PetscArrayzero(exacts, Nf)); 6213 PetscCall(PetscArrayzero(ectxs, Nf)); 6214 if (u) { 6215 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6216 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6217 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6218 } 6219 if (u_t) { 6220 PetscCall(PetscArrayzero(exacts, Nf)); 6221 PetscCall(PetscArrayzero(ectxs, Nf)); 6222 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6223 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6224 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6225 } 6226 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6227 } 6228 if (u) { 6229 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6230 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6231 } 6232 if (u_t) { 6233 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6234 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6235 } 6236 PetscCall(PetscFree2(exacts, ectxs)); 6237 if (u) { 6238 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u)); 6239 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u)); 6240 PetscCall(DMRestoreLocalVector(dm, &locu)); 6241 } 6242 if (u_t) { 6243 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6244 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6245 PetscCall(DMRestoreLocalVector(dm, &locu_t)); 6246 } 6247 PetscFunctionReturn(PETSC_SUCCESS); 6248 } 6249 6250 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 6251 { 6252 PetscDS dsNew, dsInNew = NULL; 6253 6254 PetscFunctionBegin; 6255 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6256 PetscCall(PetscDSCopy(ds, dm, dsNew)); 6257 if (dsIn) { 6258 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew)); 6259 PetscCall(PetscDSCopy(dsIn, dm, dsInNew)); 6260 } 6261 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew)); 6262 PetscCall(PetscDSDestroy(&dsNew)); 6263 PetscCall(PetscDSDestroy(&dsInNew)); 6264 PetscFunctionReturn(PETSC_SUCCESS); 6265 } 6266 6267 /*@ 6268 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6269 6270 Collective 6271 6272 Input Parameter: 6273 . dm - The `DM` 6274 6275 Output Parameter: 6276 . newdm - The `DM` 6277 6278 Level: advanced 6279 6280 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6281 @*/ 6282 PetscErrorCode DMCopyDS(DM dm, DM newdm) 6283 { 6284 PetscInt Nds, s; 6285 6286 PetscFunctionBegin; 6287 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 6288 PetscCall(DMGetNumDS(dm, &Nds)); 6289 PetscCall(DMClearDS(newdm)); 6290 for (s = 0; s < Nds; ++s) { 6291 DMLabel label; 6292 IS fields; 6293 PetscDS ds, dsIn, newds; 6294 PetscInt Nbd, bd; 6295 6296 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn)); 6297 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6298 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn)); 6299 /* Complete new labels in the new DS */ 6300 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL)); 6301 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6302 for (bd = 0; bd < Nbd; ++bd) { 6303 PetscWeakForm wf; 6304 DMLabel label; 6305 PetscInt field; 6306 6307 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6308 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6309 } 6310 } 6311 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6312 PetscFunctionReturn(PETSC_SUCCESS); 6313 } 6314 6315 /*@ 6316 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6317 6318 Collective 6319 6320 Input Parameter: 6321 . dm - The `DM` 6322 6323 Output Parameter: 6324 . newdm - The `DM` 6325 6326 Level: advanced 6327 6328 Developer Note: 6329 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6330 6331 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()` 6332 @*/ 6333 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6334 { 6335 PetscFunctionBegin; 6336 PetscCall(DMCopyFields(dm, newdm)); 6337 PetscCall(DMCopyDS(dm, newdm)); 6338 PetscFunctionReturn(PETSC_SUCCESS); 6339 } 6340 6341 /*@ 6342 DMGetDimension - Return the topological dimension of the `DM` 6343 6344 Not Collective 6345 6346 Input Parameter: 6347 . dm - The `DM` 6348 6349 Output Parameter: 6350 . dim - The topological dimension 6351 6352 Level: beginner 6353 6354 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()` 6355 @*/ 6356 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6357 { 6358 PetscFunctionBegin; 6359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6360 PetscAssertPointer(dim, 2); 6361 *dim = dm->dim; 6362 PetscFunctionReturn(PETSC_SUCCESS); 6363 } 6364 6365 /*@ 6366 DMSetDimension - Set the topological dimension of the `DM` 6367 6368 Collective 6369 6370 Input Parameters: 6371 + dm - The `DM` 6372 - dim - The topological dimension 6373 6374 Level: beginner 6375 6376 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()` 6377 @*/ 6378 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6379 { 6380 PetscDS ds; 6381 PetscInt Nds, n; 6382 6383 PetscFunctionBegin; 6384 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6385 PetscValidLogicalCollectiveInt(dm, dim, 2); 6386 dm->dim = dim; 6387 if (dm->dim >= 0) { 6388 PetscCall(DMGetNumDS(dm, &Nds)); 6389 for (n = 0; n < Nds; ++n) { 6390 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 6391 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6392 } 6393 } 6394 PetscFunctionReturn(PETSC_SUCCESS); 6395 } 6396 6397 /*@ 6398 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6399 6400 Collective 6401 6402 Input Parameters: 6403 + dm - the `DM` 6404 - dim - the dimension 6405 6406 Output Parameters: 6407 + pStart - The first point of the given dimension 6408 - pEnd - The first point following points of the given dimension 6409 6410 Level: intermediate 6411 6412 Note: 6413 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6414 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6415 then the interval is empty. 6416 6417 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6418 @*/ 6419 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6420 { 6421 PetscInt d; 6422 6423 PetscFunctionBegin; 6424 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6425 PetscCall(DMGetDimension(dm, &d)); 6426 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6427 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6428 PetscFunctionReturn(PETSC_SUCCESS); 6429 } 6430 6431 /*@ 6432 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6433 6434 Collective 6435 6436 Input Parameter: 6437 . dm - The original `DM` 6438 6439 Output Parameter: 6440 . odm - The `DM` which provides the layout for output 6441 6442 Level: intermediate 6443 6444 Note: 6445 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6446 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6447 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6448 6449 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6450 @*/ 6451 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6452 { 6453 PetscSection section; 6454 IS perm; 6455 PetscBool hasConstraints, newDM, gnewDM; 6456 6457 PetscFunctionBegin; 6458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6459 PetscAssertPointer(odm, 2); 6460 PetscCall(DMGetLocalSection(dm, §ion)); 6461 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6462 PetscCall(PetscSectionGetPermutation(section, &perm)); 6463 newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE; 6464 PetscCall(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6465 if (!gnewDM) { 6466 *odm = dm; 6467 PetscFunctionReturn(PETSC_SUCCESS); 6468 } 6469 if (!dm->dmBC) { 6470 PetscSection newSection, gsection; 6471 PetscSF sf; 6472 PetscBool usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE; 6473 6474 PetscCall(DMClone(dm, &dm->dmBC)); 6475 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6476 PetscCall(PetscSectionClone(section, &newSection)); 6477 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6478 PetscCall(PetscSectionDestroy(&newSection)); 6479 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6480 PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection)); 6481 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6482 PetscCall(PetscSectionDestroy(&gsection)); 6483 } 6484 *odm = dm->dmBC; 6485 PetscFunctionReturn(PETSC_SUCCESS); 6486 } 6487 6488 /*@ 6489 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6490 6491 Input Parameter: 6492 . dm - The original `DM` 6493 6494 Output Parameters: 6495 + num - The output sequence number 6496 - val - The output sequence value 6497 6498 Level: intermediate 6499 6500 Note: 6501 This is intended for output that should appear in sequence, for instance 6502 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6503 6504 Developer Note: 6505 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6506 not directly related to the `DM`. 6507 6508 .seealso: [](ch_dmbase), `DM`, `VecView()` 6509 @*/ 6510 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6511 { 6512 PetscFunctionBegin; 6513 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6514 if (num) { 6515 PetscAssertPointer(num, 2); 6516 *num = dm->outputSequenceNum; 6517 } 6518 if (val) { 6519 PetscAssertPointer(val, 3); 6520 *val = dm->outputSequenceVal; 6521 } 6522 PetscFunctionReturn(PETSC_SUCCESS); 6523 } 6524 6525 /*@ 6526 DMSetOutputSequenceNumber - Set the sequence number/value for output 6527 6528 Input Parameters: 6529 + dm - The original `DM` 6530 . num - The output sequence number 6531 - val - The output sequence value 6532 6533 Level: intermediate 6534 6535 Note: 6536 This is intended for output that should appear in sequence, for instance 6537 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6538 6539 .seealso: [](ch_dmbase), `DM`, `VecView()` 6540 @*/ 6541 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6542 { 6543 PetscFunctionBegin; 6544 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6545 dm->outputSequenceNum = num; 6546 dm->outputSequenceVal = val; 6547 PetscFunctionReturn(PETSC_SUCCESS); 6548 } 6549 6550 /*@C 6551 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6552 6553 Input Parameters: 6554 + dm - The original `DM` 6555 . viewer - The viewer to get it from 6556 . name - The sequence name 6557 - num - The output sequence number 6558 6559 Output Parameter: 6560 . val - The output sequence value 6561 6562 Level: intermediate 6563 6564 Note: 6565 This is intended for output that should appear in sequence, for instance 6566 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6567 6568 Developer Note: 6569 It is unclear at the user API level why a `DM` is needed as input 6570 6571 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6572 @*/ 6573 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 6574 { 6575 PetscBool ishdf5; 6576 6577 PetscFunctionBegin; 6578 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6579 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6580 PetscAssertPointer(val, 5); 6581 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6582 if (ishdf5) { 6583 #if defined(PETSC_HAVE_HDF5) 6584 PetscScalar value; 6585 6586 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6587 *val = PetscRealPart(value); 6588 #endif 6589 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6590 PetscFunctionReturn(PETSC_SUCCESS); 6591 } 6592 6593 /*@ 6594 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6595 6596 Not Collective 6597 6598 Input Parameter: 6599 . dm - The `DM` 6600 6601 Output Parameter: 6602 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6603 6604 Level: beginner 6605 6606 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6607 @*/ 6608 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6609 { 6610 PetscFunctionBegin; 6611 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6612 PetscAssertPointer(useNatural, 2); 6613 *useNatural = dm->useNatural; 6614 PetscFunctionReturn(PETSC_SUCCESS); 6615 } 6616 6617 /*@ 6618 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6619 6620 Collective 6621 6622 Input Parameters: 6623 + dm - The `DM` 6624 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6625 6626 Level: beginner 6627 6628 Note: 6629 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6630 6631 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6632 @*/ 6633 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6634 { 6635 PetscFunctionBegin; 6636 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6637 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6638 dm->useNatural = useNatural; 6639 PetscFunctionReturn(PETSC_SUCCESS); 6640 } 6641 6642 /*@C 6643 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6644 6645 Not Collective 6646 6647 Input Parameters: 6648 + dm - The `DM` object 6649 - name - The label name 6650 6651 Level: intermediate 6652 6653 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6654 @*/ 6655 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6656 { 6657 PetscBool flg; 6658 DMLabel label; 6659 6660 PetscFunctionBegin; 6661 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6662 PetscAssertPointer(name, 2); 6663 PetscCall(DMHasLabel(dm, name, &flg)); 6664 if (!flg) { 6665 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6666 PetscCall(DMAddLabel(dm, label)); 6667 PetscCall(DMLabelDestroy(&label)); 6668 } 6669 PetscFunctionReturn(PETSC_SUCCESS); 6670 } 6671 6672 /*@C 6673 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6674 6675 Not Collective 6676 6677 Input Parameters: 6678 + dm - The `DM` object 6679 . l - The index for the label 6680 - name - The label name 6681 6682 Level: intermediate 6683 6684 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6685 @*/ 6686 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6687 { 6688 DMLabelLink orig, prev = NULL; 6689 DMLabel label; 6690 PetscInt Nl, m; 6691 PetscBool flg, match; 6692 const char *lname; 6693 6694 PetscFunctionBegin; 6695 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6696 PetscAssertPointer(name, 3); 6697 PetscCall(DMHasLabel(dm, name, &flg)); 6698 if (!flg) { 6699 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6700 PetscCall(DMAddLabel(dm, label)); 6701 PetscCall(DMLabelDestroy(&label)); 6702 } 6703 PetscCall(DMGetNumLabels(dm, &Nl)); 6704 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6705 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6706 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6707 PetscCall(PetscStrcmp(name, lname, &match)); 6708 if (match) break; 6709 } 6710 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6711 if (!m) dm->labels = orig->next; 6712 else prev->next = orig->next; 6713 if (!l) { 6714 orig->next = dm->labels; 6715 dm->labels = orig; 6716 } else { 6717 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next); 6718 orig->next = prev->next; 6719 prev->next = orig; 6720 } 6721 PetscFunctionReturn(PETSC_SUCCESS); 6722 } 6723 6724 /*@C 6725 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6726 6727 Not Collective 6728 6729 Input Parameters: 6730 + dm - The `DM` object 6731 . name - The label name 6732 - point - The mesh point 6733 6734 Output Parameter: 6735 . value - The label value for this point, or -1 if the point is not in the label 6736 6737 Level: beginner 6738 6739 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6740 @*/ 6741 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6742 { 6743 DMLabel label; 6744 6745 PetscFunctionBegin; 6746 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6747 PetscAssertPointer(name, 2); 6748 PetscCall(DMGetLabel(dm, name, &label)); 6749 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6750 PetscCall(DMLabelGetValue(label, point, value)); 6751 PetscFunctionReturn(PETSC_SUCCESS); 6752 } 6753 6754 /*@C 6755 DMSetLabelValue - Add a point to a `DMLabel` with given value 6756 6757 Not Collective 6758 6759 Input Parameters: 6760 + dm - The `DM` object 6761 . name - The label name 6762 . point - The mesh point 6763 - value - The label value for this point 6764 6765 Output Parameter: 6766 6767 Level: beginner 6768 6769 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6770 @*/ 6771 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6772 { 6773 DMLabel label; 6774 6775 PetscFunctionBegin; 6776 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6777 PetscAssertPointer(name, 2); 6778 PetscCall(DMGetLabel(dm, name, &label)); 6779 if (!label) { 6780 PetscCall(DMCreateLabel(dm, name)); 6781 PetscCall(DMGetLabel(dm, name, &label)); 6782 } 6783 PetscCall(DMLabelSetValue(label, point, value)); 6784 PetscFunctionReturn(PETSC_SUCCESS); 6785 } 6786 6787 /*@C 6788 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6789 6790 Not Collective 6791 6792 Input Parameters: 6793 + dm - The `DM` object 6794 . name - The label name 6795 . point - The mesh point 6796 - value - The label value for this point 6797 6798 Level: beginner 6799 6800 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6801 @*/ 6802 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6803 { 6804 DMLabel label; 6805 6806 PetscFunctionBegin; 6807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6808 PetscAssertPointer(name, 2); 6809 PetscCall(DMGetLabel(dm, name, &label)); 6810 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6811 PetscCall(DMLabelClearValue(label, point, value)); 6812 PetscFunctionReturn(PETSC_SUCCESS); 6813 } 6814 6815 /*@C 6816 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6817 6818 Not Collective 6819 6820 Input Parameters: 6821 + dm - The `DM` object 6822 - name - The label name 6823 6824 Output Parameter: 6825 . size - The number of different integer ids, or 0 if the label does not exist 6826 6827 Level: beginner 6828 6829 Developer Note: 6830 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6831 6832 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6833 @*/ 6834 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6835 { 6836 DMLabel label; 6837 6838 PetscFunctionBegin; 6839 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6840 PetscAssertPointer(name, 2); 6841 PetscAssertPointer(size, 3); 6842 PetscCall(DMGetLabel(dm, name, &label)); 6843 *size = 0; 6844 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6845 PetscCall(DMLabelGetNumValues(label, size)); 6846 PetscFunctionReturn(PETSC_SUCCESS); 6847 } 6848 6849 /*@C 6850 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6851 6852 Not Collective 6853 6854 Input Parameters: 6855 + dm - The `DM` object 6856 - name - The label name 6857 6858 Output Parameter: 6859 . ids - The integer ids, or `NULL` if the label does not exist 6860 6861 Level: beginner 6862 6863 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6864 @*/ 6865 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6866 { 6867 DMLabel label; 6868 6869 PetscFunctionBegin; 6870 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6871 PetscAssertPointer(name, 2); 6872 PetscAssertPointer(ids, 3); 6873 PetscCall(DMGetLabel(dm, name, &label)); 6874 *ids = NULL; 6875 if (label) { 6876 PetscCall(DMLabelGetValueIS(label, ids)); 6877 } else { 6878 /* returning an empty IS */ 6879 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6880 } 6881 PetscFunctionReturn(PETSC_SUCCESS); 6882 } 6883 6884 /*@C 6885 DMGetStratumSize - Get the number of points in a label stratum 6886 6887 Not Collective 6888 6889 Input Parameters: 6890 + dm - The `DM` object 6891 . name - The label name of the stratum 6892 - value - The stratum value 6893 6894 Output Parameter: 6895 . size - The number of points, also called the stratum size 6896 6897 Level: beginner 6898 6899 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 6900 @*/ 6901 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 6902 { 6903 DMLabel label; 6904 6905 PetscFunctionBegin; 6906 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6907 PetscAssertPointer(name, 2); 6908 PetscAssertPointer(size, 4); 6909 PetscCall(DMGetLabel(dm, name, &label)); 6910 *size = 0; 6911 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6912 PetscCall(DMLabelGetStratumSize(label, value, size)); 6913 PetscFunctionReturn(PETSC_SUCCESS); 6914 } 6915 6916 /*@C 6917 DMGetStratumIS - Get the points in a label stratum 6918 6919 Not Collective 6920 6921 Input Parameters: 6922 + dm - The `DM` object 6923 . name - The label name 6924 - value - The stratum value 6925 6926 Output Parameter: 6927 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 6928 6929 Level: beginner 6930 6931 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 6932 @*/ 6933 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 6934 { 6935 DMLabel label; 6936 6937 PetscFunctionBegin; 6938 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6939 PetscAssertPointer(name, 2); 6940 PetscAssertPointer(points, 4); 6941 PetscCall(DMGetLabel(dm, name, &label)); 6942 *points = NULL; 6943 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6944 PetscCall(DMLabelGetStratumIS(label, value, points)); 6945 PetscFunctionReturn(PETSC_SUCCESS); 6946 } 6947 6948 /*@C 6949 DMSetStratumIS - Set the points in a label stratum 6950 6951 Not Collective 6952 6953 Input Parameters: 6954 + dm - The `DM` object 6955 . name - The label name 6956 . value - The stratum value 6957 - points - The stratum points 6958 6959 Level: beginner 6960 6961 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 6962 @*/ 6963 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 6964 { 6965 DMLabel label; 6966 6967 PetscFunctionBegin; 6968 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6969 PetscAssertPointer(name, 2); 6970 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 6971 PetscCall(DMGetLabel(dm, name, &label)); 6972 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6973 PetscCall(DMLabelSetStratumIS(label, value, points)); 6974 PetscFunctionReturn(PETSC_SUCCESS); 6975 } 6976 6977 /*@C 6978 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 6979 6980 Not Collective 6981 6982 Input Parameters: 6983 + dm - The `DM` object 6984 . name - The label name 6985 - value - The label value for this point 6986 6987 Output Parameter: 6988 6989 Level: beginner 6990 6991 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6992 @*/ 6993 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 6994 { 6995 DMLabel label; 6996 6997 PetscFunctionBegin; 6998 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6999 PetscAssertPointer(name, 2); 7000 PetscCall(DMGetLabel(dm, name, &label)); 7001 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 7002 PetscCall(DMLabelClearStratum(label, value)); 7003 PetscFunctionReturn(PETSC_SUCCESS); 7004 } 7005 7006 /*@ 7007 DMGetNumLabels - Return the number of labels defined by on the `DM` 7008 7009 Not Collective 7010 7011 Input Parameter: 7012 . dm - The `DM` object 7013 7014 Output Parameter: 7015 . numLabels - the number of Labels 7016 7017 Level: intermediate 7018 7019 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7020 @*/ 7021 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 7022 { 7023 DMLabelLink next = dm->labels; 7024 PetscInt n = 0; 7025 7026 PetscFunctionBegin; 7027 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7028 PetscAssertPointer(numLabels, 2); 7029 while (next) { 7030 ++n; 7031 next = next->next; 7032 } 7033 *numLabels = n; 7034 PetscFunctionReturn(PETSC_SUCCESS); 7035 } 7036 7037 /*@C 7038 DMGetLabelName - Return the name of nth label 7039 7040 Not Collective 7041 7042 Input Parameters: 7043 + dm - The `DM` object 7044 - n - the label number 7045 7046 Output Parameter: 7047 . name - the label name 7048 7049 Level: intermediate 7050 7051 Developer Note: 7052 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 7053 7054 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7055 @*/ 7056 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 7057 { 7058 DMLabelLink next = dm->labels; 7059 PetscInt l = 0; 7060 7061 PetscFunctionBegin; 7062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7063 PetscAssertPointer(name, 3); 7064 while (next) { 7065 if (l == n) { 7066 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 7067 PetscFunctionReturn(PETSC_SUCCESS); 7068 } 7069 ++l; 7070 next = next->next; 7071 } 7072 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7073 } 7074 7075 /*@C 7076 DMHasLabel - Determine whether the `DM` has a label of a given name 7077 7078 Not Collective 7079 7080 Input Parameters: 7081 + dm - The `DM` object 7082 - name - The label name 7083 7084 Output Parameter: 7085 . hasLabel - `PETSC_TRUE` if the label is present 7086 7087 Level: intermediate 7088 7089 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7090 @*/ 7091 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7092 { 7093 DMLabelLink next = dm->labels; 7094 const char *lname; 7095 7096 PetscFunctionBegin; 7097 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7098 PetscAssertPointer(name, 2); 7099 PetscAssertPointer(hasLabel, 3); 7100 *hasLabel = PETSC_FALSE; 7101 while (next) { 7102 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7103 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7104 if (*hasLabel) break; 7105 next = next->next; 7106 } 7107 PetscFunctionReturn(PETSC_SUCCESS); 7108 } 7109 7110 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7111 /*@C 7112 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7113 7114 Not Collective 7115 7116 Input Parameters: 7117 + dm - The `DM` object 7118 - name - The label name 7119 7120 Output Parameter: 7121 . label - The `DMLabel`, or `NULL` if the label is absent 7122 7123 Default labels in a `DMPLEX`: 7124 + "depth" - Holds the depth (co-dimension) of each mesh point 7125 . "celltype" - Holds the topological type of each cell 7126 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7127 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7128 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7129 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7130 7131 Level: intermediate 7132 7133 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7134 @*/ 7135 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7136 { 7137 DMLabelLink next = dm->labels; 7138 PetscBool hasLabel; 7139 const char *lname; 7140 7141 PetscFunctionBegin; 7142 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7143 PetscAssertPointer(name, 2); 7144 PetscAssertPointer(label, 3); 7145 *label = NULL; 7146 while (next) { 7147 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7148 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7149 if (hasLabel) { 7150 *label = next->label; 7151 break; 7152 } 7153 next = next->next; 7154 } 7155 PetscFunctionReturn(PETSC_SUCCESS); 7156 } 7157 7158 /*@C 7159 DMGetLabelByNum - Return the nth label on a `DM` 7160 7161 Not Collective 7162 7163 Input Parameters: 7164 + dm - The `DM` object 7165 - n - the label number 7166 7167 Output Parameter: 7168 . label - the label 7169 7170 Level: intermediate 7171 7172 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7173 @*/ 7174 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7175 { 7176 DMLabelLink next = dm->labels; 7177 PetscInt l = 0; 7178 7179 PetscFunctionBegin; 7180 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7181 PetscAssertPointer(label, 3); 7182 while (next) { 7183 if (l == n) { 7184 *label = next->label; 7185 PetscFunctionReturn(PETSC_SUCCESS); 7186 } 7187 ++l; 7188 next = next->next; 7189 } 7190 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7191 } 7192 7193 /*@C 7194 DMAddLabel - Add the label to this `DM` 7195 7196 Not Collective 7197 7198 Input Parameters: 7199 + dm - The `DM` object 7200 - label - The `DMLabel` 7201 7202 Level: developer 7203 7204 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7205 @*/ 7206 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7207 { 7208 DMLabelLink l, *p, tmpLabel; 7209 PetscBool hasLabel; 7210 const char *lname; 7211 PetscBool flg; 7212 7213 PetscFunctionBegin; 7214 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7215 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7216 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7217 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7218 PetscCall(PetscCalloc1(1, &tmpLabel)); 7219 tmpLabel->label = label; 7220 tmpLabel->output = PETSC_TRUE; 7221 for (p = &dm->labels; (l = *p); p = &l->next) { } 7222 *p = tmpLabel; 7223 PetscCall(PetscObjectReference((PetscObject)label)); 7224 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7225 if (flg) dm->depthLabel = label; 7226 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7227 if (flg) dm->celltypeLabel = label; 7228 PetscFunctionReturn(PETSC_SUCCESS); 7229 } 7230 7231 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7232 /*@C 7233 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7234 7235 Not Collective 7236 7237 Input Parameters: 7238 + dm - The `DM` object 7239 - label - The `DMLabel`, having the same name, to substitute 7240 7241 Default labels in a `DMPLEX`: 7242 + "depth" - Holds the depth (co-dimension) of each mesh point 7243 . "celltype" - Holds the topological type of each cell 7244 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7245 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7246 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7247 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7248 7249 Level: intermediate 7250 7251 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7252 @*/ 7253 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7254 { 7255 DMLabelLink next = dm->labels; 7256 PetscBool hasLabel, flg; 7257 const char *name, *lname; 7258 7259 PetscFunctionBegin; 7260 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7261 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7262 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7263 while (next) { 7264 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7265 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7266 if (hasLabel) { 7267 PetscCall(PetscObjectReference((PetscObject)label)); 7268 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7269 if (flg) dm->depthLabel = label; 7270 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7271 if (flg) dm->celltypeLabel = label; 7272 PetscCall(DMLabelDestroy(&next->label)); 7273 next->label = label; 7274 break; 7275 } 7276 next = next->next; 7277 } 7278 PetscFunctionReturn(PETSC_SUCCESS); 7279 } 7280 7281 /*@C 7282 DMRemoveLabel - Remove the label given by name from this `DM` 7283 7284 Not Collective 7285 7286 Input Parameters: 7287 + dm - The `DM` object 7288 - name - The label name 7289 7290 Output Parameter: 7291 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7292 caller is responsible for calling `DMLabelDestroy()`. 7293 7294 Level: developer 7295 7296 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7297 @*/ 7298 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7299 { 7300 DMLabelLink link, *pnext; 7301 PetscBool hasLabel; 7302 const char *lname; 7303 7304 PetscFunctionBegin; 7305 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7306 PetscAssertPointer(name, 2); 7307 if (label) { 7308 PetscAssertPointer(label, 3); 7309 *label = NULL; 7310 } 7311 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7312 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7313 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7314 if (hasLabel) { 7315 *pnext = link->next; /* Remove from list */ 7316 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7317 if (hasLabel) dm->depthLabel = NULL; 7318 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7319 if (hasLabel) dm->celltypeLabel = NULL; 7320 if (label) *label = link->label; 7321 else PetscCall(DMLabelDestroy(&link->label)); 7322 PetscCall(PetscFree(link)); 7323 break; 7324 } 7325 } 7326 PetscFunctionReturn(PETSC_SUCCESS); 7327 } 7328 7329 /*@ 7330 DMRemoveLabelBySelf - Remove the label from this `DM` 7331 7332 Not Collective 7333 7334 Input Parameters: 7335 + dm - The `DM` object 7336 . label - The `DMLabel` to be removed from the `DM` 7337 - failNotFound - Should it fail if the label is not found in the `DM`? 7338 7339 Level: developer 7340 7341 Note: 7342 Only exactly the same instance is removed if found, name match is ignored. 7343 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7344 *label nullified. 7345 7346 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7347 @*/ 7348 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7349 { 7350 DMLabelLink link, *pnext; 7351 PetscBool hasLabel = PETSC_FALSE; 7352 7353 PetscFunctionBegin; 7354 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7355 PetscAssertPointer(label, 2); 7356 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7357 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7358 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7359 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7360 if (*label == link->label) { 7361 hasLabel = PETSC_TRUE; 7362 *pnext = link->next; /* Remove from list */ 7363 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7364 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7365 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7366 PetscCall(DMLabelDestroy(&link->label)); 7367 PetscCall(PetscFree(link)); 7368 break; 7369 } 7370 } 7371 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7372 PetscFunctionReturn(PETSC_SUCCESS); 7373 } 7374 7375 /*@C 7376 DMGetLabelOutput - Get the output flag for a given label 7377 7378 Not Collective 7379 7380 Input Parameters: 7381 + dm - The `DM` object 7382 - name - The label name 7383 7384 Output Parameter: 7385 . output - The flag for output 7386 7387 Level: developer 7388 7389 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7390 @*/ 7391 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7392 { 7393 DMLabelLink next = dm->labels; 7394 const char *lname; 7395 7396 PetscFunctionBegin; 7397 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7398 PetscAssertPointer(name, 2); 7399 PetscAssertPointer(output, 3); 7400 while (next) { 7401 PetscBool flg; 7402 7403 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7404 PetscCall(PetscStrcmp(name, lname, &flg)); 7405 if (flg) { 7406 *output = next->output; 7407 PetscFunctionReturn(PETSC_SUCCESS); 7408 } 7409 next = next->next; 7410 } 7411 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7412 } 7413 7414 /*@C 7415 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7416 7417 Not Collective 7418 7419 Input Parameters: 7420 + dm - The `DM` object 7421 . name - The label name 7422 - output - `PETSC_TRUE` to save the label to the viewer 7423 7424 Level: developer 7425 7426 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7427 @*/ 7428 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7429 { 7430 DMLabelLink next = dm->labels; 7431 const char *lname; 7432 7433 PetscFunctionBegin; 7434 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7435 PetscAssertPointer(name, 2); 7436 while (next) { 7437 PetscBool flg; 7438 7439 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7440 PetscCall(PetscStrcmp(name, lname, &flg)); 7441 if (flg) { 7442 next->output = output; 7443 PetscFunctionReturn(PETSC_SUCCESS); 7444 } 7445 next = next->next; 7446 } 7447 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7448 } 7449 7450 /*@ 7451 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7452 7453 Collective 7454 7455 Input Parameters: 7456 + dmA - The `DM` object with initial labels 7457 . dmB - The `DM` object to which labels are copied 7458 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7459 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7460 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7461 7462 Level: intermediate 7463 7464 Note: 7465 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7466 7467 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7468 @*/ 7469 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7470 { 7471 DMLabel label, labelNew, labelOld; 7472 const char *name; 7473 PetscBool flg; 7474 DMLabelLink link; 7475 7476 PetscFunctionBegin; 7477 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7478 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7479 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7480 PetscValidLogicalCollectiveBool(dmA, all, 4); 7481 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7482 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7483 for (link = dmA->labels; link; link = link->next) { 7484 label = link->label; 7485 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7486 if (!all) { 7487 PetscCall(PetscStrcmp(name, "depth", &flg)); 7488 if (flg) continue; 7489 PetscCall(PetscStrcmp(name, "dim", &flg)); 7490 if (flg) continue; 7491 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7492 if (flg) continue; 7493 } 7494 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7495 if (labelOld) { 7496 switch (emode) { 7497 case DM_COPY_LABELS_KEEP: 7498 continue; 7499 case DM_COPY_LABELS_REPLACE: 7500 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7501 break; 7502 case DM_COPY_LABELS_FAIL: 7503 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7504 default: 7505 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7506 } 7507 } 7508 if (mode == PETSC_COPY_VALUES) { 7509 PetscCall(DMLabelDuplicate(label, &labelNew)); 7510 } else { 7511 labelNew = label; 7512 } 7513 PetscCall(DMAddLabel(dmB, labelNew)); 7514 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7515 } 7516 PetscFunctionReturn(PETSC_SUCCESS); 7517 } 7518 7519 /*@C 7520 DMCompareLabels - Compare labels between two `DM` objects 7521 7522 Collective; No Fortran Support 7523 7524 Input Parameters: 7525 + dm0 - First `DM` object 7526 - dm1 - Second `DM` object 7527 7528 Output Parameters: 7529 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 7530 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7531 7532 Level: intermediate 7533 7534 Notes: 7535 The output flag equal will be the same on all processes. 7536 7537 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7538 7539 Make sure to pass equal is `NULL` on all processes or none of them. 7540 7541 The output message is set independently on each rank. 7542 7543 message must be freed with `PetscFree()` 7544 7545 If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner. 7546 7547 Make sure to pass message as `NULL` on all processes or no processes. 7548 7549 Labels are matched by name. If the number of labels and their names are equal, 7550 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7551 7552 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7553 @*/ 7554 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7555 { 7556 PetscInt n, i; 7557 char msg[PETSC_MAX_PATH_LEN] = ""; 7558 PetscBool eq; 7559 MPI_Comm comm; 7560 PetscMPIInt rank; 7561 7562 PetscFunctionBegin; 7563 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7564 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7565 PetscCheckSameComm(dm0, 1, dm1, 2); 7566 if (equal) PetscAssertPointer(equal, 3); 7567 if (message) PetscAssertPointer(message, 4); 7568 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7569 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7570 { 7571 PetscInt n1; 7572 7573 PetscCall(DMGetNumLabels(dm0, &n)); 7574 PetscCall(DMGetNumLabels(dm1, &n1)); 7575 eq = (PetscBool)(n == n1); 7576 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7577 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7578 if (!eq) goto finish; 7579 } 7580 for (i = 0; i < n; i++) { 7581 DMLabel l0, l1; 7582 const char *name; 7583 char *msgInner; 7584 7585 /* Ignore label order */ 7586 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7587 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7588 PetscCall(DMGetLabel(dm1, name, &l1)); 7589 if (!l1) { 7590 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7591 eq = PETSC_FALSE; 7592 break; 7593 } 7594 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7595 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7596 PetscCall(PetscFree(msgInner)); 7597 if (!eq) break; 7598 } 7599 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7600 finish: 7601 /* If message output arg not set, print to stderr */ 7602 if (message) { 7603 *message = NULL; 7604 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7605 } else { 7606 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7607 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7608 } 7609 /* If same output arg not ser and labels are not equal, throw error */ 7610 if (equal) *equal = eq; 7611 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7612 PetscFunctionReturn(PETSC_SUCCESS); 7613 } 7614 7615 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7616 { 7617 PetscFunctionBegin; 7618 PetscAssertPointer(label, 2); 7619 if (!*label) { 7620 PetscCall(DMCreateLabel(dm, name)); 7621 PetscCall(DMGetLabel(dm, name, label)); 7622 } 7623 PetscCall(DMLabelSetValue(*label, point, value)); 7624 PetscFunctionReturn(PETSC_SUCCESS); 7625 } 7626 7627 /* 7628 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7629 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7630 (label, id) pair in the DM. 7631 7632 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7633 each label. 7634 */ 7635 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7636 { 7637 DMUniversalLabel ul; 7638 PetscBool *active; 7639 PetscInt pStart, pEnd, p, Nl, l, m; 7640 7641 PetscFunctionBegin; 7642 PetscCall(PetscMalloc1(1, &ul)); 7643 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7644 PetscCall(DMGetNumLabels(dm, &Nl)); 7645 PetscCall(PetscCalloc1(Nl, &active)); 7646 ul->Nl = 0; 7647 for (l = 0; l < Nl; ++l) { 7648 PetscBool isdepth, iscelltype; 7649 const char *name; 7650 7651 PetscCall(DMGetLabelName(dm, l, &name)); 7652 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7653 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7654 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7655 if (active[l]) ++ul->Nl; 7656 } 7657 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7658 ul->Nv = 0; 7659 for (l = 0, m = 0; l < Nl; ++l) { 7660 DMLabel label; 7661 PetscInt nv; 7662 const char *name; 7663 7664 if (!active[l]) continue; 7665 PetscCall(DMGetLabelName(dm, l, &name)); 7666 PetscCall(DMGetLabelByNum(dm, l, &label)); 7667 PetscCall(DMLabelGetNumValues(label, &nv)); 7668 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7669 ul->indices[m] = l; 7670 ul->Nv += nv; 7671 ul->offsets[m + 1] = nv; 7672 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7673 ++m; 7674 } 7675 for (l = 1; l <= ul->Nl; ++l) { 7676 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7677 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7678 } 7679 for (l = 0; l < ul->Nl; ++l) { 7680 PetscInt b; 7681 7682 ul->masks[l] = 0; 7683 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7684 } 7685 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7686 for (l = 0, m = 0; l < Nl; ++l) { 7687 DMLabel label; 7688 IS valueIS; 7689 const PetscInt *varr; 7690 PetscInt nv, v; 7691 7692 if (!active[l]) continue; 7693 PetscCall(DMGetLabelByNum(dm, l, &label)); 7694 PetscCall(DMLabelGetNumValues(label, &nv)); 7695 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7696 PetscCall(ISGetIndices(valueIS, &varr)); 7697 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7698 PetscCall(ISRestoreIndices(valueIS, &varr)); 7699 PetscCall(ISDestroy(&valueIS)); 7700 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7701 ++m; 7702 } 7703 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7704 for (p = pStart; p < pEnd; ++p) { 7705 PetscInt uval = 0; 7706 PetscBool marked = PETSC_FALSE; 7707 7708 for (l = 0, m = 0; l < Nl; ++l) { 7709 DMLabel label; 7710 PetscInt val, defval, loc, nv; 7711 7712 if (!active[l]) continue; 7713 PetscCall(DMGetLabelByNum(dm, l, &label)); 7714 PetscCall(DMLabelGetValue(label, p, &val)); 7715 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7716 if (val == defval) { 7717 ++m; 7718 continue; 7719 } 7720 nv = ul->offsets[m + 1] - ul->offsets[m]; 7721 marked = PETSC_TRUE; 7722 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7723 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7724 uval += (loc + 1) << ul->bits[m]; 7725 ++m; 7726 } 7727 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7728 } 7729 PetscCall(PetscFree(active)); 7730 *universal = ul; 7731 PetscFunctionReturn(PETSC_SUCCESS); 7732 } 7733 7734 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7735 { 7736 PetscInt l; 7737 7738 PetscFunctionBegin; 7739 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7740 PetscCall(DMLabelDestroy(&(*universal)->label)); 7741 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7742 PetscCall(PetscFree((*universal)->values)); 7743 PetscCall(PetscFree(*universal)); 7744 *universal = NULL; 7745 PetscFunctionReturn(PETSC_SUCCESS); 7746 } 7747 7748 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7749 { 7750 PetscFunctionBegin; 7751 PetscAssertPointer(ulabel, 2); 7752 *ulabel = ul->label; 7753 PetscFunctionReturn(PETSC_SUCCESS); 7754 } 7755 7756 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7757 { 7758 PetscInt Nl = ul->Nl, l; 7759 7760 PetscFunctionBegin; 7761 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7762 for (l = 0; l < Nl; ++l) { 7763 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7764 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7765 } 7766 if (preserveOrder) { 7767 for (l = 0; l < ul->Nl; ++l) { 7768 const char *name; 7769 PetscBool match; 7770 7771 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7772 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7773 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]); 7774 } 7775 } 7776 PetscFunctionReturn(PETSC_SUCCESS); 7777 } 7778 7779 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7780 { 7781 PetscInt l; 7782 7783 PetscFunctionBegin; 7784 for (l = 0; l < ul->Nl; ++l) { 7785 DMLabel label; 7786 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7787 7788 if (lval) { 7789 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7790 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7791 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7792 } 7793 } 7794 PetscFunctionReturn(PETSC_SUCCESS); 7795 } 7796 7797 /*@ 7798 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7799 7800 Not Collective 7801 7802 Input Parameter: 7803 . dm - The `DM` object 7804 7805 Output Parameter: 7806 . cdm - The coarse `DM` 7807 7808 Level: intermediate 7809 7810 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7811 @*/ 7812 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7813 { 7814 PetscFunctionBegin; 7815 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7816 PetscAssertPointer(cdm, 2); 7817 *cdm = dm->coarseMesh; 7818 PetscFunctionReturn(PETSC_SUCCESS); 7819 } 7820 7821 /*@ 7822 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7823 7824 Input Parameters: 7825 + dm - The `DM` object 7826 - cdm - The coarse `DM` 7827 7828 Level: intermediate 7829 7830 Note: 7831 Normally this is set automatically by `DMRefine()` 7832 7833 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7834 @*/ 7835 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7836 { 7837 PetscFunctionBegin; 7838 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7839 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7840 if (dm == cdm) cdm = NULL; 7841 PetscCall(PetscObjectReference((PetscObject)cdm)); 7842 PetscCall(DMDestroy(&dm->coarseMesh)); 7843 dm->coarseMesh = cdm; 7844 PetscFunctionReturn(PETSC_SUCCESS); 7845 } 7846 7847 /*@ 7848 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7849 7850 Input Parameter: 7851 . dm - The `DM` object 7852 7853 Output Parameter: 7854 . fdm - The fine `DM` 7855 7856 Level: intermediate 7857 7858 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7859 @*/ 7860 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7861 { 7862 PetscFunctionBegin; 7863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7864 PetscAssertPointer(fdm, 2); 7865 *fdm = dm->fineMesh; 7866 PetscFunctionReturn(PETSC_SUCCESS); 7867 } 7868 7869 /*@ 7870 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7871 7872 Input Parameters: 7873 + dm - The `DM` object 7874 - fdm - The fine `DM` 7875 7876 Level: developer 7877 7878 Note: 7879 Normally this is set automatically by `DMCoarsen()` 7880 7881 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7882 @*/ 7883 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7884 { 7885 PetscFunctionBegin; 7886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7887 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7888 if (dm == fdm) fdm = NULL; 7889 PetscCall(PetscObjectReference((PetscObject)fdm)); 7890 PetscCall(DMDestroy(&dm->fineMesh)); 7891 dm->fineMesh = fdm; 7892 PetscFunctionReturn(PETSC_SUCCESS); 7893 } 7894 7895 /*@C 7896 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7897 7898 Collective 7899 7900 Input Parameters: 7901 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7902 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7903 . name - The BC name 7904 . label - The label defining constrained points 7905 . Nv - The number of `DMLabel` values for constrained points 7906 . values - An array of values for constrained points 7907 . field - The field to constrain 7908 . Nc - The number of constrained field components (0 will constrain all fields) 7909 . comps - An array of constrained component numbers 7910 . bcFunc - A pointwise function giving boundary values 7911 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7912 - ctx - An optional user context for bcFunc 7913 7914 Output Parameter: 7915 . bd - (Optional) Boundary number 7916 7917 Options Database Keys: 7918 + -bc_<boundary name> <num> - Overrides the boundary ids 7919 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7920 7921 Level: intermediate 7922 7923 Notes: 7924 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 7925 .vb 7926 void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7927 .ve 7928 7929 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 7930 7931 .vb 7932 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7933 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7934 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7935 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7936 .ve 7937 + dim - the spatial dimension 7938 . Nf - the number of fields 7939 . uOff - the offset into u[] and u_t[] for each field 7940 . uOff_x - the offset into u_x[] for each field 7941 . u - each field evaluated at the current point 7942 . u_t - the time derivative of each field evaluated at the current point 7943 . u_x - the gradient of each field evaluated at the current point 7944 . aOff - the offset into a[] and a_t[] for each auxiliary field 7945 . aOff_x - the offset into a_x[] for each auxiliary field 7946 . a - each auxiliary field evaluated at the current point 7947 . a_t - the time derivative of each auxiliary field evaluated at the current point 7948 . a_x - the gradient of auxiliary each field evaluated at the current point 7949 . t - current time 7950 . x - coordinates of the current point 7951 . numConstants - number of constant parameters 7952 . constants - constant parameters 7953 - bcval - output values at the current point 7954 7955 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 7956 @*/ 7957 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) 7958 { 7959 PetscDS ds; 7960 7961 PetscFunctionBegin; 7962 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7963 PetscValidLogicalCollectiveEnum(dm, type, 2); 7964 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 7965 PetscValidLogicalCollectiveInt(dm, Nv, 5); 7966 PetscValidLogicalCollectiveInt(dm, field, 7); 7967 PetscValidLogicalCollectiveInt(dm, Nc, 8); 7968 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 7969 PetscCall(DMGetDS(dm, &ds)); 7970 /* Complete label */ 7971 if (label) { 7972 PetscObject obj; 7973 PetscClassId id; 7974 7975 PetscCall(DMGetField(dm, field, NULL, &obj)); 7976 PetscCall(PetscObjectGetClassId(obj, &id)); 7977 if (id == PETSCFE_CLASSID) { 7978 DM plex; 7979 7980 PetscCall(DMConvert(dm, DMPLEX, &plex)); 7981 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 7982 PetscCall(DMDestroy(&plex)); 7983 } 7984 } 7985 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 7986 PetscFunctionReturn(PETSC_SUCCESS); 7987 } 7988 7989 /* TODO Remove this since now the structures are the same */ 7990 static PetscErrorCode DMPopulateBoundary(DM dm) 7991 { 7992 PetscDS ds; 7993 DMBoundary *lastnext; 7994 DSBoundary dsbound; 7995 7996 PetscFunctionBegin; 7997 PetscCall(DMGetDS(dm, &ds)); 7998 dsbound = ds->boundary; 7999 if (dm->boundary) { 8000 DMBoundary next = dm->boundary; 8001 8002 /* quick check to see if the PetscDS has changed */ 8003 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 8004 /* the PetscDS has changed: tear down and rebuild */ 8005 while (next) { 8006 DMBoundary b = next; 8007 8008 next = b->next; 8009 PetscCall(PetscFree(b)); 8010 } 8011 dm->boundary = NULL; 8012 } 8013 8014 lastnext = &dm->boundary; 8015 while (dsbound) { 8016 DMBoundary dmbound; 8017 8018 PetscCall(PetscNew(&dmbound)); 8019 dmbound->dsboundary = dsbound; 8020 dmbound->label = dsbound->label; 8021 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 8022 *lastnext = dmbound; 8023 lastnext = &dmbound->next; 8024 dsbound = dsbound->next; 8025 } 8026 PetscFunctionReturn(PETSC_SUCCESS); 8027 } 8028 8029 /* TODO: missing manual page */ 8030 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8031 { 8032 DMBoundary b; 8033 8034 PetscFunctionBegin; 8035 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8036 PetscAssertPointer(isBd, 3); 8037 *isBd = PETSC_FALSE; 8038 PetscCall(DMPopulateBoundary(dm)); 8039 b = dm->boundary; 8040 while (b && !(*isBd)) { 8041 DMLabel label = b->label; 8042 DSBoundary dsb = b->dsboundary; 8043 PetscInt i; 8044 8045 if (label) { 8046 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8047 } 8048 b = b->next; 8049 } 8050 PetscFunctionReturn(PETSC_SUCCESS); 8051 } 8052 8053 /*@C 8054 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8055 8056 Collective 8057 8058 Input Parameters: 8059 + dm - The `DM` 8060 . time - The time 8061 . funcs - The coordinate functions to evaluate, one per field 8062 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8063 - mode - The insertion mode for values 8064 8065 Output Parameter: 8066 . X - vector 8067 8068 Calling sequence of `funcs`: 8069 + dim - The spatial dimension 8070 . time - The time at which to sample 8071 . x - The coordinates 8072 . Nc - The number of components 8073 . u - The output field values 8074 - ctx - optional user-defined function context 8075 8076 Level: developer 8077 8078 Developer Notes: 8079 This API is specific to only particular usage of `DM` 8080 8081 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8082 8083 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8084 @*/ 8085 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) 8086 { 8087 Vec localX; 8088 8089 PetscFunctionBegin; 8090 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8091 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8092 PetscCall(DMGetLocalVector(dm, &localX)); 8093 PetscCall(VecSet(localX, 0.)); 8094 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8095 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8096 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8097 PetscCall(DMRestoreLocalVector(dm, &localX)); 8098 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8099 PetscFunctionReturn(PETSC_SUCCESS); 8100 } 8101 8102 /*@C 8103 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8104 8105 Not Collective 8106 8107 Input Parameters: 8108 + dm - The `DM` 8109 . time - The time 8110 . funcs - The coordinate functions to evaluate, one per field 8111 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8112 - mode - The insertion mode for values 8113 8114 Output Parameter: 8115 . localX - vector 8116 8117 Calling sequence of `funcs`: 8118 + dim - The spatial dimension 8119 . time - The current timestep 8120 . x - The coordinates 8121 . Nc - The number of components 8122 . u - The output field values 8123 - ctx - optional user-defined function context 8124 8125 Level: developer 8126 8127 Developer Notes: 8128 This API is specific to only particular usage of `DM` 8129 8130 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8131 8132 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8133 @*/ 8134 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) 8135 { 8136 PetscFunctionBegin; 8137 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8138 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8139 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8140 PetscFunctionReturn(PETSC_SUCCESS); 8141 } 8142 8143 /*@C 8144 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. 8145 8146 Collective 8147 8148 Input Parameters: 8149 + dm - The `DM` 8150 . time - The time 8151 . numIds - The number of ids 8152 . ids - The ids 8153 . Nc - The number of components 8154 . comps - The components 8155 . label - The `DMLabel` selecting the portion of the mesh for projection 8156 . funcs - The coordinate functions to evaluate, one per field 8157 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8158 - mode - The insertion mode for values 8159 8160 Output Parameter: 8161 . X - vector 8162 8163 Calling sequence of `funcs`: 8164 + dim - The spatial dimension 8165 . time - The current timestep 8166 . x - The coordinates 8167 . Nc - The number of components 8168 . u - The output field values 8169 - ctx - optional user-defined function context 8170 8171 Level: developer 8172 8173 Developer Notes: 8174 This API is specific to only particular usage of `DM` 8175 8176 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8177 8178 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8179 @*/ 8180 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) 8181 { 8182 Vec localX; 8183 8184 PetscFunctionBegin; 8185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8186 PetscCall(DMGetLocalVector(dm, &localX)); 8187 PetscCall(VecSet(localX, 0.)); 8188 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8189 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8190 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8191 PetscCall(DMRestoreLocalVector(dm, &localX)); 8192 PetscFunctionReturn(PETSC_SUCCESS); 8193 } 8194 8195 /*@C 8196 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. 8197 8198 Not Collective 8199 8200 Input Parameters: 8201 + dm - The `DM` 8202 . time - The time 8203 . label - The `DMLabel` selecting the portion of the mesh for projection 8204 . numIds - The number of ids 8205 . ids - The ids 8206 . Nc - The number of components 8207 . comps - The components 8208 . funcs - The coordinate functions to evaluate, one per field 8209 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8210 - mode - The insertion mode for values 8211 8212 Output Parameter: 8213 . localX - vector 8214 8215 Calling sequence of `funcs`: 8216 + dim - The spatial dimension 8217 . time - The current time 8218 . x - The coordinates 8219 . Nc - The number of components 8220 . u - The output field values 8221 - ctx - optional user-defined function context 8222 8223 Level: developer 8224 8225 Developer Notes: 8226 This API is specific to only particular usage of `DM` 8227 8228 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8229 8230 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8231 @*/ 8232 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) 8233 { 8234 PetscFunctionBegin; 8235 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8236 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8237 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8238 PetscFunctionReturn(PETSC_SUCCESS); 8239 } 8240 8241 /*@C 8242 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. 8243 8244 Not Collective 8245 8246 Input Parameters: 8247 + dm - The `DM` 8248 . time - The time 8249 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8250 . funcs - The functions to evaluate, one per field 8251 - mode - The insertion mode for values 8252 8253 Output Parameter: 8254 . localX - The output vector 8255 8256 Calling sequence of `funcs`: 8257 + dim - The spatial dimension 8258 . Nf - The number of input fields 8259 . NfAux - The number of input auxiliary fields 8260 . uOff - The offset of each field in u[] 8261 . uOff_x - The offset of each field in u_x[] 8262 . u - The field values at this point in space 8263 . u_t - The field time derivative at this point in space (or NULL) 8264 . u_x - The field derivatives at this point in space 8265 . aOff - The offset of each auxiliary field in u[] 8266 . aOff_x - The offset of each auxiliary field in u_x[] 8267 . a - The auxiliary field values at this point in space 8268 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8269 . a_x - The auxiliary field derivatives at this point in space 8270 . t - The current time 8271 . x - The coordinates of this point 8272 . numConstants - The number of constants 8273 . constants - The value of each constant 8274 - f - The value of the function at this point in space 8275 8276 Level: intermediate 8277 8278 Note: 8279 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. 8280 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 8281 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8282 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8283 8284 Developer Notes: 8285 This API is specific to only particular usage of `DM` 8286 8287 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8288 8289 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8290 `DMProjectFunction()`, `DMComputeL2Diff()` 8291 @*/ 8292 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) 8293 { 8294 PetscFunctionBegin; 8295 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8296 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8297 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8298 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8299 PetscFunctionReturn(PETSC_SUCCESS); 8300 } 8301 8302 /*@C 8303 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. 8304 8305 Not Collective 8306 8307 Input Parameters: 8308 + dm - The `DM` 8309 . time - The time 8310 . label - The `DMLabel` marking the portion of the domain to output 8311 . numIds - The number of label ids to use 8312 . ids - The label ids to use for marking 8313 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8314 . comps - The components to set in the output, or `NULL` for all components 8315 . localU - The input field vector 8316 . funcs - The functions to evaluate, one per field 8317 - mode - The insertion mode for values 8318 8319 Output Parameter: 8320 . localX - The output vector 8321 8322 Calling sequence of `funcs`: 8323 + dim - The spatial dimension 8324 . Nf - The number of input fields 8325 . NfAux - The number of input auxiliary fields 8326 . uOff - The offset of each field in u[] 8327 . uOff_x - The offset of each field in u_x[] 8328 . u - The field values at this point in space 8329 . u_t - The field time derivative at this point in space (or NULL) 8330 . u_x - The field derivatives at this point in space 8331 . aOff - The offset of each auxiliary field in u[] 8332 . aOff_x - The offset of each auxiliary field in u_x[] 8333 . a - The auxiliary field values at this point in space 8334 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8335 . a_x - The auxiliary field derivatives at this point in space 8336 . t - The current time 8337 . x - The coordinates of this point 8338 . numConstants - The number of constants 8339 . constants - The value of each constant 8340 - f - The value of the function at this point in space 8341 8342 Level: intermediate 8343 8344 Note: 8345 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. 8346 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 8347 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8348 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8349 8350 Developer Notes: 8351 This API is specific to only particular usage of `DM` 8352 8353 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8354 8355 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8356 @*/ 8357 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) 8358 { 8359 PetscFunctionBegin; 8360 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8361 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8362 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8363 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8364 PetscFunctionReturn(PETSC_SUCCESS); 8365 } 8366 8367 /*@C 8368 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. 8369 8370 Not Collective 8371 8372 Input Parameters: 8373 + dm - The `DM` 8374 . time - The time 8375 . label - The `DMLabel` marking the portion of the domain to output 8376 . numIds - The number of label ids to use 8377 . ids - The label ids to use for marking 8378 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8379 . comps - The components to set in the output, or `NULL` for all components 8380 . U - The input field vector 8381 . funcs - The functions to evaluate, one per field 8382 - mode - The insertion mode for values 8383 8384 Output Parameter: 8385 . X - The output vector 8386 8387 Calling sequence of `funcs`: 8388 + dim - The spatial dimension 8389 . Nf - The number of input fields 8390 . NfAux - The number of input auxiliary fields 8391 . uOff - The offset of each field in u[] 8392 . uOff_x - The offset of each field in u_x[] 8393 . u - The field values at this point in space 8394 . u_t - The field time derivative at this point in space (or NULL) 8395 . u_x - The field derivatives at this point in space 8396 . aOff - The offset of each auxiliary field in u[] 8397 . aOff_x - The offset of each auxiliary field in u_x[] 8398 . a - The auxiliary field values at this point in space 8399 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8400 . a_x - The auxiliary field derivatives at this point in space 8401 . t - The current time 8402 . x - The coordinates of this point 8403 . numConstants - The number of constants 8404 . constants - The value of each constant 8405 - f - The value of the function at this point in space 8406 8407 Level: intermediate 8408 8409 Note: 8410 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. 8411 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 8412 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8413 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8414 8415 Developer Notes: 8416 This API is specific to only particular usage of `DM` 8417 8418 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8419 8420 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8421 @*/ 8422 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) 8423 { 8424 DM dmIn; 8425 Vec localU, localX; 8426 8427 PetscFunctionBegin; 8428 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8429 PetscCall(VecGetDM(U, &dmIn)); 8430 PetscCall(DMGetLocalVector(dmIn, &localU)); 8431 PetscCall(DMGetLocalVector(dm, &localX)); 8432 PetscCall(VecSet(localX, 0.)); 8433 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8434 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8435 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8436 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8437 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8438 PetscCall(DMRestoreLocalVector(dm, &localX)); 8439 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8440 PetscFunctionReturn(PETSC_SUCCESS); 8441 } 8442 8443 /*@C 8444 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. 8445 8446 Not Collective 8447 8448 Input Parameters: 8449 + dm - The `DM` 8450 . time - The time 8451 . label - The `DMLabel` marking the portion of the domain boundary to output 8452 . numIds - The number of label ids to use 8453 . ids - The label ids to use for marking 8454 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8455 . comps - The components to set in the output, or `NULL` for all components 8456 . localU - The input field vector 8457 . funcs - The functions to evaluate, one per field 8458 - mode - The insertion mode for values 8459 8460 Output Parameter: 8461 . localX - The output vector 8462 8463 Calling sequence of `funcs`: 8464 + dim - The spatial dimension 8465 . Nf - The number of input fields 8466 . NfAux - The number of input auxiliary fields 8467 . uOff - The offset of each field in u[] 8468 . uOff_x - The offset of each field in u_x[] 8469 . u - The field values at this point in space 8470 . u_t - The field time derivative at this point in space (or NULL) 8471 . u_x - The field derivatives at this point in space 8472 . aOff - The offset of each auxiliary field in u[] 8473 . aOff_x - The offset of each auxiliary field in u_x[] 8474 . a - The auxiliary field values at this point in space 8475 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8476 . a_x - The auxiliary field derivatives at this point in space 8477 . t - The current time 8478 . x - The coordinates of this point 8479 . n - The face normal 8480 . numConstants - The number of constants 8481 . constants - The value of each constant 8482 - f - The value of the function at this point in space 8483 8484 Level: intermediate 8485 8486 Note: 8487 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. 8488 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 8489 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8490 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8491 8492 Developer Notes: 8493 This API is specific to only particular usage of `DM` 8494 8495 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8496 8497 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8498 @*/ 8499 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) 8500 { 8501 PetscFunctionBegin; 8502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8503 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8504 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8505 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8506 PetscFunctionReturn(PETSC_SUCCESS); 8507 } 8508 8509 /*@C 8510 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8511 8512 Collective 8513 8514 Input Parameters: 8515 + dm - The `DM` 8516 . time - The time 8517 . funcs - The functions to evaluate for each field component 8518 . ctxs - Optional array of contexts to pass to each function, or NULL. 8519 - X - The coefficient vector u_h, a global vector 8520 8521 Output Parameter: 8522 . diff - The diff ||u - u_h||_2 8523 8524 Level: developer 8525 8526 Developer Notes: 8527 This API is specific to only particular usage of `DM` 8528 8529 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8530 8531 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8532 @*/ 8533 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8534 { 8535 PetscFunctionBegin; 8536 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8537 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8538 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8539 PetscFunctionReturn(PETSC_SUCCESS); 8540 } 8541 8542 /*@C 8543 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8544 8545 Collective 8546 8547 Input Parameters: 8548 + dm - The `DM` 8549 . time - The time 8550 . funcs - The gradient functions to evaluate for each field component 8551 . ctxs - Optional array of contexts to pass to each function, or NULL. 8552 . X - The coefficient vector u_h, a global vector 8553 - n - The vector to project along 8554 8555 Output Parameter: 8556 . diff - The diff ||(grad u - grad u_h) . n||_2 8557 8558 Level: developer 8559 8560 Developer Notes: 8561 This API is specific to only particular usage of `DM` 8562 8563 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8564 8565 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8566 @*/ 8567 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) 8568 { 8569 PetscFunctionBegin; 8570 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8571 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8572 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8573 PetscFunctionReturn(PETSC_SUCCESS); 8574 } 8575 8576 /*@C 8577 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8578 8579 Collective 8580 8581 Input Parameters: 8582 + dm - The `DM` 8583 . time - The time 8584 . funcs - The functions to evaluate for each field component 8585 . ctxs - Optional array of contexts to pass to each function, or NULL. 8586 - X - The coefficient vector u_h, a global vector 8587 8588 Output Parameter: 8589 . diff - The array of differences, ||u^f - u^f_h||_2 8590 8591 Level: developer 8592 8593 Developer Notes: 8594 This API is specific to only particular usage of `DM` 8595 8596 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8597 8598 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8599 @*/ 8600 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8601 { 8602 PetscFunctionBegin; 8603 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8604 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8605 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8606 PetscFunctionReturn(PETSC_SUCCESS); 8607 } 8608 8609 /*@C 8610 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8611 8612 Not Collective 8613 8614 Input Parameter: 8615 . dm - The `DM` 8616 8617 Output Parameters: 8618 + nranks - the number of neighbours 8619 - ranks - the neighbors ranks 8620 8621 Level: beginner 8622 8623 Note: 8624 Do not free the array, it is freed when the `DM` is destroyed. 8625 8626 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8627 @*/ 8628 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8629 { 8630 PetscFunctionBegin; 8631 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8632 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8633 PetscFunctionReturn(PETSC_SUCCESS); 8634 } 8635 8636 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8637 8638 /* 8639 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8640 This must be a different function because it requires DM which is not defined in the Mat library 8641 */ 8642 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8643 { 8644 PetscFunctionBegin; 8645 if (coloring->ctype == IS_COLORING_LOCAL) { 8646 Vec x1local; 8647 DM dm; 8648 PetscCall(MatGetDM(J, &dm)); 8649 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8650 PetscCall(DMGetLocalVector(dm, &x1local)); 8651 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8652 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8653 x1 = x1local; 8654 } 8655 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8656 if (coloring->ctype == IS_COLORING_LOCAL) { 8657 DM dm; 8658 PetscCall(MatGetDM(J, &dm)); 8659 PetscCall(DMRestoreLocalVector(dm, &x1)); 8660 } 8661 PetscFunctionReturn(PETSC_SUCCESS); 8662 } 8663 8664 /*@ 8665 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8666 8667 Input Parameters: 8668 + coloring - The matrix to get the `DM` from 8669 - fdcoloring - the `MatFDColoring` object 8670 8671 Level: advanced 8672 8673 Developer Note: 8674 This routine exists because the PETSc `Mat` library does not know about the `DM` objects 8675 8676 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8677 @*/ 8678 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8679 { 8680 PetscFunctionBegin; 8681 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8682 PetscFunctionReturn(PETSC_SUCCESS); 8683 } 8684 8685 /*@ 8686 DMGetCompatibility - determine if two `DM`s are compatible 8687 8688 Collective 8689 8690 Input Parameters: 8691 + dm1 - the first `DM` 8692 - dm2 - the second `DM` 8693 8694 Output Parameters: 8695 + compatible - whether or not the two `DM`s are compatible 8696 - set - whether or not the compatible value was actually determined and set 8697 8698 Level: advanced 8699 8700 Notes: 8701 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8702 of the same topology. This implies that the section (field data) on one 8703 "makes sense" with respect to the topology and parallel decomposition of the other. 8704 Loosely speaking, compatible `DM`s represent the same domain and parallel 8705 decomposition, but hold different data. 8706 8707 Typically, one would confirm compatibility if intending to simultaneously iterate 8708 over a pair of vectors obtained from different `DM`s. 8709 8710 For example, two `DMDA` objects are compatible if they have the same local 8711 and global sizes and the same stencil width. They can have different numbers 8712 of degrees of freedom per node. Thus, one could use the node numbering from 8713 either `DM` in bounds for a loop over vectors derived from either `DM`. 8714 8715 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8716 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8717 .vb 8718 ... 8719 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8720 if (set && compatible) { 8721 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8722 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8723 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8724 for (j=y; j<y+n; ++j) { 8725 for (i=x; i<x+m, ++i) { 8726 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8727 } 8728 } 8729 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8730 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8731 } else { 8732 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8733 } 8734 ... 8735 .ve 8736 8737 Checking compatibility might be expensive for a given implementation of `DM`, 8738 or might be impossible to unambiguously confirm or deny. For this reason, 8739 this function may decline to determine compatibility, and hence users should 8740 always check the "set" output parameter. 8741 8742 A `DM` is always compatible with itself. 8743 8744 In the current implementation, `DM`s which live on "unequal" communicators 8745 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8746 incompatible. 8747 8748 This function is labeled "Collective," as information about all subdomains 8749 is required on each rank. However, in `DM` implementations which store all this 8750 information locally, this function may be merely "Logically Collective". 8751 8752 Developer Note: 8753 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8754 iff B is compatible with A. Thus, this function checks the implementations 8755 of both dm and dmc (if they are of different types), attempting to determine 8756 compatibility. It is left to `DM` implementers to ensure that symmetry is 8757 preserved. The simplest way to do this is, when implementing type-specific 8758 logic for this function, is to check for existing logic in the implementation 8759 of other `DM` types and let *set = PETSC_FALSE if found. 8760 8761 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8762 @*/ 8763 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8764 { 8765 PetscMPIInt compareResult; 8766 DMType type, type2; 8767 PetscBool sameType; 8768 8769 PetscFunctionBegin; 8770 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8771 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8772 8773 /* Declare a DM compatible with itself */ 8774 if (dm1 == dm2) { 8775 *set = PETSC_TRUE; 8776 *compatible = PETSC_TRUE; 8777 PetscFunctionReturn(PETSC_SUCCESS); 8778 } 8779 8780 /* Declare a DM incompatible with a DM that lives on an "unequal" 8781 communicator. Note that this does not preclude compatibility with 8782 DMs living on "congruent" or "similar" communicators, but this must be 8783 determined by the implementation-specific logic */ 8784 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8785 if (compareResult == MPI_UNEQUAL) { 8786 *set = PETSC_TRUE; 8787 *compatible = PETSC_FALSE; 8788 PetscFunctionReturn(PETSC_SUCCESS); 8789 } 8790 8791 /* Pass to the implementation-specific routine, if one exists. */ 8792 if (dm1->ops->getcompatibility) { 8793 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8794 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8795 } 8796 8797 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8798 with an implementation of this function from dm2 */ 8799 PetscCall(DMGetType(dm1, &type)); 8800 PetscCall(DMGetType(dm2, &type2)); 8801 PetscCall(PetscStrcmp(type, type2, &sameType)); 8802 if (!sameType && dm2->ops->getcompatibility) { 8803 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8804 } else { 8805 *set = PETSC_FALSE; 8806 } 8807 PetscFunctionReturn(PETSC_SUCCESS); 8808 } 8809 8810 /*@C 8811 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8812 8813 Logically Collective 8814 8815 Input Parameters: 8816 + dm - the `DM` 8817 . f - the monitor function 8818 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8819 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`) 8820 8821 Options Database Key: 8822 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8823 does not cancel those set via the options database. 8824 8825 Level: intermediate 8826 8827 Note: 8828 Several different monitoring routines may be set by calling 8829 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8830 order in which they were set. 8831 8832 Fortran Note: 8833 Only a single monitor function can be set for each `DM` object 8834 8835 Developer Note: 8836 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8837 8838 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8839 @*/ 8840 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8841 { 8842 PetscInt m; 8843 8844 PetscFunctionBegin; 8845 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8846 for (m = 0; m < dm->numbermonitors; ++m) { 8847 PetscBool identical; 8848 8849 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8850 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 8851 } 8852 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8853 dm->monitor[dm->numbermonitors] = f; 8854 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8855 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8856 PetscFunctionReturn(PETSC_SUCCESS); 8857 } 8858 8859 /*@ 8860 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8861 8862 Logically Collective 8863 8864 Input Parameter: 8865 . dm - the DM 8866 8867 Options Database Key: 8868 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8869 into a code by calls to `DMonitorSet()`, but does not cancel those 8870 set via the options database 8871 8872 Level: intermediate 8873 8874 Note: 8875 There is no way to clear one specific monitor from a `DM` object. 8876 8877 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8878 @*/ 8879 PetscErrorCode DMMonitorCancel(DM dm) 8880 { 8881 PetscInt m; 8882 8883 PetscFunctionBegin; 8884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8885 for (m = 0; m < dm->numbermonitors; ++m) { 8886 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8887 } 8888 dm->numbermonitors = 0; 8889 PetscFunctionReturn(PETSC_SUCCESS); 8890 } 8891 8892 /*@C 8893 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8894 8895 Collective 8896 8897 Input Parameters: 8898 + dm - `DM` object you wish to monitor 8899 . name - the monitor type one is seeking 8900 . help - message indicating what monitoring is done 8901 . manual - manual page for the monitor 8902 . monitor - the monitor function 8903 - 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 8904 8905 Output Parameter: 8906 . flg - Flag set if the monitor was created 8907 8908 Level: developer 8909 8910 .seealso: [](ch_dmbase), `DM`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8911 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8912 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 8913 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8914 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8915 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8916 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8917 @*/ 8918 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8919 { 8920 PetscViewer viewer; 8921 PetscViewerFormat format; 8922 8923 PetscFunctionBegin; 8924 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8925 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8926 if (*flg) { 8927 PetscViewerAndFormat *vf; 8928 8929 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8930 PetscCall(PetscOptionsRestoreViewer(&viewer)); 8931 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8932 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8933 } 8934 PetscFunctionReturn(PETSC_SUCCESS); 8935 } 8936 8937 /*@ 8938 DMMonitor - runs the user provided monitor routines, if they exist 8939 8940 Collective 8941 8942 Input Parameter: 8943 . dm - The `DM` 8944 8945 Level: developer 8946 8947 Developer Note: 8948 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 8949 related to the discretization process seems rather specialized since some `DM` have no 8950 concept of discretization. 8951 8952 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 8953 @*/ 8954 PetscErrorCode DMMonitor(DM dm) 8955 { 8956 PetscInt m; 8957 8958 PetscFunctionBegin; 8959 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 8960 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8961 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 8962 PetscFunctionReturn(PETSC_SUCCESS); 8963 } 8964 8965 /*@ 8966 DMComputeError - Computes the error assuming the user has provided the exact solution functions 8967 8968 Collective 8969 8970 Input Parameters: 8971 + dm - The `DM` 8972 - sol - The solution vector 8973 8974 Input/Output Parameter: 8975 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 8976 contains the error in each field 8977 8978 Output Parameter: 8979 . errorVec - A vector to hold the cellwise error (may be `NULL`) 8980 8981 Level: developer 8982 8983 Note: 8984 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 8985 8986 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 8987 @*/ 8988 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 8989 { 8990 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 8991 void **ctxs; 8992 PetscReal time; 8993 PetscInt Nf, f, Nds, s; 8994 8995 PetscFunctionBegin; 8996 PetscCall(DMGetNumFields(dm, &Nf)); 8997 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 8998 PetscCall(DMGetNumDS(dm, &Nds)); 8999 for (s = 0; s < Nds; ++s) { 9000 PetscDS ds; 9001 DMLabel label; 9002 IS fieldIS; 9003 const PetscInt *fields; 9004 PetscInt dsNf; 9005 9006 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 9007 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 9008 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 9009 for (f = 0; f < dsNf; ++f) { 9010 const PetscInt field = fields[f]; 9011 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 9012 } 9013 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 9014 } 9015 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); 9016 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 9017 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 9018 if (errorVec) { 9019 DM edm; 9020 DMPolytopeType ct; 9021 PetscBool simplex; 9022 PetscInt dim, cStart, Nf; 9023 9024 PetscCall(DMClone(dm, &edm)); 9025 PetscCall(DMGetDimension(edm, &dim)); 9026 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 9027 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 9028 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9029 PetscCall(DMGetNumFields(dm, &Nf)); 9030 for (f = 0; f < Nf; ++f) { 9031 PetscFE fe, efe; 9032 PetscQuadrature q; 9033 const char *name; 9034 9035 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9036 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9037 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9038 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9039 PetscCall(PetscFEGetQuadrature(fe, &q)); 9040 PetscCall(PetscFESetQuadrature(efe, q)); 9041 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9042 PetscCall(PetscFEDestroy(&efe)); 9043 } 9044 PetscCall(DMCreateDS(edm)); 9045 9046 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9047 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9048 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9049 PetscCall(DMDestroy(&edm)); 9050 } 9051 PetscCall(PetscFree2(exactSol, ctxs)); 9052 PetscFunctionReturn(PETSC_SUCCESS); 9053 } 9054 9055 /*@ 9056 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9057 9058 Not Collective 9059 9060 Input Parameter: 9061 . dm - The `DM` 9062 9063 Output Parameter: 9064 . numAux - The number of auxiliary data vectors 9065 9066 Level: advanced 9067 9068 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9069 @*/ 9070 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9071 { 9072 PetscFunctionBegin; 9073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9074 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9075 PetscFunctionReturn(PETSC_SUCCESS); 9076 } 9077 9078 /*@ 9079 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9080 9081 Not Collective 9082 9083 Input Parameters: 9084 + dm - The `DM` 9085 . label - The `DMLabel` 9086 . value - The label value indicating the region 9087 - part - The equation part, or 0 if unused 9088 9089 Output Parameter: 9090 . aux - The `Vec` holding auxiliary field data 9091 9092 Level: advanced 9093 9094 Note: 9095 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9096 9097 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9098 @*/ 9099 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9100 { 9101 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9102 PetscBool has; 9103 9104 PetscFunctionBegin; 9105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9106 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9107 key.label = label; 9108 key.value = value; 9109 key.part = part; 9110 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9111 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9112 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9113 PetscFunctionReturn(PETSC_SUCCESS); 9114 } 9115 9116 /*@ 9117 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9118 9119 Not Collective because auxiliary vectors are not parallel 9120 9121 Input Parameters: 9122 + dm - The `DM` 9123 . label - The `DMLabel` 9124 . value - The label value indicating the region 9125 . part - The equation part, or 0 if unused 9126 - aux - The `Vec` holding auxiliary field data 9127 9128 Level: advanced 9129 9130 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9131 @*/ 9132 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9133 { 9134 Vec old; 9135 PetscHashAuxKey key; 9136 9137 PetscFunctionBegin; 9138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9139 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9140 key.label = label; 9141 key.value = value; 9142 key.part = part; 9143 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9144 PetscCall(PetscObjectReference((PetscObject)aux)); 9145 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9146 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9147 PetscCall(VecDestroy(&old)); 9148 PetscFunctionReturn(PETSC_SUCCESS); 9149 } 9150 9151 /*@C 9152 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9153 9154 Not Collective 9155 9156 Input Parameter: 9157 . dm - The `DM` 9158 9159 Output Parameters: 9160 + labels - The `DMLabel`s for each `Vec` 9161 . values - The label values for each `Vec` 9162 - parts - The equation parts for each `Vec` 9163 9164 Level: advanced 9165 9166 Note: 9167 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9168 9169 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9170 @*/ 9171 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9172 { 9173 PetscHashAuxKey *keys; 9174 PetscInt n, i, off = 0; 9175 9176 PetscFunctionBegin; 9177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9178 PetscAssertPointer(labels, 2); 9179 PetscAssertPointer(values, 3); 9180 PetscAssertPointer(parts, 4); 9181 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9182 PetscCall(PetscMalloc1(n, &keys)); 9183 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9184 for (i = 0; i < n; ++i) { 9185 labels[i] = keys[i].label; 9186 values[i] = keys[i].value; 9187 parts[i] = keys[i].part; 9188 } 9189 PetscCall(PetscFree(keys)); 9190 PetscFunctionReturn(PETSC_SUCCESS); 9191 } 9192 9193 /*@ 9194 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9195 9196 Not Collective 9197 9198 Input Parameter: 9199 . dm - The `DM` 9200 9201 Output Parameter: 9202 . dmNew - The new `DM`, now with the same auxiliary data 9203 9204 Level: advanced 9205 9206 Note: 9207 This is a shallow copy of the auxiliary vectors 9208 9209 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9210 @*/ 9211 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9212 { 9213 PetscFunctionBegin; 9214 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9215 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9216 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9217 PetscCall(DMClearAuxiliaryVec(dmNew)); 9218 9219 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9220 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9221 { 9222 Vec *auxData; 9223 PetscInt n, i, off = 0; 9224 9225 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9226 PetscCall(PetscMalloc1(n, &auxData)); 9227 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9228 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9229 PetscCall(PetscFree(auxData)); 9230 } 9231 PetscFunctionReturn(PETSC_SUCCESS); 9232 } 9233 9234 /*@ 9235 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9236 9237 Not Collective 9238 9239 Input Parameter: 9240 . dm - The `DM` 9241 9242 Level: advanced 9243 9244 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9245 @*/ 9246 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9247 { 9248 Vec *auxData; 9249 PetscInt n, i, off = 0; 9250 9251 PetscFunctionBegin; 9252 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9253 PetscCall(PetscMalloc1(n, &auxData)); 9254 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9255 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9256 PetscCall(PetscFree(auxData)); 9257 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9258 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9259 PetscFunctionReturn(PETSC_SUCCESS); 9260 } 9261 9262 /*@C 9263 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9264 9265 Not Collective 9266 9267 Input Parameters: 9268 + ct - The `DMPolytopeType` 9269 . sourceCone - The source arrangement of faces 9270 - targetCone - The target arrangement of faces 9271 9272 Output Parameters: 9273 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9274 - found - Flag indicating that a suitable orientation was found 9275 9276 Level: advanced 9277 9278 Note: 9279 An arrangement is a face order combined with an orientation for each face 9280 9281 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9282 that labels each arrangement (face ordering plus orientation for each face). 9283 9284 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9285 9286 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9287 @*/ 9288 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9289 { 9290 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9291 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9292 PetscInt o, c; 9293 9294 PetscFunctionBegin; 9295 if (!nO) { 9296 *ornt = 0; 9297 *found = PETSC_TRUE; 9298 PetscFunctionReturn(PETSC_SUCCESS); 9299 } 9300 for (o = -nO; o < nO; ++o) { 9301 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9302 9303 for (c = 0; c < cS; ++c) 9304 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9305 if (c == cS) { 9306 *ornt = o; 9307 break; 9308 } 9309 } 9310 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9311 PetscFunctionReturn(PETSC_SUCCESS); 9312 } 9313 9314 /*@C 9315 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9316 9317 Not Collective 9318 9319 Input Parameters: 9320 + ct - The `DMPolytopeType` 9321 . sourceCone - The source arrangement of faces 9322 - targetCone - The target arrangement of faces 9323 9324 Output Parameter: 9325 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9326 9327 Level: advanced 9328 9329 Note: 9330 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9331 9332 Developer Note: 9333 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9334 9335 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9336 @*/ 9337 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9338 { 9339 PetscBool found; 9340 9341 PetscFunctionBegin; 9342 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9343 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9344 PetscFunctionReturn(PETSC_SUCCESS); 9345 } 9346 9347 /*@C 9348 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9349 9350 Not Collective 9351 9352 Input Parameters: 9353 + ct - The `DMPolytopeType` 9354 . sourceVert - The source arrangement of vertices 9355 - targetVert - The target arrangement of vertices 9356 9357 Output Parameters: 9358 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9359 - found - Flag indicating that a suitable orientation was found 9360 9361 Level: advanced 9362 9363 Notes: 9364 An arrangement is a vertex order 9365 9366 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9367 that labels each arrangement (vertex ordering). 9368 9369 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9370 9371 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9372 @*/ 9373 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9374 { 9375 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9376 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9377 PetscInt o, c; 9378 9379 PetscFunctionBegin; 9380 if (!nO) { 9381 *ornt = 0; 9382 *found = PETSC_TRUE; 9383 PetscFunctionReturn(PETSC_SUCCESS); 9384 } 9385 for (o = -nO; o < nO; ++o) { 9386 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9387 9388 for (c = 0; c < cS; ++c) 9389 if (sourceVert[arr[c]] != targetVert[c]) break; 9390 if (c == cS) { 9391 *ornt = o; 9392 break; 9393 } 9394 } 9395 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9396 PetscFunctionReturn(PETSC_SUCCESS); 9397 } 9398 9399 /*@C 9400 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9401 9402 Not Collective 9403 9404 Input Parameters: 9405 + ct - The `DMPolytopeType` 9406 . sourceCone - The source arrangement of vertices 9407 - targetCone - The target arrangement of vertices 9408 9409 Output Parameter: 9410 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9411 9412 Level: advanced 9413 9414 Note: 9415 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9416 9417 Developer Note: 9418 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9419 9420 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9421 @*/ 9422 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9423 { 9424 PetscBool found; 9425 9426 PetscFunctionBegin; 9427 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9428 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9429 PetscFunctionReturn(PETSC_SUCCESS); 9430 } 9431 9432 /*@C 9433 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9434 9435 Not Collective 9436 9437 Input Parameters: 9438 + ct - The `DMPolytopeType` 9439 - point - Coordinates of the point 9440 9441 Output Parameter: 9442 . inside - Flag indicating whether the point is inside the reference cell of given type 9443 9444 Level: advanced 9445 9446 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9447 @*/ 9448 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9449 { 9450 PetscReal sum = 0.0; 9451 PetscInt d; 9452 9453 PetscFunctionBegin; 9454 *inside = PETSC_TRUE; 9455 switch (ct) { 9456 case DM_POLYTOPE_TRIANGLE: 9457 case DM_POLYTOPE_TETRAHEDRON: 9458 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9459 if (point[d] < -1.0) { 9460 *inside = PETSC_FALSE; 9461 break; 9462 } 9463 sum += point[d]; 9464 } 9465 if (sum > PETSC_SMALL) { 9466 *inside = PETSC_FALSE; 9467 break; 9468 } 9469 break; 9470 case DM_POLYTOPE_QUADRILATERAL: 9471 case DM_POLYTOPE_HEXAHEDRON: 9472 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9473 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9474 *inside = PETSC_FALSE; 9475 break; 9476 } 9477 break; 9478 default: 9479 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9480 } 9481 PetscFunctionReturn(PETSC_SUCCESS); 9482 } 9483 9484 /*@ 9485 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9486 9487 Logically collective 9488 9489 Input Parameters: 9490 + dm - The DM 9491 - reorder - Flag for reordering 9492 9493 Level: intermediate 9494 9495 .seealso: `DMReorderSectionGetDefault()` 9496 @*/ 9497 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9498 { 9499 PetscFunctionBegin; 9500 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9501 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9502 PetscFunctionReturn(PETSC_SUCCESS); 9503 } 9504 9505 /*@ 9506 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9507 9508 Not collective 9509 9510 Input Parameter: 9511 . dm - The DM 9512 9513 Output Parameter: 9514 . reorder - Flag for reordering 9515 9516 Level: intermediate 9517 9518 .seealso: `DMReorderSetDefault()` 9519 @*/ 9520 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9521 { 9522 PetscFunctionBegin; 9523 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9524 PetscAssertPointer(reorder, 2); 9525 *reorder = DM_REORDER_DEFAULT_NOTSET; 9526 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9527 PetscFunctionReturn(PETSC_SUCCESS); 9528 } 9529 9530 /*@C 9531 DMReorderSectionSetType - Set the type of local section reordering 9532 9533 Logically collective 9534 9535 Input Parameters: 9536 + dm - The DM 9537 - reorder - The reordering method 9538 9539 Level: intermediate 9540 9541 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9542 @*/ 9543 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9544 { 9545 PetscFunctionBegin; 9546 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9547 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9548 PetscFunctionReturn(PETSC_SUCCESS); 9549 } 9550 9551 /*@C 9552 DMReorderSectionGetType - Get the reordering type for the local section 9553 9554 Not collective 9555 9556 Input Parameter: 9557 . dm - The DM 9558 9559 Output Parameter: 9560 . reorder - The reordering method 9561 9562 Level: intermediate 9563 9564 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9565 @*/ 9566 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9567 { 9568 PetscFunctionBegin; 9569 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9570 PetscAssertPointer(reorder, 2); 9571 *reorder = NULL; 9572 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9573 PetscFunctionReturn(PETSC_SUCCESS); 9574 } 9575