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