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