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