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