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