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