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