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