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