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