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