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 if (dm->setfromoptionscalled) { 6033 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds)); 6034 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn)); 6035 } 6036 PetscCall(PetscDSSetUp(dm->probs[s].ds)); 6037 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn)); 6038 } 6039 } 6040 PetscFunctionReturn(PETSC_SUCCESS); 6041 } 6042 6043 /*@ 6044 DMUseTensorOrder - Use a tensor product closure ordering for the default section 6045 6046 Input Parameters: 6047 + dm - The DM 6048 - tensor - Flag for tensor order 6049 6050 Level: developer 6051 6052 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()` 6053 @*/ 6054 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor) 6055 { 6056 PetscInt Nf; 6057 PetscBool reorder = PETSC_TRUE, isPlex; 6058 6059 PetscFunctionBegin; 6060 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 6061 PetscCall(DMGetNumFields(dm, &Nf)); 6062 for (PetscInt f = 0; f < Nf; ++f) { 6063 PetscObject obj; 6064 PetscClassId id; 6065 6066 PetscCall(DMGetField(dm, f, NULL, &obj)); 6067 PetscCall(PetscObjectGetClassId(obj, &id)); 6068 if (id == PETSCFE_CLASSID) { 6069 PetscSpace sp; 6070 PetscBool tensor; 6071 6072 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp)); 6073 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor)); 6074 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE; 6075 } else reorder = PETSC_FALSE; 6076 } 6077 if (tensor) { 6078 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 6079 } else { 6080 PetscSection s; 6081 6082 PetscCall(DMGetLocalSection(dm, &s)); 6083 if (s) PetscCall(PetscSectionResetClosurePermutation(s)); 6084 } 6085 PetscFunctionReturn(PETSC_SUCCESS); 6086 } 6087 6088 /*@ 6089 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 6090 6091 Collective 6092 6093 Input Parameters: 6094 + dm - The `DM` 6095 - time - The time 6096 6097 Output Parameters: 6098 + u - The vector will be filled with exact solution values, or `NULL` 6099 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL` 6100 6101 Level: developer 6102 6103 Note: 6104 The user must call `PetscDSSetExactSolution()` before using this routine 6105 6106 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()` 6107 @*/ 6108 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 6109 { 6110 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 6111 void **ectxs; 6112 Vec locu, locu_t; 6113 PetscInt Nf, Nds, s; 6114 6115 PetscFunctionBegin; 6116 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6117 if (u) { 6118 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 6119 PetscCall(DMGetLocalVector(dm, &locu)); 6120 PetscCall(VecSet(locu, 0.)); 6121 } 6122 if (u_t) { 6123 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 6124 PetscCall(DMGetLocalVector(dm, &locu_t)); 6125 PetscCall(VecSet(locu_t, 0.)); 6126 } 6127 PetscCall(DMGetNumFields(dm, &Nf)); 6128 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 6129 PetscCall(DMGetNumDS(dm, &Nds)); 6130 for (s = 0; s < Nds; ++s) { 6131 PetscDS ds; 6132 DMLabel label; 6133 IS fieldIS; 6134 const PetscInt *fields, id = 1; 6135 PetscInt dsNf, f; 6136 6137 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 6138 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6139 PetscCall(ISGetIndices(fieldIS, &fields)); 6140 PetscCall(PetscArrayzero(exacts, Nf)); 6141 PetscCall(PetscArrayzero(ectxs, Nf)); 6142 if (u) { 6143 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6144 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6145 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6146 } 6147 if (u_t) { 6148 PetscCall(PetscArrayzero(exacts, Nf)); 6149 PetscCall(PetscArrayzero(ectxs, Nf)); 6150 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6151 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6152 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6153 } 6154 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6155 } 6156 if (u) { 6157 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6158 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6159 } 6160 if (u_t) { 6161 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6162 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6163 } 6164 PetscCall(PetscFree2(exacts, ectxs)); 6165 if (u) { 6166 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u)); 6167 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u)); 6168 PetscCall(DMRestoreLocalVector(dm, &locu)); 6169 } 6170 if (u_t) { 6171 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6172 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6173 PetscCall(DMRestoreLocalVector(dm, &locu_t)); 6174 } 6175 PetscFunctionReturn(PETSC_SUCCESS); 6176 } 6177 6178 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 6179 { 6180 PetscDS dsNew, dsInNew = NULL; 6181 6182 PetscFunctionBegin; 6183 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6184 PetscCall(PetscDSCopy(ds, dm, dsNew)); 6185 if (dsIn) { 6186 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew)); 6187 PetscCall(PetscDSCopy(dsIn, dm, dsInNew)); 6188 } 6189 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew)); 6190 PetscCall(PetscDSDestroy(&dsNew)); 6191 PetscCall(PetscDSDestroy(&dsInNew)); 6192 PetscFunctionReturn(PETSC_SUCCESS); 6193 } 6194 6195 /*@ 6196 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6197 6198 Collective 6199 6200 Input Parameter: 6201 . dm - The `DM` 6202 6203 Output Parameter: 6204 . newdm - The `DM` 6205 6206 Level: advanced 6207 6208 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6209 @*/ 6210 PetscErrorCode DMCopyDS(DM dm, DM newdm) 6211 { 6212 PetscInt Nds, s; 6213 6214 PetscFunctionBegin; 6215 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 6216 PetscCall(DMGetNumDS(dm, &Nds)); 6217 PetscCall(DMClearDS(newdm)); 6218 for (s = 0; s < Nds; ++s) { 6219 DMLabel label; 6220 IS fields; 6221 PetscDS ds, dsIn, newds; 6222 PetscInt Nbd, bd; 6223 6224 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn)); 6225 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6226 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn)); 6227 /* Complete new labels in the new DS */ 6228 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL)); 6229 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6230 for (bd = 0; bd < Nbd; ++bd) { 6231 PetscWeakForm wf; 6232 DMLabel label; 6233 PetscInt field; 6234 6235 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6236 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6237 } 6238 } 6239 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6240 PetscFunctionReturn(PETSC_SUCCESS); 6241 } 6242 6243 /*@ 6244 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6245 6246 Collective 6247 6248 Input Parameter: 6249 . dm - The `DM` 6250 6251 Output Parameter: 6252 . newdm - The `DM` 6253 6254 Level: advanced 6255 6256 Developer Notes: 6257 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6258 6259 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()` 6260 @*/ 6261 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6262 { 6263 PetscFunctionBegin; 6264 PetscCall(DMCopyFields(dm, newdm)); 6265 PetscCall(DMCopyDS(dm, newdm)); 6266 PetscFunctionReturn(PETSC_SUCCESS); 6267 } 6268 6269 /*@ 6270 DMGetDimension - Return the topological dimension of the `DM` 6271 6272 Not Collective 6273 6274 Input Parameter: 6275 . dm - The `DM` 6276 6277 Output Parameter: 6278 . dim - The topological dimension 6279 6280 Level: beginner 6281 6282 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()` 6283 @*/ 6284 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6285 { 6286 PetscFunctionBegin; 6287 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6288 PetscAssertPointer(dim, 2); 6289 *dim = dm->dim; 6290 PetscFunctionReturn(PETSC_SUCCESS); 6291 } 6292 6293 /*@ 6294 DMSetDimension - Set the topological dimension of the `DM` 6295 6296 Collective 6297 6298 Input Parameters: 6299 + dm - The `DM` 6300 - dim - The topological dimension 6301 6302 Level: beginner 6303 6304 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()` 6305 @*/ 6306 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6307 { 6308 PetscDS ds; 6309 PetscInt Nds, n; 6310 6311 PetscFunctionBegin; 6312 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6313 PetscValidLogicalCollectiveInt(dm, dim, 2); 6314 dm->dim = dim; 6315 if (dm->dim >= 0) { 6316 PetscCall(DMGetNumDS(dm, &Nds)); 6317 for (n = 0; n < Nds; ++n) { 6318 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 6319 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6320 } 6321 } 6322 PetscFunctionReturn(PETSC_SUCCESS); 6323 } 6324 6325 /*@ 6326 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6327 6328 Collective 6329 6330 Input Parameters: 6331 + dm - the `DM` 6332 - dim - the dimension 6333 6334 Output Parameters: 6335 + pStart - The first point of the given dimension 6336 - pEnd - The first point following points of the given dimension 6337 6338 Level: intermediate 6339 6340 Note: 6341 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6342 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6343 then the interval is empty. 6344 6345 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6346 @*/ 6347 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6348 { 6349 PetscInt d; 6350 6351 PetscFunctionBegin; 6352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6353 PetscCall(DMGetDimension(dm, &d)); 6354 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6355 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6356 PetscFunctionReturn(PETSC_SUCCESS); 6357 } 6358 6359 /*@ 6360 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6361 6362 Collective 6363 6364 Input Parameter: 6365 . dm - The original `DM` 6366 6367 Output Parameter: 6368 . odm - The `DM` which provides the layout for output 6369 6370 Level: intermediate 6371 6372 Note: 6373 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6374 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6375 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6376 6377 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6378 @*/ 6379 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6380 { 6381 PetscSection section; 6382 PetscBool hasConstraints, ghasConstraints; 6383 6384 PetscFunctionBegin; 6385 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6386 PetscAssertPointer(odm, 2); 6387 PetscCall(DMGetLocalSection(dm, §ion)); 6388 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6389 PetscCall(MPIU_Allreduce(&hasConstraints, &ghasConstraints, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6390 if (!ghasConstraints) { 6391 *odm = dm; 6392 PetscFunctionReturn(PETSC_SUCCESS); 6393 } 6394 if (!dm->dmBC) { 6395 PetscSection newSection, gsection; 6396 PetscSF sf; 6397 6398 PetscCall(DMClone(dm, &dm->dmBC)); 6399 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6400 PetscCall(PetscSectionClone(section, &newSection)); 6401 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6402 PetscCall(PetscSectionDestroy(&newSection)); 6403 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6404 PetscCall(PetscSectionCreateGlobalSection(section, sf, PETSC_TRUE, PETSC_FALSE, &gsection)); 6405 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6406 PetscCall(PetscSectionDestroy(&gsection)); 6407 } 6408 *odm = dm->dmBC; 6409 PetscFunctionReturn(PETSC_SUCCESS); 6410 } 6411 6412 /*@ 6413 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6414 6415 Input Parameter: 6416 . dm - The original `DM` 6417 6418 Output Parameters: 6419 + num - The output sequence number 6420 - val - The output sequence value 6421 6422 Level: intermediate 6423 6424 Note: 6425 This is intended for output that should appear in sequence, for instance 6426 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6427 6428 Developer Notes: 6429 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6430 not directly related to the `DM`. 6431 6432 .seealso: [](ch_dmbase), `DM`, `VecView()` 6433 @*/ 6434 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6435 { 6436 PetscFunctionBegin; 6437 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6438 if (num) { 6439 PetscAssertPointer(num, 2); 6440 *num = dm->outputSequenceNum; 6441 } 6442 if (val) { 6443 PetscAssertPointer(val, 3); 6444 *val = dm->outputSequenceVal; 6445 } 6446 PetscFunctionReturn(PETSC_SUCCESS); 6447 } 6448 6449 /*@ 6450 DMSetOutputSequenceNumber - Set the sequence number/value for output 6451 6452 Input Parameters: 6453 + dm - The original `DM` 6454 . num - The output sequence number 6455 - val - The output sequence value 6456 6457 Level: intermediate 6458 6459 Note: 6460 This is intended for output that should appear in sequence, for instance 6461 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6462 6463 .seealso: [](ch_dmbase), `DM`, `VecView()` 6464 @*/ 6465 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6466 { 6467 PetscFunctionBegin; 6468 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6469 dm->outputSequenceNum = num; 6470 dm->outputSequenceVal = val; 6471 PetscFunctionReturn(PETSC_SUCCESS); 6472 } 6473 6474 /*@C 6475 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6476 6477 Input Parameters: 6478 + dm - The original `DM` 6479 . viewer - The viewer to get it from 6480 . name - The sequence name 6481 - num - The output sequence number 6482 6483 Output Parameter: 6484 . val - The output sequence value 6485 6486 Level: intermediate 6487 6488 Note: 6489 This is intended for output that should appear in sequence, for instance 6490 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6491 6492 Developer Notes: 6493 It is unclear at the user API level why a `DM` is needed as input 6494 6495 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6496 @*/ 6497 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 6498 { 6499 PetscBool ishdf5; 6500 6501 PetscFunctionBegin; 6502 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6503 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6504 PetscAssertPointer(val, 5); 6505 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6506 if (ishdf5) { 6507 #if defined(PETSC_HAVE_HDF5) 6508 PetscScalar value; 6509 6510 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6511 *val = PetscRealPart(value); 6512 #endif 6513 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6514 PetscFunctionReturn(PETSC_SUCCESS); 6515 } 6516 6517 /*@ 6518 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6519 6520 Not Collective 6521 6522 Input Parameter: 6523 . dm - The `DM` 6524 6525 Output Parameter: 6526 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6527 6528 Level: beginner 6529 6530 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6531 @*/ 6532 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6533 { 6534 PetscFunctionBegin; 6535 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6536 PetscAssertPointer(useNatural, 2); 6537 *useNatural = dm->useNatural; 6538 PetscFunctionReturn(PETSC_SUCCESS); 6539 } 6540 6541 /*@ 6542 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6543 6544 Collective 6545 6546 Input Parameters: 6547 + dm - The `DM` 6548 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6549 6550 Note: 6551 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6552 6553 Level: beginner 6554 6555 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6556 @*/ 6557 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6558 { 6559 PetscFunctionBegin; 6560 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6561 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6562 dm->useNatural = useNatural; 6563 PetscFunctionReturn(PETSC_SUCCESS); 6564 } 6565 6566 /*@C 6567 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6568 6569 Not Collective 6570 6571 Input Parameters: 6572 + dm - The `DM` object 6573 - name - The label name 6574 6575 Level: intermediate 6576 6577 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6578 @*/ 6579 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6580 { 6581 PetscBool flg; 6582 DMLabel label; 6583 6584 PetscFunctionBegin; 6585 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6586 PetscAssertPointer(name, 2); 6587 PetscCall(DMHasLabel(dm, name, &flg)); 6588 if (!flg) { 6589 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6590 PetscCall(DMAddLabel(dm, label)); 6591 PetscCall(DMLabelDestroy(&label)); 6592 } 6593 PetscFunctionReturn(PETSC_SUCCESS); 6594 } 6595 6596 /*@C 6597 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6598 6599 Not Collective 6600 6601 Input Parameters: 6602 + dm - The `DM` object 6603 . l - The index for the label 6604 - name - The label name 6605 6606 Level: intermediate 6607 6608 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6609 @*/ 6610 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6611 { 6612 DMLabelLink orig, prev = NULL; 6613 DMLabel label; 6614 PetscInt Nl, m; 6615 PetscBool flg, match; 6616 const char *lname; 6617 6618 PetscFunctionBegin; 6619 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6620 PetscAssertPointer(name, 3); 6621 PetscCall(DMHasLabel(dm, name, &flg)); 6622 if (!flg) { 6623 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6624 PetscCall(DMAddLabel(dm, label)); 6625 PetscCall(DMLabelDestroy(&label)); 6626 } 6627 PetscCall(DMGetNumLabels(dm, &Nl)); 6628 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6629 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6630 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6631 PetscCall(PetscStrcmp(name, lname, &match)); 6632 if (match) break; 6633 } 6634 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6635 if (!m) dm->labels = orig->next; 6636 else prev->next = orig->next; 6637 if (!l) { 6638 orig->next = dm->labels; 6639 dm->labels = orig; 6640 } else { 6641 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next) 6642 ; 6643 orig->next = prev->next; 6644 prev->next = orig; 6645 } 6646 PetscFunctionReturn(PETSC_SUCCESS); 6647 } 6648 6649 /*@C 6650 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6651 6652 Not Collective 6653 6654 Input Parameters: 6655 + dm - The `DM` object 6656 . name - The label name 6657 - point - The mesh point 6658 6659 Output Parameter: 6660 . value - The label value for this point, or -1 if the point is not in the label 6661 6662 Level: beginner 6663 6664 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6665 @*/ 6666 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6667 { 6668 DMLabel label; 6669 6670 PetscFunctionBegin; 6671 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6672 PetscAssertPointer(name, 2); 6673 PetscCall(DMGetLabel(dm, name, &label)); 6674 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6675 PetscCall(DMLabelGetValue(label, point, value)); 6676 PetscFunctionReturn(PETSC_SUCCESS); 6677 } 6678 6679 /*@C 6680 DMSetLabelValue - Add a point to a `DMLabel` with given value 6681 6682 Not Collective 6683 6684 Input Parameters: 6685 + dm - The `DM` object 6686 . name - The label name 6687 . point - The mesh point 6688 - value - The label value for this point 6689 6690 Output Parameter: 6691 6692 Level: beginner 6693 6694 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6695 @*/ 6696 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6697 { 6698 DMLabel label; 6699 6700 PetscFunctionBegin; 6701 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6702 PetscAssertPointer(name, 2); 6703 PetscCall(DMGetLabel(dm, name, &label)); 6704 if (!label) { 6705 PetscCall(DMCreateLabel(dm, name)); 6706 PetscCall(DMGetLabel(dm, name, &label)); 6707 } 6708 PetscCall(DMLabelSetValue(label, point, value)); 6709 PetscFunctionReturn(PETSC_SUCCESS); 6710 } 6711 6712 /*@C 6713 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6714 6715 Not Collective 6716 6717 Input Parameters: 6718 + dm - The `DM` object 6719 . name - The label name 6720 . point - The mesh point 6721 - value - The label value for this point 6722 6723 Level: beginner 6724 6725 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6726 @*/ 6727 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6728 { 6729 DMLabel label; 6730 6731 PetscFunctionBegin; 6732 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6733 PetscAssertPointer(name, 2); 6734 PetscCall(DMGetLabel(dm, name, &label)); 6735 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6736 PetscCall(DMLabelClearValue(label, point, value)); 6737 PetscFunctionReturn(PETSC_SUCCESS); 6738 } 6739 6740 /*@C 6741 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6742 6743 Not Collective 6744 6745 Input Parameters: 6746 + dm - The `DM` object 6747 - name - The label name 6748 6749 Output Parameter: 6750 . size - The number of different integer ids, or 0 if the label does not exist 6751 6752 Level: beginner 6753 6754 Developer Notes: 6755 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6756 6757 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6758 @*/ 6759 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6760 { 6761 DMLabel label; 6762 6763 PetscFunctionBegin; 6764 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6765 PetscAssertPointer(name, 2); 6766 PetscAssertPointer(size, 3); 6767 PetscCall(DMGetLabel(dm, name, &label)); 6768 *size = 0; 6769 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6770 PetscCall(DMLabelGetNumValues(label, size)); 6771 PetscFunctionReturn(PETSC_SUCCESS); 6772 } 6773 6774 /*@C 6775 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6776 6777 Not Collective 6778 6779 Input Parameters: 6780 + dm - The `DM` object 6781 - name - The label name 6782 6783 Output Parameter: 6784 . ids - The integer ids, or `NULL` if the label does not exist 6785 6786 Level: beginner 6787 6788 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6789 @*/ 6790 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6791 { 6792 DMLabel label; 6793 6794 PetscFunctionBegin; 6795 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6796 PetscAssertPointer(name, 2); 6797 PetscAssertPointer(ids, 3); 6798 PetscCall(DMGetLabel(dm, name, &label)); 6799 *ids = NULL; 6800 if (label) { 6801 PetscCall(DMLabelGetValueIS(label, ids)); 6802 } else { 6803 /* returning an empty IS */ 6804 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6805 } 6806 PetscFunctionReturn(PETSC_SUCCESS); 6807 } 6808 6809 /*@C 6810 DMGetStratumSize - Get the number of points in a label stratum 6811 6812 Not Collective 6813 6814 Input Parameters: 6815 + dm - The `DM` object 6816 . name - The label name 6817 - value - The stratum value 6818 6819 Output Parameter: 6820 . size - The number of points, also called the stratum size 6821 6822 Level: beginner 6823 6824 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 6825 @*/ 6826 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 6827 { 6828 DMLabel label; 6829 6830 PetscFunctionBegin; 6831 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6832 PetscAssertPointer(name, 2); 6833 PetscAssertPointer(size, 4); 6834 PetscCall(DMGetLabel(dm, name, &label)); 6835 *size = 0; 6836 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6837 PetscCall(DMLabelGetStratumSize(label, value, size)); 6838 PetscFunctionReturn(PETSC_SUCCESS); 6839 } 6840 6841 /*@C 6842 DMGetStratumIS - Get the points in a label stratum 6843 6844 Not Collective 6845 6846 Input Parameters: 6847 + dm - The `DM` object 6848 . name - The label name 6849 - value - The stratum value 6850 6851 Output Parameter: 6852 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 6853 6854 Level: beginner 6855 6856 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 6857 @*/ 6858 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 6859 { 6860 DMLabel label; 6861 6862 PetscFunctionBegin; 6863 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6864 PetscAssertPointer(name, 2); 6865 PetscAssertPointer(points, 4); 6866 PetscCall(DMGetLabel(dm, name, &label)); 6867 *points = NULL; 6868 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6869 PetscCall(DMLabelGetStratumIS(label, value, points)); 6870 PetscFunctionReturn(PETSC_SUCCESS); 6871 } 6872 6873 /*@C 6874 DMSetStratumIS - Set the points in a label stratum 6875 6876 Not Collective 6877 6878 Input Parameters: 6879 + dm - The `DM` object 6880 . name - The label name 6881 . value - The stratum value 6882 - points - The stratum points 6883 6884 Level: beginner 6885 6886 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 6887 @*/ 6888 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 6889 { 6890 DMLabel label; 6891 6892 PetscFunctionBegin; 6893 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6894 PetscAssertPointer(name, 2); 6895 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 6896 PetscCall(DMGetLabel(dm, name, &label)); 6897 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6898 PetscCall(DMLabelSetStratumIS(label, value, points)); 6899 PetscFunctionReturn(PETSC_SUCCESS); 6900 } 6901 6902 /*@C 6903 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 6904 6905 Not Collective 6906 6907 Input Parameters: 6908 + dm - The `DM` object 6909 . name - The label name 6910 - value - The label value for this point 6911 6912 Output Parameter: 6913 6914 Level: beginner 6915 6916 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6917 @*/ 6918 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 6919 { 6920 DMLabel label; 6921 6922 PetscFunctionBegin; 6923 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6924 PetscAssertPointer(name, 2); 6925 PetscCall(DMGetLabel(dm, name, &label)); 6926 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6927 PetscCall(DMLabelClearStratum(label, value)); 6928 PetscFunctionReturn(PETSC_SUCCESS); 6929 } 6930 6931 /*@ 6932 DMGetNumLabels - Return the number of labels defined by on the `DM` 6933 6934 Not Collective 6935 6936 Input Parameter: 6937 . dm - The `DM` object 6938 6939 Output Parameter: 6940 . numLabels - the number of Labels 6941 6942 Level: intermediate 6943 6944 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6945 @*/ 6946 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 6947 { 6948 DMLabelLink next = dm->labels; 6949 PetscInt n = 0; 6950 6951 PetscFunctionBegin; 6952 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6953 PetscAssertPointer(numLabels, 2); 6954 while (next) { 6955 ++n; 6956 next = next->next; 6957 } 6958 *numLabels = n; 6959 PetscFunctionReturn(PETSC_SUCCESS); 6960 } 6961 6962 /*@C 6963 DMGetLabelName - Return the name of nth label 6964 6965 Not Collective 6966 6967 Input Parameters: 6968 + dm - The `DM` object 6969 - n - the label number 6970 6971 Output Parameter: 6972 . name - the label name 6973 6974 Level: intermediate 6975 6976 Developer Notes: 6977 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 6978 6979 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6980 @*/ 6981 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 6982 { 6983 DMLabelLink next = dm->labels; 6984 PetscInt l = 0; 6985 6986 PetscFunctionBegin; 6987 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6988 PetscAssertPointer(name, 3); 6989 while (next) { 6990 if (l == n) { 6991 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 6992 PetscFunctionReturn(PETSC_SUCCESS); 6993 } 6994 ++l; 6995 next = next->next; 6996 } 6997 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 6998 } 6999 7000 /*@C 7001 DMHasLabel - Determine whether the `DM` has a label of a given name 7002 7003 Not Collective 7004 7005 Input Parameters: 7006 + dm - The `DM` object 7007 - name - The label name 7008 7009 Output Parameter: 7010 . hasLabel - `PETSC_TRUE` if the label is present 7011 7012 Level: intermediate 7013 7014 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7015 @*/ 7016 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7017 { 7018 DMLabelLink next = dm->labels; 7019 const char *lname; 7020 7021 PetscFunctionBegin; 7022 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7023 PetscAssertPointer(name, 2); 7024 PetscAssertPointer(hasLabel, 3); 7025 *hasLabel = PETSC_FALSE; 7026 while (next) { 7027 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7028 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7029 if (*hasLabel) break; 7030 next = next->next; 7031 } 7032 PetscFunctionReturn(PETSC_SUCCESS); 7033 } 7034 7035 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7036 /*@C 7037 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7038 7039 Not Collective 7040 7041 Input Parameters: 7042 + dm - The `DM` object 7043 - name - The label name 7044 7045 Output Parameter: 7046 . label - The `DMLabel`, or `NULL` if the label is absent 7047 7048 Default labels in a `DMPLEX`: 7049 + "depth" - Holds the depth (co-dimension) of each mesh point 7050 . "celltype" - Holds the topological type of each cell 7051 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7052 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7053 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7054 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7055 7056 Level: intermediate 7057 7058 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7059 @*/ 7060 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7061 { 7062 DMLabelLink next = dm->labels; 7063 PetscBool hasLabel; 7064 const char *lname; 7065 7066 PetscFunctionBegin; 7067 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7068 PetscAssertPointer(name, 2); 7069 PetscAssertPointer(label, 3); 7070 *label = NULL; 7071 while (next) { 7072 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7073 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7074 if (hasLabel) { 7075 *label = next->label; 7076 break; 7077 } 7078 next = next->next; 7079 } 7080 PetscFunctionReturn(PETSC_SUCCESS); 7081 } 7082 7083 /*@C 7084 DMGetLabelByNum - Return the nth label on a `DM` 7085 7086 Not Collective 7087 7088 Input Parameters: 7089 + dm - The `DM` object 7090 - n - the label number 7091 7092 Output Parameter: 7093 . label - the label 7094 7095 Level: intermediate 7096 7097 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7098 @*/ 7099 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7100 { 7101 DMLabelLink next = dm->labels; 7102 PetscInt l = 0; 7103 7104 PetscFunctionBegin; 7105 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7106 PetscAssertPointer(label, 3); 7107 while (next) { 7108 if (l == n) { 7109 *label = next->label; 7110 PetscFunctionReturn(PETSC_SUCCESS); 7111 } 7112 ++l; 7113 next = next->next; 7114 } 7115 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7116 } 7117 7118 /*@C 7119 DMAddLabel - Add the label to this `DM` 7120 7121 Not Collective 7122 7123 Input Parameters: 7124 + dm - The `DM` object 7125 - label - The `DMLabel` 7126 7127 Level: developer 7128 7129 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7130 @*/ 7131 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7132 { 7133 DMLabelLink l, *p, tmpLabel; 7134 PetscBool hasLabel; 7135 const char *lname; 7136 PetscBool flg; 7137 7138 PetscFunctionBegin; 7139 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7140 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7141 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7142 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7143 PetscCall(PetscCalloc1(1, &tmpLabel)); 7144 tmpLabel->label = label; 7145 tmpLabel->output = PETSC_TRUE; 7146 for (p = &dm->labels; (l = *p); p = &l->next) { } 7147 *p = tmpLabel; 7148 PetscCall(PetscObjectReference((PetscObject)label)); 7149 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7150 if (flg) dm->depthLabel = label; 7151 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7152 if (flg) dm->celltypeLabel = label; 7153 PetscFunctionReturn(PETSC_SUCCESS); 7154 } 7155 7156 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7157 /*@C 7158 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7159 7160 Not Collective 7161 7162 Input Parameters: 7163 + dm - The `DM` object 7164 - label - The `DMLabel`, having the same name, to substitute 7165 7166 Default labels in a `DMPLEX`: 7167 + "depth" - Holds the depth (co-dimension) of each mesh point 7168 . "celltype" - Holds the topological type of each cell 7169 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7170 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7171 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7172 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7173 7174 Level: intermediate 7175 7176 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7177 @*/ 7178 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7179 { 7180 DMLabelLink next = dm->labels; 7181 PetscBool hasLabel, flg; 7182 const char *name, *lname; 7183 7184 PetscFunctionBegin; 7185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7186 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7187 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7188 while (next) { 7189 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7190 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7191 if (hasLabel) { 7192 PetscCall(PetscObjectReference((PetscObject)label)); 7193 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7194 if (flg) dm->depthLabel = label; 7195 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7196 if (flg) dm->celltypeLabel = label; 7197 PetscCall(DMLabelDestroy(&next->label)); 7198 next->label = label; 7199 break; 7200 } 7201 next = next->next; 7202 } 7203 PetscFunctionReturn(PETSC_SUCCESS); 7204 } 7205 7206 /*@C 7207 DMRemoveLabel - Remove the label given by name from this `DM` 7208 7209 Not Collective 7210 7211 Input Parameters: 7212 + dm - The `DM` object 7213 - name - The label name 7214 7215 Output Parameter: 7216 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7217 caller is responsible for calling `DMLabelDestroy()`. 7218 7219 Level: developer 7220 7221 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7222 @*/ 7223 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7224 { 7225 DMLabelLink link, *pnext; 7226 PetscBool hasLabel; 7227 const char *lname; 7228 7229 PetscFunctionBegin; 7230 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7231 PetscAssertPointer(name, 2); 7232 if (label) { 7233 PetscAssertPointer(label, 3); 7234 *label = NULL; 7235 } 7236 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7237 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7238 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7239 if (hasLabel) { 7240 *pnext = link->next; /* Remove from list */ 7241 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7242 if (hasLabel) dm->depthLabel = NULL; 7243 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7244 if (hasLabel) dm->celltypeLabel = NULL; 7245 if (label) *label = link->label; 7246 else PetscCall(DMLabelDestroy(&link->label)); 7247 PetscCall(PetscFree(link)); 7248 break; 7249 } 7250 } 7251 PetscFunctionReturn(PETSC_SUCCESS); 7252 } 7253 7254 /*@ 7255 DMRemoveLabelBySelf - Remove the label from this `DM` 7256 7257 Not Collective 7258 7259 Input Parameters: 7260 + dm - The `DM` object 7261 . label - The `DMLabel` to be removed from the `DM` 7262 - failNotFound - Should it fail if the label is not found in the `DM`? 7263 7264 Level: developer 7265 7266 Note: 7267 Only exactly the same instance is removed if found, name match is ignored. 7268 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7269 *label nullified. 7270 7271 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7272 @*/ 7273 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7274 { 7275 DMLabelLink link, *pnext; 7276 PetscBool hasLabel = PETSC_FALSE; 7277 7278 PetscFunctionBegin; 7279 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7280 PetscAssertPointer(label, 2); 7281 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7282 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7283 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7284 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7285 if (*label == link->label) { 7286 hasLabel = PETSC_TRUE; 7287 *pnext = link->next; /* Remove from list */ 7288 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7289 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7290 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7291 PetscCall(DMLabelDestroy(&link->label)); 7292 PetscCall(PetscFree(link)); 7293 break; 7294 } 7295 } 7296 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7297 PetscFunctionReturn(PETSC_SUCCESS); 7298 } 7299 7300 /*@C 7301 DMGetLabelOutput - Get the output flag for a given label 7302 7303 Not Collective 7304 7305 Input Parameters: 7306 + dm - The `DM` object 7307 - name - The label name 7308 7309 Output Parameter: 7310 . output - The flag for output 7311 7312 Level: developer 7313 7314 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7315 @*/ 7316 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7317 { 7318 DMLabelLink next = dm->labels; 7319 const char *lname; 7320 7321 PetscFunctionBegin; 7322 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7323 PetscAssertPointer(name, 2); 7324 PetscAssertPointer(output, 3); 7325 while (next) { 7326 PetscBool flg; 7327 7328 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7329 PetscCall(PetscStrcmp(name, lname, &flg)); 7330 if (flg) { 7331 *output = next->output; 7332 PetscFunctionReturn(PETSC_SUCCESS); 7333 } 7334 next = next->next; 7335 } 7336 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7337 } 7338 7339 /*@C 7340 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7341 7342 Not Collective 7343 7344 Input Parameters: 7345 + dm - The `DM` object 7346 . name - The label name 7347 - output - `PETSC_TRUE` to save the label to the viewer 7348 7349 Level: developer 7350 7351 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7352 @*/ 7353 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7354 { 7355 DMLabelLink next = dm->labels; 7356 const char *lname; 7357 7358 PetscFunctionBegin; 7359 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7360 PetscAssertPointer(name, 2); 7361 while (next) { 7362 PetscBool flg; 7363 7364 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7365 PetscCall(PetscStrcmp(name, lname, &flg)); 7366 if (flg) { 7367 next->output = output; 7368 PetscFunctionReturn(PETSC_SUCCESS); 7369 } 7370 next = next->next; 7371 } 7372 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7373 } 7374 7375 /*@ 7376 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7377 7378 Collective 7379 7380 Input Parameters: 7381 + dmA - The `DM` object with initial labels 7382 . dmB - The `DM` object to which labels are copied 7383 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7384 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7385 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7386 7387 Level: intermediate 7388 7389 Note: 7390 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7391 7392 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7393 @*/ 7394 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7395 { 7396 DMLabel label, labelNew, labelOld; 7397 const char *name; 7398 PetscBool flg; 7399 DMLabelLink link; 7400 7401 PetscFunctionBegin; 7402 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7403 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7404 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7405 PetscValidLogicalCollectiveBool(dmA, all, 4); 7406 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7407 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7408 for (link = dmA->labels; link; link = link->next) { 7409 label = link->label; 7410 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7411 if (!all) { 7412 PetscCall(PetscStrcmp(name, "depth", &flg)); 7413 if (flg) continue; 7414 PetscCall(PetscStrcmp(name, "dim", &flg)); 7415 if (flg) continue; 7416 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7417 if (flg) continue; 7418 } 7419 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7420 if (labelOld) { 7421 switch (emode) { 7422 case DM_COPY_LABELS_KEEP: 7423 continue; 7424 case DM_COPY_LABELS_REPLACE: 7425 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7426 break; 7427 case DM_COPY_LABELS_FAIL: 7428 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7429 default: 7430 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7431 } 7432 } 7433 if (mode == PETSC_COPY_VALUES) { 7434 PetscCall(DMLabelDuplicate(label, &labelNew)); 7435 } else { 7436 labelNew = label; 7437 } 7438 PetscCall(DMAddLabel(dmB, labelNew)); 7439 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7440 } 7441 PetscFunctionReturn(PETSC_SUCCESS); 7442 } 7443 7444 /*@C 7445 DMCompareLabels - Compare labels between two `DM` objects 7446 7447 Collective; No Fortran Support 7448 7449 Input Parameters: 7450 + dm0 - First `DM` object 7451 - dm1 - Second `DM` object 7452 7453 Output Parameters: 7454 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 7455 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7456 7457 Level: intermediate 7458 7459 Notes: 7460 The output flag equal will be the same on all processes. 7461 7462 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7463 7464 Make sure to pass equal is `NULL` on all processes or none of them. 7465 7466 The output message is set independently on each rank. 7467 7468 message must be freed with `PetscFree()` 7469 7470 If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner. 7471 7472 Make sure to pass message as `NULL` on all processes or no processes. 7473 7474 Labels are matched by name. If the number of labels and their names are equal, 7475 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7476 7477 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7478 @*/ 7479 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7480 { 7481 PetscInt n, i; 7482 char msg[PETSC_MAX_PATH_LEN] = ""; 7483 PetscBool eq; 7484 MPI_Comm comm; 7485 PetscMPIInt rank; 7486 7487 PetscFunctionBegin; 7488 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7489 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7490 PetscCheckSameComm(dm0, 1, dm1, 2); 7491 if (equal) PetscAssertPointer(equal, 3); 7492 if (message) PetscAssertPointer(message, 4); 7493 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7494 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7495 { 7496 PetscInt n1; 7497 7498 PetscCall(DMGetNumLabels(dm0, &n)); 7499 PetscCall(DMGetNumLabels(dm1, &n1)); 7500 eq = (PetscBool)(n == n1); 7501 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7502 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7503 if (!eq) goto finish; 7504 } 7505 for (i = 0; i < n; i++) { 7506 DMLabel l0, l1; 7507 const char *name; 7508 char *msgInner; 7509 7510 /* Ignore label order */ 7511 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7512 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7513 PetscCall(DMGetLabel(dm1, name, &l1)); 7514 if (!l1) { 7515 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7516 eq = PETSC_FALSE; 7517 break; 7518 } 7519 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7520 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7521 PetscCall(PetscFree(msgInner)); 7522 if (!eq) break; 7523 } 7524 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7525 finish: 7526 /* If message output arg not set, print to stderr */ 7527 if (message) { 7528 *message = NULL; 7529 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7530 } else { 7531 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7532 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7533 } 7534 /* If same output arg not ser and labels are not equal, throw error */ 7535 if (equal) *equal = eq; 7536 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7537 PetscFunctionReturn(PETSC_SUCCESS); 7538 } 7539 7540 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7541 { 7542 PetscFunctionBegin; 7543 PetscAssertPointer(label, 2); 7544 if (!*label) { 7545 PetscCall(DMCreateLabel(dm, name)); 7546 PetscCall(DMGetLabel(dm, name, label)); 7547 } 7548 PetscCall(DMLabelSetValue(*label, point, value)); 7549 PetscFunctionReturn(PETSC_SUCCESS); 7550 } 7551 7552 /* 7553 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7554 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7555 (label, id) pair in the DM. 7556 7557 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7558 each label. 7559 */ 7560 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7561 { 7562 DMUniversalLabel ul; 7563 PetscBool *active; 7564 PetscInt pStart, pEnd, p, Nl, l, m; 7565 7566 PetscFunctionBegin; 7567 PetscCall(PetscMalloc1(1, &ul)); 7568 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7569 PetscCall(DMGetNumLabels(dm, &Nl)); 7570 PetscCall(PetscCalloc1(Nl, &active)); 7571 ul->Nl = 0; 7572 for (l = 0; l < Nl; ++l) { 7573 PetscBool isdepth, iscelltype; 7574 const char *name; 7575 7576 PetscCall(DMGetLabelName(dm, l, &name)); 7577 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7578 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7579 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7580 if (active[l]) ++ul->Nl; 7581 } 7582 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7583 ul->Nv = 0; 7584 for (l = 0, m = 0; l < Nl; ++l) { 7585 DMLabel label; 7586 PetscInt nv; 7587 const char *name; 7588 7589 if (!active[l]) continue; 7590 PetscCall(DMGetLabelName(dm, l, &name)); 7591 PetscCall(DMGetLabelByNum(dm, l, &label)); 7592 PetscCall(DMLabelGetNumValues(label, &nv)); 7593 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7594 ul->indices[m] = l; 7595 ul->Nv += nv; 7596 ul->offsets[m + 1] = nv; 7597 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7598 ++m; 7599 } 7600 for (l = 1; l <= ul->Nl; ++l) { 7601 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7602 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7603 } 7604 for (l = 0; l < ul->Nl; ++l) { 7605 PetscInt b; 7606 7607 ul->masks[l] = 0; 7608 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7609 } 7610 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7611 for (l = 0, m = 0; l < Nl; ++l) { 7612 DMLabel label; 7613 IS valueIS; 7614 const PetscInt *varr; 7615 PetscInt nv, v; 7616 7617 if (!active[l]) continue; 7618 PetscCall(DMGetLabelByNum(dm, l, &label)); 7619 PetscCall(DMLabelGetNumValues(label, &nv)); 7620 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7621 PetscCall(ISGetIndices(valueIS, &varr)); 7622 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7623 PetscCall(ISRestoreIndices(valueIS, &varr)); 7624 PetscCall(ISDestroy(&valueIS)); 7625 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7626 ++m; 7627 } 7628 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7629 for (p = pStart; p < pEnd; ++p) { 7630 PetscInt uval = 0; 7631 PetscBool marked = PETSC_FALSE; 7632 7633 for (l = 0, m = 0; l < Nl; ++l) { 7634 DMLabel label; 7635 PetscInt val, defval, loc, nv; 7636 7637 if (!active[l]) continue; 7638 PetscCall(DMGetLabelByNum(dm, l, &label)); 7639 PetscCall(DMLabelGetValue(label, p, &val)); 7640 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7641 if (val == defval) { 7642 ++m; 7643 continue; 7644 } 7645 nv = ul->offsets[m + 1] - ul->offsets[m]; 7646 marked = PETSC_TRUE; 7647 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7648 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7649 uval += (loc + 1) << ul->bits[m]; 7650 ++m; 7651 } 7652 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7653 } 7654 PetscCall(PetscFree(active)); 7655 *universal = ul; 7656 PetscFunctionReturn(PETSC_SUCCESS); 7657 } 7658 7659 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7660 { 7661 PetscInt l; 7662 7663 PetscFunctionBegin; 7664 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7665 PetscCall(DMLabelDestroy(&(*universal)->label)); 7666 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7667 PetscCall(PetscFree((*universal)->values)); 7668 PetscCall(PetscFree(*universal)); 7669 *universal = NULL; 7670 PetscFunctionReturn(PETSC_SUCCESS); 7671 } 7672 7673 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7674 { 7675 PetscFunctionBegin; 7676 PetscAssertPointer(ulabel, 2); 7677 *ulabel = ul->label; 7678 PetscFunctionReturn(PETSC_SUCCESS); 7679 } 7680 7681 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7682 { 7683 PetscInt Nl = ul->Nl, l; 7684 7685 PetscFunctionBegin; 7686 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7687 for (l = 0; l < Nl; ++l) { 7688 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7689 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7690 } 7691 if (preserveOrder) { 7692 for (l = 0; l < ul->Nl; ++l) { 7693 const char *name; 7694 PetscBool match; 7695 7696 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7697 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7698 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]); 7699 } 7700 } 7701 PetscFunctionReturn(PETSC_SUCCESS); 7702 } 7703 7704 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7705 { 7706 PetscInt l; 7707 7708 PetscFunctionBegin; 7709 for (l = 0; l < ul->Nl; ++l) { 7710 DMLabel label; 7711 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7712 7713 if (lval) { 7714 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7715 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7716 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7717 } 7718 } 7719 PetscFunctionReturn(PETSC_SUCCESS); 7720 } 7721 7722 /*@ 7723 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7724 7725 Not Collective 7726 7727 Input Parameter: 7728 . dm - The `DM` object 7729 7730 Output Parameter: 7731 . cdm - The coarse `DM` 7732 7733 Level: intermediate 7734 7735 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7736 @*/ 7737 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7738 { 7739 PetscFunctionBegin; 7740 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7741 PetscAssertPointer(cdm, 2); 7742 *cdm = dm->coarseMesh; 7743 PetscFunctionReturn(PETSC_SUCCESS); 7744 } 7745 7746 /*@ 7747 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7748 7749 Input Parameters: 7750 + dm - The `DM` object 7751 - cdm - The coarse `DM` 7752 7753 Level: intermediate 7754 7755 Note: 7756 Normally this is set automatically by `DMRefine()` 7757 7758 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7759 @*/ 7760 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7761 { 7762 PetscFunctionBegin; 7763 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7764 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7765 if (dm == cdm) cdm = NULL; 7766 PetscCall(PetscObjectReference((PetscObject)cdm)); 7767 PetscCall(DMDestroy(&dm->coarseMesh)); 7768 dm->coarseMesh = cdm; 7769 PetscFunctionReturn(PETSC_SUCCESS); 7770 } 7771 7772 /*@ 7773 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7774 7775 Input Parameter: 7776 . dm - The `DM` object 7777 7778 Output Parameter: 7779 . fdm - The fine `DM` 7780 7781 Level: intermediate 7782 7783 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7784 @*/ 7785 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7786 { 7787 PetscFunctionBegin; 7788 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7789 PetscAssertPointer(fdm, 2); 7790 *fdm = dm->fineMesh; 7791 PetscFunctionReturn(PETSC_SUCCESS); 7792 } 7793 7794 /*@ 7795 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7796 7797 Input Parameters: 7798 + dm - The `DM` object 7799 - fdm - The fine `DM` 7800 7801 Level: developer 7802 7803 Note: 7804 Normally this is set automatically by `DMCoarsen()` 7805 7806 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7807 @*/ 7808 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7809 { 7810 PetscFunctionBegin; 7811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7812 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7813 if (dm == fdm) fdm = NULL; 7814 PetscCall(PetscObjectReference((PetscObject)fdm)); 7815 PetscCall(DMDestroy(&dm->fineMesh)); 7816 dm->fineMesh = fdm; 7817 PetscFunctionReturn(PETSC_SUCCESS); 7818 } 7819 7820 /*@C 7821 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7822 7823 Collective 7824 7825 Input Parameters: 7826 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7827 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7828 . name - The BC name 7829 . label - The label defining constrained points 7830 . Nv - The number of `DMLabel` values for constrained points 7831 . values - An array of values for constrained points 7832 . field - The field to constrain 7833 . Nc - The number of constrained field components (0 will constrain all fields) 7834 . comps - An array of constrained component numbers 7835 . bcFunc - A pointwise function giving boundary values 7836 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7837 - ctx - An optional user context for bcFunc 7838 7839 Output Parameter: 7840 . bd - (Optional) Boundary number 7841 7842 Options Database Keys: 7843 + -bc_<boundary name> <num> - Overrides the boundary ids 7844 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7845 7846 Level: intermediate 7847 7848 Notes: 7849 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 7850 7851 $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7852 7853 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 7854 7855 .vb 7856 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7857 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7858 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7859 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7860 .ve 7861 + dim - the spatial dimension 7862 . Nf - the number of fields 7863 . uOff - the offset into u[] and u_t[] for each field 7864 . uOff_x - the offset into u_x[] for each field 7865 . u - each field evaluated at the current point 7866 . u_t - the time derivative of each field evaluated at the current point 7867 . u_x - the gradient of each field evaluated at the current point 7868 . aOff - the offset into a[] and a_t[] for each auxiliary field 7869 . aOff_x - the offset into a_x[] for each auxiliary field 7870 . a - each auxiliary field evaluated at the current point 7871 . a_t - the time derivative of each auxiliary field evaluated at the current point 7872 . a_x - the gradient of auxiliary each field evaluated at the current point 7873 . t - current time 7874 . x - coordinates of the current point 7875 . numConstants - number of constant parameters 7876 . constants - constant parameters 7877 - bcval - output values at the current point 7878 7879 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 7880 @*/ 7881 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) 7882 { 7883 PetscDS ds; 7884 7885 PetscFunctionBegin; 7886 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7887 PetscValidLogicalCollectiveEnum(dm, type, 2); 7888 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 7889 PetscValidLogicalCollectiveInt(dm, Nv, 5); 7890 PetscValidLogicalCollectiveInt(dm, field, 7); 7891 PetscValidLogicalCollectiveInt(dm, Nc, 8); 7892 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 7893 PetscCall(DMGetDS(dm, &ds)); 7894 /* Complete label */ 7895 if (label) { 7896 PetscObject obj; 7897 PetscClassId id; 7898 7899 PetscCall(DMGetField(dm, field, NULL, &obj)); 7900 PetscCall(PetscObjectGetClassId(obj, &id)); 7901 if (id == PETSCFE_CLASSID) { 7902 DM plex; 7903 7904 PetscCall(DMConvert(dm, DMPLEX, &plex)); 7905 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 7906 PetscCall(DMDestroy(&plex)); 7907 } 7908 } 7909 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 7910 PetscFunctionReturn(PETSC_SUCCESS); 7911 } 7912 7913 /* TODO Remove this since now the structures are the same */ 7914 static PetscErrorCode DMPopulateBoundary(DM dm) 7915 { 7916 PetscDS ds; 7917 DMBoundary *lastnext; 7918 DSBoundary dsbound; 7919 7920 PetscFunctionBegin; 7921 PetscCall(DMGetDS(dm, &ds)); 7922 dsbound = ds->boundary; 7923 if (dm->boundary) { 7924 DMBoundary next = dm->boundary; 7925 7926 /* quick check to see if the PetscDS has changed */ 7927 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 7928 /* the PetscDS has changed: tear down and rebuild */ 7929 while (next) { 7930 DMBoundary b = next; 7931 7932 next = b->next; 7933 PetscCall(PetscFree(b)); 7934 } 7935 dm->boundary = NULL; 7936 } 7937 7938 lastnext = &(dm->boundary); 7939 while (dsbound) { 7940 DMBoundary dmbound; 7941 7942 PetscCall(PetscNew(&dmbound)); 7943 dmbound->dsboundary = dsbound; 7944 dmbound->label = dsbound->label; 7945 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 7946 *lastnext = dmbound; 7947 lastnext = &(dmbound->next); 7948 dsbound = dsbound->next; 7949 } 7950 PetscFunctionReturn(PETSC_SUCCESS); 7951 } 7952 7953 /* TODO: missing manual page */ 7954 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 7955 { 7956 DMBoundary b; 7957 7958 PetscFunctionBegin; 7959 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7960 PetscAssertPointer(isBd, 3); 7961 *isBd = PETSC_FALSE; 7962 PetscCall(DMPopulateBoundary(dm)); 7963 b = dm->boundary; 7964 while (b && !(*isBd)) { 7965 DMLabel label = b->label; 7966 DSBoundary dsb = b->dsboundary; 7967 PetscInt i; 7968 7969 if (label) { 7970 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 7971 } 7972 b = b->next; 7973 } 7974 PetscFunctionReturn(PETSC_SUCCESS); 7975 } 7976 7977 /*@C 7978 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 7979 7980 Collective 7981 7982 Input Parameters: 7983 + dm - The `DM` 7984 . time - The time 7985 . funcs - The coordinate functions to evaluate, one per field 7986 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 7987 - mode - The insertion mode for values 7988 7989 Output Parameter: 7990 . X - vector 7991 7992 Calling sequence of `funcs`: 7993 + dim - The spatial dimension 7994 . time - The time at which to sample 7995 . x - The coordinates 7996 . Nc - The number of components 7997 . u - The output field values 7998 - ctx - optional user-defined function context 7999 8000 Level: developer 8001 8002 Developer Notes: 8003 This API is specific to only particular usage of `DM` 8004 8005 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8006 8007 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8008 @*/ 8009 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) 8010 { 8011 Vec localX; 8012 8013 PetscFunctionBegin; 8014 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8015 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8016 PetscCall(DMGetLocalVector(dm, &localX)); 8017 PetscCall(VecSet(localX, 0.)); 8018 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8019 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8020 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8021 PetscCall(DMRestoreLocalVector(dm, &localX)); 8022 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8023 PetscFunctionReturn(PETSC_SUCCESS); 8024 } 8025 8026 /*@C 8027 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8028 8029 Not Collective 8030 8031 Input Parameters: 8032 + dm - The `DM` 8033 . time - The time 8034 . funcs - The coordinate functions to evaluate, one per field 8035 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8036 - mode - The insertion mode for values 8037 8038 Output Parameter: 8039 . localX - vector 8040 8041 Calling sequence of `funcs`: 8042 + dim - The spatial dimension 8043 . time - The current timestep 8044 . x - The coordinates 8045 . Nc - The number of components 8046 . u - The output field values 8047 - ctx - optional user-defined function context 8048 8049 Level: developer 8050 8051 Developer Notes: 8052 This API is specific to only particular usage of `DM` 8053 8054 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8055 8056 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8057 @*/ 8058 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) 8059 { 8060 PetscFunctionBegin; 8061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8062 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8063 PetscCall((dm->ops->projectfunctionlocal)(dm, time, funcs, ctxs, mode, localX)); 8064 PetscFunctionReturn(PETSC_SUCCESS); 8065 } 8066 8067 /*@C 8068 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. 8069 8070 Collective 8071 8072 Input Parameters: 8073 + dm - The `DM` 8074 . time - The time 8075 . numIds - The number of ids 8076 . ids - The ids 8077 . Nc - The number of components 8078 . comps - The components 8079 . label - The `DMLabel` selecting the portion of the mesh for projection 8080 . funcs - The coordinate functions to evaluate, one per field 8081 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8082 - mode - The insertion mode for values 8083 8084 Output Parameter: 8085 . X - vector 8086 8087 Calling sequence of `funcs`: 8088 + dim - The spatial dimension 8089 . time - The current timestep 8090 . x - The coordinates 8091 . Nc - The number of components 8092 . u - The output field values 8093 - ctx - optional user-defined function context 8094 8095 Level: developer 8096 8097 Developer Notes: 8098 This API is specific to only particular usage of `DM` 8099 8100 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8101 8102 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8103 @*/ 8104 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) 8105 { 8106 Vec localX; 8107 8108 PetscFunctionBegin; 8109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8110 PetscCall(DMGetLocalVector(dm, &localX)); 8111 PetscCall(VecSet(localX, 0.)); 8112 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8113 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8114 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8115 PetscCall(DMRestoreLocalVector(dm, &localX)); 8116 PetscFunctionReturn(PETSC_SUCCESS); 8117 } 8118 8119 /*@C 8120 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. 8121 8122 Not Collective 8123 8124 Input Parameters: 8125 + dm - The `DM` 8126 . time - The time 8127 . label - The `DMLabel` selecting the portion of the mesh for projection 8128 . numIds - The number of ids 8129 . ids - The ids 8130 . Nc - The number of components 8131 . comps - The components 8132 . funcs - The coordinate functions to evaluate, one per field 8133 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8134 - mode - The insertion mode for values 8135 8136 Output Parameter: 8137 . localX - vector 8138 8139 Calling sequence of `funcs`: 8140 + dim - The spatial dimension 8141 . time - The current time 8142 . x - The coordinates 8143 . Nc - The number of components 8144 . u - The output field values 8145 - ctx - optional user-defined function context 8146 8147 Level: developer 8148 8149 Developer Notes: 8150 This API is specific to only particular usage of `DM` 8151 8152 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8153 8154 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8155 @*/ 8156 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) 8157 { 8158 PetscFunctionBegin; 8159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8160 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8161 PetscCall((dm->ops->projectfunctionlabellocal)(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8162 PetscFunctionReturn(PETSC_SUCCESS); 8163 } 8164 8165 /*@C 8166 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. 8167 8168 Not Collective 8169 8170 Input Parameters: 8171 + dm - The `DM` 8172 . time - The time 8173 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8174 . funcs - The functions to evaluate, one per field 8175 - mode - The insertion mode for values 8176 8177 Output Parameter: 8178 . localX - The output vector 8179 8180 Calling sequence of `funcs`: 8181 + dim - The spatial dimension 8182 . Nf - The number of input fields 8183 . NfAux - The number of input auxiliary fields 8184 . uOff - The offset of each field in u[] 8185 . uOff_x - The offset of each field in u_x[] 8186 . u - The field values at this point in space 8187 . u_t - The field time derivative at this point in space (or NULL) 8188 . u_x - The field derivatives at this point in space 8189 . aOff - The offset of each auxiliary field in u[] 8190 . aOff_x - The offset of each auxiliary field in u_x[] 8191 . a - The auxiliary field values at this point in space 8192 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8193 . a_x - The auxiliary field derivatives at this point in space 8194 . t - The current time 8195 . x - The coordinates of this point 8196 . numConstants - The number of constants 8197 . constants - The value of each constant 8198 - f - The value of the function at this point in space 8199 8200 Note: 8201 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. 8202 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 8203 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8204 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8205 8206 Level: intermediate 8207 8208 Developer Notes: 8209 This API is specific to only particular usage of `DM` 8210 8211 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8212 8213 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8214 `DMProjectFunction()`, `DMComputeL2Diff()` 8215 @*/ 8216 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) 8217 { 8218 PetscFunctionBegin; 8219 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8220 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8221 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8222 PetscCall((dm->ops->projectfieldlocal)(dm, time, localU, funcs, mode, localX)); 8223 PetscFunctionReturn(PETSC_SUCCESS); 8224 } 8225 8226 /*@C 8227 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. 8228 8229 Not Collective 8230 8231 Input Parameters: 8232 + dm - The `DM` 8233 . time - The time 8234 . label - The `DMLabel` marking the portion of the domain to output 8235 . numIds - The number of label ids to use 8236 . ids - The label ids to use for marking 8237 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8238 . comps - The components to set in the output, or `NULL` for all components 8239 . localU - The input field vector 8240 . funcs - The functions to evaluate, one per field 8241 - mode - The insertion mode for values 8242 8243 Output Parameter: 8244 . localX - The output vector 8245 8246 Calling sequence of `funcs`: 8247 + dim - The spatial dimension 8248 . Nf - The number of input fields 8249 . NfAux - The number of input auxiliary fields 8250 . uOff - The offset of each field in u[] 8251 . uOff_x - The offset of each field in u_x[] 8252 . u - The field values at this point in space 8253 . u_t - The field time derivative at this point in space (or NULL) 8254 . u_x - The field derivatives at this point in space 8255 . aOff - The offset of each auxiliary field in u[] 8256 . aOff_x - The offset of each auxiliary field in u_x[] 8257 . a - The auxiliary field values at this point in space 8258 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8259 . a_x - The auxiliary field derivatives at this point in space 8260 . t - The current time 8261 . x - The coordinates of this point 8262 . numConstants - The number of constants 8263 . constants - The value of each constant 8264 - f - The value of the function at this point in space 8265 8266 Note: 8267 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. 8268 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 8269 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8270 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8271 8272 Level: intermediate 8273 8274 Developer Notes: 8275 This API is specific to only particular usage of `DM` 8276 8277 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8278 8279 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8280 @*/ 8281 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) 8282 { 8283 PetscFunctionBegin; 8284 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8285 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8286 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8287 PetscCall((dm->ops->projectfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8288 PetscFunctionReturn(PETSC_SUCCESS); 8289 } 8290 8291 /*@C 8292 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. 8293 8294 Not Collective 8295 8296 Input Parameters: 8297 + dm - The `DM` 8298 . time - The time 8299 . label - The `DMLabel` marking the portion of the domain to output 8300 . numIds - The number of label ids to use 8301 . ids - The label ids to use for marking 8302 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8303 . comps - The components to set in the output, or `NULL` for all components 8304 . U - The input field vector 8305 . funcs - The functions to evaluate, one per field 8306 - mode - The insertion mode for values 8307 8308 Output Parameter: 8309 . X - The output vector 8310 8311 Calling sequence of `funcs`: 8312 + dim - The spatial dimension 8313 . Nf - The number of input fields 8314 . NfAux - The number of input auxiliary fields 8315 . uOff - The offset of each field in u[] 8316 . uOff_x - The offset of each field in u_x[] 8317 . u - The field values at this point in space 8318 . u_t - The field time derivative at this point in space (or NULL) 8319 . u_x - The field derivatives at this point in space 8320 . aOff - The offset of each auxiliary field in u[] 8321 . aOff_x - The offset of each auxiliary field in u_x[] 8322 . a - The auxiliary field values at this point in space 8323 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8324 . a_x - The auxiliary field derivatives at this point in space 8325 . t - The current time 8326 . x - The coordinates of this point 8327 . numConstants - The number of constants 8328 . constants - The value of each constant 8329 - f - The value of the function at this point in space 8330 8331 Note: 8332 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. 8333 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 8334 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8335 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8336 8337 Level: intermediate 8338 8339 Developer Notes: 8340 This API is specific to only particular usage of `DM` 8341 8342 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8343 8344 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8345 @*/ 8346 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) 8347 { 8348 DM dmIn; 8349 Vec localU, localX; 8350 8351 PetscFunctionBegin; 8352 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8353 PetscCall(VecGetDM(U, &dmIn)); 8354 PetscCall(DMGetLocalVector(dmIn, &localU)); 8355 PetscCall(DMGetLocalVector(dm, &localX)); 8356 PetscCall(VecSet(localX, 0.)); 8357 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8358 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8359 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8360 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8361 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8362 PetscCall(DMRestoreLocalVector(dm, &localX)); 8363 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8364 PetscFunctionReturn(PETSC_SUCCESS); 8365 } 8366 8367 /*@C 8368 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. 8369 8370 Not Collective 8371 8372 Input Parameters: 8373 + dm - The `DM` 8374 . time - The time 8375 . label - The `DMLabel` marking the portion of the domain boundary to output 8376 . numIds - The number of label ids to use 8377 . ids - The label ids to use for marking 8378 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8379 . comps - The components to set in the output, or `NULL` for all components 8380 . localU - The input field vector 8381 . funcs - The functions to evaluate, one per field 8382 - mode - The insertion mode for values 8383 8384 Output Parameter: 8385 . localX - The output vector 8386 8387 Calling sequence of `funcs`: 8388 + dim - The spatial dimension 8389 . Nf - The number of input fields 8390 . NfAux - The number of input auxiliary fields 8391 . uOff - The offset of each field in u[] 8392 . uOff_x - The offset of each field in u_x[] 8393 . u - The field values at this point in space 8394 . u_t - The field time derivative at this point in space (or NULL) 8395 . u_x - The field derivatives at this point in space 8396 . aOff - The offset of each auxiliary field in u[] 8397 . aOff_x - The offset of each auxiliary field in u_x[] 8398 . a - The auxiliary field values at this point in space 8399 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8400 . a_x - The auxiliary field derivatives at this point in space 8401 . t - The current time 8402 . x - The coordinates of this point 8403 . n - The face normal 8404 . numConstants - The number of constants 8405 . constants - The value of each constant 8406 - f - The value of the function at this point in space 8407 8408 Note: 8409 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. 8410 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 8411 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8412 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8413 8414 Level: intermediate 8415 8416 Developer Notes: 8417 This API is specific to only particular usage of `DM` 8418 8419 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8420 8421 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8422 @*/ 8423 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) 8424 { 8425 PetscFunctionBegin; 8426 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8427 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8428 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8429 PetscCall((dm->ops->projectbdfieldlabellocal)(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8430 PetscFunctionReturn(PETSC_SUCCESS); 8431 } 8432 8433 /*@C 8434 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8435 8436 Collective 8437 8438 Input Parameters: 8439 + dm - The `DM` 8440 . time - The time 8441 . funcs - The functions to evaluate for each field component 8442 . ctxs - Optional array of contexts to pass to each function, or NULL. 8443 - X - The coefficient vector u_h, a global vector 8444 8445 Output Parameter: 8446 . diff - The diff ||u - u_h||_2 8447 8448 Level: developer 8449 8450 Developer Notes: 8451 This API is specific to only particular usage of `DM` 8452 8453 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8454 8455 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8456 @*/ 8457 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8458 { 8459 PetscFunctionBegin; 8460 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8461 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8462 PetscCall((dm->ops->computel2diff)(dm, time, funcs, ctxs, X, diff)); 8463 PetscFunctionReturn(PETSC_SUCCESS); 8464 } 8465 8466 /*@C 8467 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8468 8469 Collective 8470 8471 Input Parameters: 8472 + dm - The `DM` 8473 . time - The time 8474 . funcs - The gradient functions to evaluate for each field component 8475 . ctxs - Optional array of contexts to pass to each function, or NULL. 8476 . X - The coefficient vector u_h, a global vector 8477 - n - The vector to project along 8478 8479 Output Parameter: 8480 . diff - The diff ||(grad u - grad u_h) . n||_2 8481 8482 Level: developer 8483 8484 Developer Notes: 8485 This API is specific to only particular usage of `DM` 8486 8487 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8488 8489 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8490 @*/ 8491 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) 8492 { 8493 PetscFunctionBegin; 8494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8495 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8496 PetscCall((dm->ops->computel2gradientdiff)(dm, time, funcs, ctxs, X, n, diff)); 8497 PetscFunctionReturn(PETSC_SUCCESS); 8498 } 8499 8500 /*@C 8501 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8502 8503 Collective 8504 8505 Input Parameters: 8506 + dm - The `DM` 8507 . time - The time 8508 . funcs - The functions to evaluate for each field component 8509 . ctxs - Optional array of contexts to pass to each function, or NULL. 8510 - X - The coefficient vector u_h, a global vector 8511 8512 Output Parameter: 8513 . diff - The array of differences, ||u^f - u^f_h||_2 8514 8515 Level: developer 8516 8517 Developer Notes: 8518 This API is specific to only particular usage of `DM` 8519 8520 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8521 8522 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8523 @*/ 8524 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8525 { 8526 PetscFunctionBegin; 8527 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8528 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8529 PetscCall((dm->ops->computel2fielddiff)(dm, time, funcs, ctxs, X, diff)); 8530 PetscFunctionReturn(PETSC_SUCCESS); 8531 } 8532 8533 /*@C 8534 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8535 8536 Not Collective 8537 8538 Input Parameter: 8539 . dm - The `DM` 8540 8541 Output Parameters: 8542 + nranks - the number of neighbours 8543 - ranks - the neighbors ranks 8544 8545 Level: beginner 8546 8547 Note: 8548 Do not free the array, it is freed when the `DM` is destroyed. 8549 8550 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8551 @*/ 8552 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8553 { 8554 PetscFunctionBegin; 8555 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8556 PetscCall((dm->ops->getneighbors)(dm, nranks, ranks)); 8557 PetscFunctionReturn(PETSC_SUCCESS); 8558 } 8559 8560 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8561 8562 /* 8563 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8564 This must be a different function because it requires DM which is not defined in the Mat library 8565 */ 8566 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8567 { 8568 PetscFunctionBegin; 8569 if (coloring->ctype == IS_COLORING_LOCAL) { 8570 Vec x1local; 8571 DM dm; 8572 PetscCall(MatGetDM(J, &dm)); 8573 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8574 PetscCall(DMGetLocalVector(dm, &x1local)); 8575 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8576 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8577 x1 = x1local; 8578 } 8579 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8580 if (coloring->ctype == IS_COLORING_LOCAL) { 8581 DM dm; 8582 PetscCall(MatGetDM(J, &dm)); 8583 PetscCall(DMRestoreLocalVector(dm, &x1)); 8584 } 8585 PetscFunctionReturn(PETSC_SUCCESS); 8586 } 8587 8588 /*@ 8589 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8590 8591 Input Parameters: 8592 + coloring - The matrix to get the `DM` from 8593 - fdcoloring - the `MatFDColoring` object 8594 8595 Level: advanced 8596 8597 Developer Notes: 8598 this routine exists because the PETSc `Mat` library does not know about the `DM` objects 8599 8600 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8601 @*/ 8602 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8603 { 8604 PetscFunctionBegin; 8605 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8606 PetscFunctionReturn(PETSC_SUCCESS); 8607 } 8608 8609 /*@ 8610 DMGetCompatibility - determine if two `DM`s are compatible 8611 8612 Collective 8613 8614 Input Parameters: 8615 + dm1 - the first `DM` 8616 - dm2 - the second `DM` 8617 8618 Output Parameters: 8619 + compatible - whether or not the two `DM`s are compatible 8620 - set - whether or not the compatible value was actually determined and set 8621 8622 Level: advanced 8623 8624 Notes: 8625 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8626 of the same topology. This implies that the section (field data) on one 8627 "makes sense" with respect to the topology and parallel decomposition of the other. 8628 Loosely speaking, compatible `DM`s represent the same domain and parallel 8629 decomposition, but hold different data. 8630 8631 Typically, one would confirm compatibility if intending to simultaneously iterate 8632 over a pair of vectors obtained from different `DM`s. 8633 8634 For example, two `DMDA` objects are compatible if they have the same local 8635 and global sizes and the same stencil width. They can have different numbers 8636 of degrees of freedom per node. Thus, one could use the node numbering from 8637 either `DM` in bounds for a loop over vectors derived from either `DM`. 8638 8639 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8640 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8641 .vb 8642 ... 8643 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8644 if (set && compatible) { 8645 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8646 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8647 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8648 for (j=y; j<y+n; ++j) { 8649 for (i=x; i<x+m, ++i) { 8650 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8651 } 8652 } 8653 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8654 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8655 } else { 8656 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8657 } 8658 ... 8659 .ve 8660 8661 Checking compatibility might be expensive for a given implementation of `DM`, 8662 or might be impossible to unambiguously confirm or deny. For this reason, 8663 this function may decline to determine compatibility, and hence users should 8664 always check the "set" output parameter. 8665 8666 A `DM` is always compatible with itself. 8667 8668 In the current implementation, `DM`s which live on "unequal" communicators 8669 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8670 incompatible. 8671 8672 This function is labeled "Collective," as information about all subdomains 8673 is required on each rank. However, in `DM` implementations which store all this 8674 information locally, this function may be merely "Logically Collective". 8675 8676 Developer Notes: 8677 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8678 iff B is compatible with A. Thus, this function checks the implementations 8679 of both dm and dmc (if they are of different types), attempting to determine 8680 compatibility. It is left to `DM` implementers to ensure that symmetry is 8681 preserved. The simplest way to do this is, when implementing type-specific 8682 logic for this function, is to check for existing logic in the implementation 8683 of other `DM` types and let *set = PETSC_FALSE if found. 8684 8685 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8686 @*/ 8687 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8688 { 8689 PetscMPIInt compareResult; 8690 DMType type, type2; 8691 PetscBool sameType; 8692 8693 PetscFunctionBegin; 8694 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8695 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8696 8697 /* Declare a DM compatible with itself */ 8698 if (dm1 == dm2) { 8699 *set = PETSC_TRUE; 8700 *compatible = PETSC_TRUE; 8701 PetscFunctionReturn(PETSC_SUCCESS); 8702 } 8703 8704 /* Declare a DM incompatible with a DM that lives on an "unequal" 8705 communicator. Note that this does not preclude compatibility with 8706 DMs living on "congruent" or "similar" communicators, but this must be 8707 determined by the implementation-specific logic */ 8708 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8709 if (compareResult == MPI_UNEQUAL) { 8710 *set = PETSC_TRUE; 8711 *compatible = PETSC_FALSE; 8712 PetscFunctionReturn(PETSC_SUCCESS); 8713 } 8714 8715 /* Pass to the implementation-specific routine, if one exists. */ 8716 if (dm1->ops->getcompatibility) { 8717 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8718 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8719 } 8720 8721 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8722 with an implementation of this function from dm2 */ 8723 PetscCall(DMGetType(dm1, &type)); 8724 PetscCall(DMGetType(dm2, &type2)); 8725 PetscCall(PetscStrcmp(type, type2, &sameType)); 8726 if (!sameType && dm2->ops->getcompatibility) { 8727 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8728 } else { 8729 *set = PETSC_FALSE; 8730 } 8731 PetscFunctionReturn(PETSC_SUCCESS); 8732 } 8733 8734 /*@C 8735 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8736 8737 Logically Collective 8738 8739 Input Parameters: 8740 + dm - the `DM` 8741 . f - the monitor function 8742 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8743 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`) 8744 8745 Options Database Key: 8746 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8747 does not cancel those set via the options database. 8748 8749 Level: intermediate 8750 8751 Note: 8752 Several different monitoring routines may be set by calling 8753 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8754 order in which they were set. 8755 8756 Fortran Notes: 8757 Only a single monitor function can be set for each `DM` object 8758 8759 Developer Notes: 8760 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8761 8762 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8763 @*/ 8764 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8765 { 8766 PetscInt m; 8767 8768 PetscFunctionBegin; 8769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8770 for (m = 0; m < dm->numbermonitors; ++m) { 8771 PetscBool identical; 8772 8773 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8774 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 8775 } 8776 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8777 dm->monitor[dm->numbermonitors] = f; 8778 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8779 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8780 PetscFunctionReturn(PETSC_SUCCESS); 8781 } 8782 8783 /*@ 8784 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8785 8786 Logically Collective 8787 8788 Input Parameter: 8789 . dm - the DM 8790 8791 Options Database Key: 8792 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8793 into a code by calls to `DMonitorSet()`, but does not cancel those 8794 set via the options database 8795 8796 Level: intermediate 8797 8798 Note: 8799 There is no way to clear one specific monitor from a `DM` object. 8800 8801 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8802 @*/ 8803 PetscErrorCode DMMonitorCancel(DM dm) 8804 { 8805 PetscInt m; 8806 8807 PetscFunctionBegin; 8808 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8809 for (m = 0; m < dm->numbermonitors; ++m) { 8810 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8811 } 8812 dm->numbermonitors = 0; 8813 PetscFunctionReturn(PETSC_SUCCESS); 8814 } 8815 8816 /*@C 8817 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8818 8819 Collective 8820 8821 Input Parameters: 8822 + dm - `DM` object you wish to monitor 8823 . name - the monitor type one is seeking 8824 . help - message indicating what monitoring is done 8825 . manual - manual page for the monitor 8826 . monitor - the monitor function 8827 - 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 8828 8829 Output Parameter: 8830 . flg - Flag set if the monitor was created 8831 8832 Level: developer 8833 8834 .seealso: [](ch_dmbase), `DM`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8835 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8836 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 8837 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8838 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8839 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8840 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8841 @*/ 8842 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8843 { 8844 PetscViewer viewer; 8845 PetscViewerFormat format; 8846 8847 PetscFunctionBegin; 8848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8849 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8850 if (*flg) { 8851 PetscViewerAndFormat *vf; 8852 8853 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8854 PetscCall(PetscObjectDereference((PetscObject)viewer)); 8855 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8856 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8857 } 8858 PetscFunctionReturn(PETSC_SUCCESS); 8859 } 8860 8861 /*@ 8862 DMMonitor - runs the user provided monitor routines, if they exist 8863 8864 Collective 8865 8866 Input Parameter: 8867 . dm - The `DM` 8868 8869 Level: developer 8870 8871 Developer Notes: 8872 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 8873 related to the discretization process seems rather specialized since some `DM` have no 8874 concept of discretization. 8875 8876 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 8877 @*/ 8878 PetscErrorCode DMMonitor(DM dm) 8879 { 8880 PetscInt m; 8881 8882 PetscFunctionBegin; 8883 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 8884 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8885 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 8886 PetscFunctionReturn(PETSC_SUCCESS); 8887 } 8888 8889 /*@ 8890 DMComputeError - Computes the error assuming the user has provided the exact solution functions 8891 8892 Collective 8893 8894 Input Parameters: 8895 + dm - The `DM` 8896 - sol - The solution vector 8897 8898 Input/Output Parameter: 8899 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 8900 contains the error in each field 8901 8902 Output Parameter: 8903 . errorVec - A vector to hold the cellwise error (may be `NULL`) 8904 8905 Level: developer 8906 8907 Note: 8908 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 8909 8910 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 8911 @*/ 8912 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 8913 { 8914 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 8915 void **ctxs; 8916 PetscReal time; 8917 PetscInt Nf, f, Nds, s; 8918 8919 PetscFunctionBegin; 8920 PetscCall(DMGetNumFields(dm, &Nf)); 8921 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 8922 PetscCall(DMGetNumDS(dm, &Nds)); 8923 for (s = 0; s < Nds; ++s) { 8924 PetscDS ds; 8925 DMLabel label; 8926 IS fieldIS; 8927 const PetscInt *fields; 8928 PetscInt dsNf; 8929 8930 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 8931 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 8932 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 8933 for (f = 0; f < dsNf; ++f) { 8934 const PetscInt field = fields[f]; 8935 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 8936 } 8937 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 8938 } 8939 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); 8940 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 8941 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 8942 if (errorVec) { 8943 DM edm; 8944 DMPolytopeType ct; 8945 PetscBool simplex; 8946 PetscInt dim, cStart, Nf; 8947 8948 PetscCall(DMClone(dm, &edm)); 8949 PetscCall(DMGetDimension(edm, &dim)); 8950 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 8951 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8952 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 8953 PetscCall(DMGetNumFields(dm, &Nf)); 8954 for (f = 0; f < Nf; ++f) { 8955 PetscFE fe, efe; 8956 PetscQuadrature q; 8957 const char *name; 8958 8959 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 8960 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 8961 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 8962 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 8963 PetscCall(PetscFEGetQuadrature(fe, &q)); 8964 PetscCall(PetscFESetQuadrature(efe, q)); 8965 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 8966 PetscCall(PetscFEDestroy(&efe)); 8967 } 8968 PetscCall(DMCreateDS(edm)); 8969 8970 PetscCall(DMCreateGlobalVector(edm, errorVec)); 8971 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 8972 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 8973 PetscCall(DMDestroy(&edm)); 8974 } 8975 PetscCall(PetscFree2(exactSol, ctxs)); 8976 PetscFunctionReturn(PETSC_SUCCESS); 8977 } 8978 8979 /*@ 8980 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 8981 8982 Not Collective 8983 8984 Input Parameter: 8985 . dm - The `DM` 8986 8987 Output Parameter: 8988 . numAux - The number of auxiliary data vectors 8989 8990 Level: advanced 8991 8992 .seealso: [](ch_dmbase), `DM`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 8993 @*/ 8994 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 8995 { 8996 PetscFunctionBegin; 8997 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8998 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 8999 PetscFunctionReturn(PETSC_SUCCESS); 9000 } 9001 9002 /*@ 9003 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9004 9005 Not Collective 9006 9007 Input Parameters: 9008 + dm - The `DM` 9009 . label - The `DMLabel` 9010 . value - The label value indicating the region 9011 - part - The equation part, or 0 if unused 9012 9013 Output Parameter: 9014 . aux - The `Vec` holding auxiliary field data 9015 9016 Level: advanced 9017 9018 Note: 9019 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9020 9021 .seealso: [](ch_dmbase), `DM`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9022 @*/ 9023 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9024 { 9025 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9026 PetscBool has; 9027 9028 PetscFunctionBegin; 9029 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9030 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9031 key.label = label; 9032 key.value = value; 9033 key.part = part; 9034 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9035 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9036 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9037 PetscFunctionReturn(PETSC_SUCCESS); 9038 } 9039 9040 /*@ 9041 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9042 9043 Not Collective because auxiliary vectors are not parallel 9044 9045 Input Parameters: 9046 + dm - The `DM` 9047 . label - The `DMLabel` 9048 . value - The label value indicating the region 9049 . part - The equation part, or 0 if unused 9050 - aux - The `Vec` holding auxiliary field data 9051 9052 Level: advanced 9053 9054 .seealso: [](ch_dmbase), `DM`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9055 @*/ 9056 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9057 { 9058 Vec old; 9059 PetscHashAuxKey key; 9060 9061 PetscFunctionBegin; 9062 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9063 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9064 key.label = label; 9065 key.value = value; 9066 key.part = part; 9067 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9068 PetscCall(PetscObjectReference((PetscObject)aux)); 9069 PetscCall(PetscObjectDereference((PetscObject)old)); 9070 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9071 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9072 PetscFunctionReturn(PETSC_SUCCESS); 9073 } 9074 9075 /*@C 9076 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9077 9078 Not Collective 9079 9080 Input Parameter: 9081 . dm - The `DM` 9082 9083 Output Parameters: 9084 + labels - The `DMLabel`s for each `Vec` 9085 . values - The label values for each `Vec` 9086 - parts - The equation parts for each `Vec` 9087 9088 Level: advanced 9089 9090 Note: 9091 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9092 9093 .seealso: [](ch_dmbase), `DM`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9094 @*/ 9095 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9096 { 9097 PetscHashAuxKey *keys; 9098 PetscInt n, i, off = 0; 9099 9100 PetscFunctionBegin; 9101 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9102 PetscAssertPointer(labels, 2); 9103 PetscAssertPointer(values, 3); 9104 PetscAssertPointer(parts, 4); 9105 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9106 PetscCall(PetscMalloc1(n, &keys)); 9107 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9108 for (i = 0; i < n; ++i) { 9109 labels[i] = keys[i].label; 9110 values[i] = keys[i].value; 9111 parts[i] = keys[i].part; 9112 } 9113 PetscCall(PetscFree(keys)); 9114 PetscFunctionReturn(PETSC_SUCCESS); 9115 } 9116 9117 /*@ 9118 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9119 9120 Not Collective 9121 9122 Input Parameter: 9123 . dm - The `DM` 9124 9125 Output Parameter: 9126 . dmNew - The new `DM`, now with the same auxiliary data 9127 9128 Level: advanced 9129 9130 Note: 9131 This is a shallow copy of the auxiliary vectors 9132 9133 .seealso: [](ch_dmbase), `DM`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9134 @*/ 9135 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9136 { 9137 PetscFunctionBegin; 9138 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9139 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9140 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9141 PetscFunctionReturn(PETSC_SUCCESS); 9142 } 9143 9144 /*@C 9145 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9146 9147 Not Collective 9148 9149 Input Parameters: 9150 + ct - The `DMPolytopeType` 9151 . sourceCone - The source arrangement of faces 9152 - targetCone - The target arrangement of faces 9153 9154 Output Parameters: 9155 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9156 - found - Flag indicating that a suitable orientation was found 9157 9158 Level: advanced 9159 9160 Note: 9161 An arrangement is a face order combined with an orientation for each face 9162 9163 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2 9164 that labels each arrangement (face ordering plus orientation for each face). 9165 9166 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9167 9168 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9169 @*/ 9170 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9171 { 9172 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9173 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2; 9174 PetscInt o, c; 9175 9176 PetscFunctionBegin; 9177 if (!nO) { 9178 *ornt = 0; 9179 *found = PETSC_TRUE; 9180 PetscFunctionReturn(PETSC_SUCCESS); 9181 } 9182 for (o = -nO; o < nO; ++o) { 9183 const PetscInt *arr = DMPolytopeTypeGetArrangment(ct, o); 9184 9185 for (c = 0; c < cS; ++c) 9186 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9187 if (c == cS) { 9188 *ornt = o; 9189 break; 9190 } 9191 } 9192 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9193 PetscFunctionReturn(PETSC_SUCCESS); 9194 } 9195 9196 /*@C 9197 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9198 9199 Not Collective 9200 9201 Input Parameters: 9202 + ct - The `DMPolytopeType` 9203 . sourceCone - The source arrangement of faces 9204 - targetCone - The target arrangement of faces 9205 9206 Output Parameter: 9207 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9208 9209 Level: advanced 9210 9211 Note: 9212 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9213 9214 Developer Notes: 9215 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9216 9217 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9218 @*/ 9219 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9220 { 9221 PetscBool found; 9222 9223 PetscFunctionBegin; 9224 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9225 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9226 PetscFunctionReturn(PETSC_SUCCESS); 9227 } 9228 9229 /*@C 9230 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9231 9232 Not Collective 9233 9234 Input Parameters: 9235 + ct - The `DMPolytopeType` 9236 . sourceVert - The source arrangement of vertices 9237 - targetVert - The target arrangement of vertices 9238 9239 Output Parameters: 9240 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9241 - found - Flag indicating that a suitable orientation was found 9242 9243 Level: advanced 9244 9245 Note: 9246 An arrangement is a vertex order 9247 9248 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangments(ct)`/2 to `DMPolytopeTypeGetNumArrangments(ct)`/2 9249 that labels each arrangement (vertex ordering). 9250 9251 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9252 9253 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangment()` 9254 @*/ 9255 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9256 { 9257 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9258 const PetscInt nO = DMPolytopeTypeGetNumArrangments(ct) / 2; 9259 PetscInt o, c; 9260 9261 PetscFunctionBegin; 9262 if (!nO) { 9263 *ornt = 0; 9264 *found = PETSC_TRUE; 9265 PetscFunctionReturn(PETSC_SUCCESS); 9266 } 9267 for (o = -nO; o < nO; ++o) { 9268 const PetscInt *arr = DMPolytopeTypeGetVertexArrangment(ct, o); 9269 9270 for (c = 0; c < cS; ++c) 9271 if (sourceVert[arr[c]] != targetVert[c]) break; 9272 if (c == cS) { 9273 *ornt = o; 9274 break; 9275 } 9276 } 9277 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9278 PetscFunctionReturn(PETSC_SUCCESS); 9279 } 9280 9281 /*@C 9282 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9283 9284 Not Collective 9285 9286 Input Parameters: 9287 + ct - The `DMPolytopeType` 9288 . sourceCone - The source arrangement of vertices 9289 - targetCone - The target arrangement of vertices 9290 9291 Output Parameter: 9292 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9293 9294 Level: advanced 9295 9296 Note: 9297 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9298 9299 Developer Notes: 9300 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9301 9302 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9303 @*/ 9304 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9305 { 9306 PetscBool found; 9307 9308 PetscFunctionBegin; 9309 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9310 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9311 PetscFunctionReturn(PETSC_SUCCESS); 9312 } 9313 9314 /*@C 9315 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9316 9317 Not Collective 9318 9319 Input Parameters: 9320 + ct - The `DMPolytopeType` 9321 - point - Coordinates of the point 9322 9323 Output Parameter: 9324 . inside - Flag indicating whether the point is inside the reference cell of given type 9325 9326 Level: advanced 9327 9328 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9329 @*/ 9330 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9331 { 9332 PetscReal sum = 0.0; 9333 PetscInt d; 9334 9335 PetscFunctionBegin; 9336 *inside = PETSC_TRUE; 9337 switch (ct) { 9338 case DM_POLYTOPE_TRIANGLE: 9339 case DM_POLYTOPE_TETRAHEDRON: 9340 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9341 if (point[d] < -1.0) { 9342 *inside = PETSC_FALSE; 9343 break; 9344 } 9345 sum += point[d]; 9346 } 9347 if (sum > PETSC_SMALL) { 9348 *inside = PETSC_FALSE; 9349 break; 9350 } 9351 break; 9352 case DM_POLYTOPE_QUADRILATERAL: 9353 case DM_POLYTOPE_HEXAHEDRON: 9354 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9355 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9356 *inside = PETSC_FALSE; 9357 break; 9358 } 9359 break; 9360 default: 9361 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9362 } 9363 PetscFunctionReturn(PETSC_SUCCESS); 9364 } 9365