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