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