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