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