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