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", ((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 4563 PetscFunctionBegin; 4564 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4565 PetscAssertPointer(sf, 2); 4566 PetscCall(PetscObjectQueryFunction((PetscObject)dm, "DMGetIsoperiodicPointSF_C", &f)); 4567 if (f) PetscCall(f(dm, sf)); 4568 else *sf = dm->sf; 4569 PetscFunctionReturn(PETSC_SUCCESS); 4570 } 4571 4572 /*@ 4573 DMGetGlobalSection - Get the `PetscSection` encoding the global data layout for the `DM`. 4574 4575 Collective 4576 4577 Input Parameter: 4578 . dm - The `DM` 4579 4580 Output Parameter: 4581 . section - The `PetscSection` 4582 4583 Level: intermediate 4584 4585 Note: 4586 This gets a borrowed reference, so the user should not destroy this `PetscSection`. 4587 4588 .seealso: [](ch_dmbase), `DM`, `DMSetLocalSection()`, `DMGetLocalSection()` 4589 @*/ 4590 PetscErrorCode DMGetGlobalSection(DM dm, PetscSection *section) 4591 { 4592 PetscFunctionBegin; 4593 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4594 PetscAssertPointer(section, 2); 4595 if (!dm->globalSection) { 4596 PetscSection s; 4597 PetscSF sf; 4598 4599 PetscCall(DMGetLocalSection(dm, &s)); 4600 PetscCheck(s, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a default PetscSection in order to create a global PetscSection"); 4601 PetscCheck(dm->sf, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM must have a point PetscSF in order to create a global PetscSection"); 4602 PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &sf)); 4603 PetscCall(PetscSectionCreateGlobalSection(s, sf, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &dm->globalSection)); 4604 PetscCall(PetscLayoutDestroy(&dm->map)); 4605 PetscCall(PetscSectionGetValueLayout(PetscObjectComm((PetscObject)dm), dm->globalSection, &dm->map)); 4606 PetscCall(PetscSectionViewFromOptions(dm->globalSection, NULL, "-global_section_view")); 4607 } 4608 *section = dm->globalSection; 4609 PetscFunctionReturn(PETSC_SUCCESS); 4610 } 4611 4612 /*@ 4613 DMSetGlobalSection - Set the `PetscSection` encoding the global data layout for the `DM`. 4614 4615 Input Parameters: 4616 + dm - The `DM` 4617 - section - The PetscSection, or `NULL` 4618 4619 Level: intermediate 4620 4621 Note: 4622 Any existing `PetscSection` will be destroyed 4623 4624 .seealso: [](ch_dmbase), `DM`, `DMGetGlobalSection()`, `DMSetLocalSection()` 4625 @*/ 4626 PetscErrorCode DMSetGlobalSection(DM dm, PetscSection section) 4627 { 4628 PetscFunctionBegin; 4629 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4630 if (section) PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 2); 4631 PetscCall(PetscObjectReference((PetscObject)section)); 4632 PetscCall(PetscSectionDestroy(&dm->globalSection)); 4633 dm->globalSection = section; 4634 #if defined(PETSC_USE_DEBUG) 4635 if (section) PetscCall(DMDefaultSectionCheckConsistency_Internal(dm, dm->localSection, section)); 4636 #endif 4637 /* Clear global scratch vectors and sectionSF */ 4638 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4639 PetscCall(DMClearGlobalVectors(dm)); 4640 PetscCall(DMClearNamedGlobalVectors(dm)); 4641 PetscFunctionReturn(PETSC_SUCCESS); 4642 } 4643 4644 /*@ 4645 DMGetSectionSF - Get the `PetscSF` encoding the parallel dof overlap for the `DM`. If it has not been set, 4646 it is created from the default `PetscSection` layouts in the `DM`. 4647 4648 Input Parameter: 4649 . dm - The `DM` 4650 4651 Output Parameter: 4652 . sf - The `PetscSF` 4653 4654 Level: intermediate 4655 4656 Note: 4657 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4658 4659 .seealso: [](ch_dmbase), `DM`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4660 @*/ 4661 PetscErrorCode DMGetSectionSF(DM dm, PetscSF *sf) 4662 { 4663 PetscInt nroots; 4664 4665 PetscFunctionBegin; 4666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4667 PetscAssertPointer(sf, 2); 4668 if (!dm->sectionSF) PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &dm->sectionSF)); 4669 PetscCall(PetscSFGetGraph(dm->sectionSF, &nroots, NULL, NULL, NULL)); 4670 if (nroots < 0) { 4671 PetscSection section, gSection; 4672 4673 PetscCall(DMGetLocalSection(dm, §ion)); 4674 if (section) { 4675 PetscCall(DMGetGlobalSection(dm, &gSection)); 4676 PetscCall(DMCreateSectionSF(dm, section, gSection)); 4677 } else { 4678 *sf = NULL; 4679 PetscFunctionReturn(PETSC_SUCCESS); 4680 } 4681 } 4682 *sf = dm->sectionSF; 4683 PetscFunctionReturn(PETSC_SUCCESS); 4684 } 4685 4686 /*@ 4687 DMSetSectionSF - Set the `PetscSF` encoding the parallel dof overlap for the `DM` 4688 4689 Input Parameters: 4690 + dm - The `DM` 4691 - sf - The `PetscSF` 4692 4693 Level: intermediate 4694 4695 Note: 4696 Any previous `PetscSF` is destroyed 4697 4698 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMCreateSectionSF()` 4699 @*/ 4700 PetscErrorCode DMSetSectionSF(DM dm, PetscSF sf) 4701 { 4702 PetscFunctionBegin; 4703 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4704 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4705 PetscCall(PetscObjectReference((PetscObject)sf)); 4706 PetscCall(PetscSFDestroy(&dm->sectionSF)); 4707 dm->sectionSF = sf; 4708 PetscFunctionReturn(PETSC_SUCCESS); 4709 } 4710 4711 /*@C 4712 DMCreateSectionSF - Create the `PetscSF` encoding the parallel dof overlap for the `DM` based upon the `PetscSection`s 4713 describing the data layout. 4714 4715 Input Parameters: 4716 + dm - The `DM` 4717 . localSection - `PetscSection` describing the local data layout 4718 - globalSection - `PetscSection` describing the global data layout 4719 4720 Level: developer 4721 4722 Note: 4723 One usually uses `DMGetSectionSF()` to obtain the `PetscSF` 4724 4725 Developer Notes: 4726 Since this routine has for arguments the two sections from the `DM` and puts the resulting `PetscSF` 4727 directly into the `DM`, perhaps this function should not take the local and global sections as 4728 input and should just obtain them from the `DM`? 4729 4730 .seealso: [](ch_dmbase), `DM`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMGetLocalSection()`, `DMGetGlobalSection()` 4731 @*/ 4732 PetscErrorCode DMCreateSectionSF(DM dm, PetscSection localSection, PetscSection globalSection) 4733 { 4734 PetscFunctionBegin; 4735 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4736 PetscCall(PetscSFSetGraphSection(dm->sectionSF, localSection, globalSection)); 4737 PetscFunctionReturn(PETSC_SUCCESS); 4738 } 4739 4740 /*@ 4741 DMGetPointSF - Get the `PetscSF` encoding the parallel section point overlap for the `DM`. 4742 4743 Not collective but the resulting `PetscSF` is collective 4744 4745 Input Parameter: 4746 . dm - The `DM` 4747 4748 Output Parameter: 4749 . sf - The `PetscSF` 4750 4751 Level: intermediate 4752 4753 Note: 4754 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4755 4756 .seealso: [](ch_dmbase), `DM`, `DMSetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4757 @*/ 4758 PetscErrorCode DMGetPointSF(DM dm, PetscSF *sf) 4759 { 4760 PetscFunctionBegin; 4761 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4762 PetscAssertPointer(sf, 2); 4763 *sf = dm->sf; 4764 PetscFunctionReturn(PETSC_SUCCESS); 4765 } 4766 4767 /*@ 4768 DMSetPointSF - Set the `PetscSF` encoding the parallel section point overlap for the `DM`. 4769 4770 Collective 4771 4772 Input Parameters: 4773 + dm - The `DM` 4774 - sf - The `PetscSF` 4775 4776 Level: intermediate 4777 4778 .seealso: [](ch_dmbase), `DM`, `DMGetPointSF()`, `DMGetSectionSF()`, `DMSetSectionSF()`, `DMCreateSectionSF()` 4779 @*/ 4780 PetscErrorCode DMSetPointSF(DM dm, PetscSF sf) 4781 { 4782 PetscFunctionBegin; 4783 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4784 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4785 PetscCall(PetscObjectReference((PetscObject)sf)); 4786 PetscCall(PetscSFDestroy(&dm->sf)); 4787 dm->sf = sf; 4788 PetscFunctionReturn(PETSC_SUCCESS); 4789 } 4790 4791 /*@ 4792 DMGetNaturalSF - Get the `PetscSF` encoding the map back to the original mesh ordering 4793 4794 Input Parameter: 4795 . dm - The `DM` 4796 4797 Output Parameter: 4798 . sf - The `PetscSF` 4799 4800 Level: intermediate 4801 4802 Note: 4803 This gets a borrowed reference, so the user should not destroy this `PetscSF`. 4804 4805 .seealso: [](ch_dmbase), `DM`, `DMSetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4806 @*/ 4807 PetscErrorCode DMGetNaturalSF(DM dm, PetscSF *sf) 4808 { 4809 PetscFunctionBegin; 4810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4811 PetscAssertPointer(sf, 2); 4812 *sf = dm->sfNatural; 4813 PetscFunctionReturn(PETSC_SUCCESS); 4814 } 4815 4816 /*@ 4817 DMSetNaturalSF - Set the PetscSF encoding the map back to the original mesh ordering 4818 4819 Input Parameters: 4820 + dm - The DM 4821 - sf - The PetscSF 4822 4823 Level: intermediate 4824 4825 .seealso: [](ch_dmbase), `DM`, `DMGetNaturalSF()`, `DMSetUseNatural()`, `DMGetUseNatural()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexDistribute()` 4826 @*/ 4827 PetscErrorCode DMSetNaturalSF(DM dm, PetscSF sf) 4828 { 4829 PetscFunctionBegin; 4830 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4831 if (sf) PetscValidHeaderSpecific(sf, PETSCSF_CLASSID, 2); 4832 PetscCall(PetscObjectReference((PetscObject)sf)); 4833 PetscCall(PetscSFDestroy(&dm->sfNatural)); 4834 dm->sfNatural = sf; 4835 PetscFunctionReturn(PETSC_SUCCESS); 4836 } 4837 4838 static PetscErrorCode DMSetDefaultAdjacency_Private(DM dm, PetscInt f, PetscObject disc) 4839 { 4840 PetscClassId id; 4841 4842 PetscFunctionBegin; 4843 PetscCall(PetscObjectGetClassId(disc, &id)); 4844 if (id == PETSCFE_CLASSID) { 4845 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4846 } else if (id == PETSCFV_CLASSID) { 4847 PetscCall(DMSetAdjacency(dm, f, PETSC_TRUE, PETSC_FALSE)); 4848 } else { 4849 PetscCall(DMSetAdjacency(dm, f, PETSC_FALSE, PETSC_TRUE)); 4850 } 4851 PetscFunctionReturn(PETSC_SUCCESS); 4852 } 4853 4854 static PetscErrorCode DMFieldEnlarge_Static(DM dm, PetscInt NfNew) 4855 { 4856 RegionField *tmpr; 4857 PetscInt Nf = dm->Nf, f; 4858 4859 PetscFunctionBegin; 4860 if (Nf >= NfNew) PetscFunctionReturn(PETSC_SUCCESS); 4861 PetscCall(PetscMalloc1(NfNew, &tmpr)); 4862 for (f = 0; f < Nf; ++f) tmpr[f] = dm->fields[f]; 4863 for (f = Nf; f < NfNew; ++f) { 4864 tmpr[f].disc = NULL; 4865 tmpr[f].label = NULL; 4866 tmpr[f].avoidTensor = PETSC_FALSE; 4867 } 4868 PetscCall(PetscFree(dm->fields)); 4869 dm->Nf = NfNew; 4870 dm->fields = tmpr; 4871 PetscFunctionReturn(PETSC_SUCCESS); 4872 } 4873 4874 /*@ 4875 DMClearFields - Remove all fields from the `DM` 4876 4877 Logically Collective 4878 4879 Input Parameter: 4880 . dm - The `DM` 4881 4882 Level: intermediate 4883 4884 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetNumFields()`, `DMSetField()` 4885 @*/ 4886 PetscErrorCode DMClearFields(DM dm) 4887 { 4888 PetscInt f; 4889 4890 PetscFunctionBegin; 4891 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4892 for (f = 0; f < dm->Nf; ++f) { 4893 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4894 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4895 } 4896 PetscCall(PetscFree(dm->fields)); 4897 dm->fields = NULL; 4898 dm->Nf = 0; 4899 PetscFunctionReturn(PETSC_SUCCESS); 4900 } 4901 4902 /*@ 4903 DMGetNumFields - Get the number of fields in the `DM` 4904 4905 Not Collective 4906 4907 Input Parameter: 4908 . dm - The `DM` 4909 4910 Output Parameter: 4911 . numFields - The number of fields 4912 4913 Level: intermediate 4914 4915 .seealso: [](ch_dmbase), `DM`, `DMSetNumFields()`, `DMSetField()` 4916 @*/ 4917 PetscErrorCode DMGetNumFields(DM dm, PetscInt *numFields) 4918 { 4919 PetscFunctionBegin; 4920 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4921 PetscAssertPointer(numFields, 2); 4922 *numFields = dm->Nf; 4923 PetscFunctionReturn(PETSC_SUCCESS); 4924 } 4925 4926 /*@ 4927 DMSetNumFields - Set the number of fields in the `DM` 4928 4929 Logically Collective 4930 4931 Input Parameters: 4932 + dm - The `DM` 4933 - numFields - The number of fields 4934 4935 Level: intermediate 4936 4937 .seealso: [](ch_dmbase), `DM`, `DMGetNumFields()`, `DMSetField()` 4938 @*/ 4939 PetscErrorCode DMSetNumFields(DM dm, PetscInt numFields) 4940 { 4941 PetscInt Nf, f; 4942 4943 PetscFunctionBegin; 4944 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4945 PetscCall(DMGetNumFields(dm, &Nf)); 4946 for (f = Nf; f < numFields; ++f) { 4947 PetscContainer obj; 4948 4949 PetscCall(PetscContainerCreate(PetscObjectComm((PetscObject)dm), &obj)); 4950 PetscCall(DMAddField(dm, NULL, (PetscObject)obj)); 4951 PetscCall(PetscContainerDestroy(&obj)); 4952 } 4953 PetscFunctionReturn(PETSC_SUCCESS); 4954 } 4955 4956 /*@ 4957 DMGetField - Return the `DMLabel` and discretization object for a given `DM` field 4958 4959 Not Collective 4960 4961 Input Parameters: 4962 + dm - The `DM` 4963 - f - The field number 4964 4965 Output Parameters: 4966 + label - The label indicating the support of the field, or `NULL` for the entire mesh (pass in `NULL` if not needed) 4967 - disc - The discretization object (pass in `NULL` if not needed) 4968 4969 Level: intermediate 4970 4971 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()` 4972 @*/ 4973 PetscErrorCode DMGetField(DM dm, PetscInt f, DMLabel *label, PetscObject *disc) 4974 { 4975 PetscFunctionBegin; 4976 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 4977 PetscAssertPointer(disc, 4); 4978 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); 4979 if (label) *label = dm->fields[f].label; 4980 if (disc) *disc = dm->fields[f].disc; 4981 PetscFunctionReturn(PETSC_SUCCESS); 4982 } 4983 4984 /* Does not clear the DS */ 4985 PetscErrorCode DMSetField_Internal(DM dm, PetscInt f, DMLabel label, PetscObject disc) 4986 { 4987 PetscFunctionBegin; 4988 PetscCall(DMFieldEnlarge_Static(dm, f + 1)); 4989 PetscCall(DMLabelDestroy(&dm->fields[f].label)); 4990 PetscCall(PetscObjectDestroy(&dm->fields[f].disc)); 4991 dm->fields[f].label = label; 4992 dm->fields[f].disc = disc; 4993 PetscCall(PetscObjectReference((PetscObject)label)); 4994 PetscCall(PetscObjectReference((PetscObject)disc)); 4995 PetscFunctionReturn(PETSC_SUCCESS); 4996 } 4997 4998 /*@C 4999 DMSetField - Set the discretization object for a given `DM` field. Usually one would call `DMAddField()` which automatically handles 5000 the field numbering. 5001 5002 Logically Collective 5003 5004 Input Parameters: 5005 + dm - The `DM` 5006 . f - The field number 5007 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5008 - disc - The discretization object 5009 5010 Level: intermediate 5011 5012 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMGetField()` 5013 @*/ 5014 PetscErrorCode DMSetField(DM dm, PetscInt f, DMLabel label, PetscObject disc) 5015 { 5016 PetscFunctionBegin; 5017 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5018 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5019 PetscValidHeader(disc, 4); 5020 PetscCheck(f >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be non-negative", f); 5021 PetscCall(DMSetField_Internal(dm, f, label, disc)); 5022 PetscCall(DMSetDefaultAdjacency_Private(dm, f, disc)); 5023 PetscCall(DMClearDS(dm)); 5024 PetscFunctionReturn(PETSC_SUCCESS); 5025 } 5026 5027 /*@C 5028 DMAddField - Add a field to a `DM` object. A field is a function space defined by of a set of discretization points (geometric entities) 5029 and a discretization object that defines the function space associated with those points. 5030 5031 Logically Collective 5032 5033 Input Parameters: 5034 + dm - The `DM` 5035 . label - The label indicating the support of the field, or `NULL` for the entire mesh 5036 - disc - The discretization object 5037 5038 Level: intermediate 5039 5040 Notes: 5041 The label already exists or will be added to the `DM` with `DMSetLabel()`. 5042 5043 For example, a piecewise continuous pressure field can be defined by coefficients at the cell centers of a mesh and piecewise constant functions 5044 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 5045 geometry entities, a `DMLabel` indicating a subset of those geometric entities, and a discretization object, such as a `PetscFE`. 5046 5047 .seealso: [](ch_dmbase), `DM`, `DMSetLabel()`, `DMSetField()`, `DMGetField()`, `PetscFE` 5048 @*/ 5049 PetscErrorCode DMAddField(DM dm, DMLabel label, PetscObject disc) 5050 { 5051 PetscInt Nf = dm->Nf; 5052 5053 PetscFunctionBegin; 5054 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5055 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5056 PetscValidHeader(disc, 3); 5057 PetscCall(DMFieldEnlarge_Static(dm, Nf + 1)); 5058 dm->fields[Nf].label = label; 5059 dm->fields[Nf].disc = disc; 5060 PetscCall(PetscObjectReference((PetscObject)label)); 5061 PetscCall(PetscObjectReference((PetscObject)disc)); 5062 PetscCall(DMSetDefaultAdjacency_Private(dm, Nf, disc)); 5063 PetscCall(DMClearDS(dm)); 5064 PetscFunctionReturn(PETSC_SUCCESS); 5065 } 5066 5067 /*@ 5068 DMSetFieldAvoidTensor - Set flag to avoid defining the field on tensor cells 5069 5070 Logically Collective 5071 5072 Input Parameters: 5073 + dm - The `DM` 5074 . f - The field index 5075 - avoidTensor - `PETSC_TRUE` to skip defining the field on tensor cells 5076 5077 Level: intermediate 5078 5079 .seealso: [](ch_dmbase), `DM`, `DMGetFieldAvoidTensor()`, `DMSetField()`, `DMGetField()` 5080 @*/ 5081 PetscErrorCode DMSetFieldAvoidTensor(DM dm, PetscInt f, PetscBool avoidTensor) 5082 { 5083 PetscFunctionBegin; 5084 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); 5085 dm->fields[f].avoidTensor = avoidTensor; 5086 PetscFunctionReturn(PETSC_SUCCESS); 5087 } 5088 5089 /*@ 5090 DMGetFieldAvoidTensor - Get flag to avoid defining the field on tensor cells 5091 5092 Not Collective 5093 5094 Input Parameters: 5095 + dm - The `DM` 5096 - f - The field index 5097 5098 Output Parameter: 5099 . avoidTensor - The flag to avoid defining the field on tensor cells 5100 5101 Level: intermediate 5102 5103 .seealso: [](ch_dmbase), `DM`, `DMAddField()`, `DMSetField()`, `DMGetField()`, `DMSetFieldAvoidTensor()` 5104 @*/ 5105 PetscErrorCode DMGetFieldAvoidTensor(DM dm, PetscInt f, PetscBool *avoidTensor) 5106 { 5107 PetscFunctionBegin; 5108 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); 5109 *avoidTensor = dm->fields[f].avoidTensor; 5110 PetscFunctionReturn(PETSC_SUCCESS); 5111 } 5112 5113 /*@ 5114 DMCopyFields - Copy the discretizations for the `DM` into another `DM` 5115 5116 Collective 5117 5118 Input Parameter: 5119 . dm - The `DM` 5120 5121 Output Parameter: 5122 . newdm - The `DM` 5123 5124 Level: advanced 5125 5126 .seealso: [](ch_dmbase), `DM`, `DMGetField()`, `DMSetField()`, `DMAddField()`, `DMCopyDS()`, `DMGetDS()`, `DMGetCellDS()` 5127 @*/ 5128 PetscErrorCode DMCopyFields(DM dm, DM newdm) 5129 { 5130 PetscInt Nf, f; 5131 5132 PetscFunctionBegin; 5133 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 5134 PetscCall(DMGetNumFields(dm, &Nf)); 5135 PetscCall(DMClearFields(newdm)); 5136 for (f = 0; f < Nf; ++f) { 5137 DMLabel label; 5138 PetscObject field; 5139 PetscBool useCone, useClosure; 5140 5141 PetscCall(DMGetField(dm, f, &label, &field)); 5142 PetscCall(DMSetField(newdm, f, label, field)); 5143 PetscCall(DMGetAdjacency(dm, f, &useCone, &useClosure)); 5144 PetscCall(DMSetAdjacency(newdm, f, useCone, useClosure)); 5145 } 5146 PetscFunctionReturn(PETSC_SUCCESS); 5147 } 5148 5149 /*@ 5150 DMGetAdjacency - Returns the flags for determining variable influence 5151 5152 Not Collective 5153 5154 Input Parameters: 5155 + dm - The `DM` object 5156 - f - The field number, or `PETSC_DEFAULT` for the default adjacency 5157 5158 Output Parameters: 5159 + useCone - Flag for variable influence starting with the cone operation 5160 - useClosure - Flag for variable influence using transitive closure 5161 5162 Level: developer 5163 5164 Notes: 5165 .vb 5166 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5167 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5168 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5169 .ve 5170 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5171 5172 .seealso: [](ch_dmbase), `DM`, `DMSetAdjacency()`, `DMGetField()`, `DMSetField()` 5173 @*/ 5174 PetscErrorCode DMGetAdjacency(DM dm, PetscInt f, PetscBool *useCone, PetscBool *useClosure) 5175 { 5176 PetscFunctionBegin; 5177 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5178 if (useCone) PetscAssertPointer(useCone, 3); 5179 if (useClosure) PetscAssertPointer(useClosure, 4); 5180 if (f < 0) { 5181 if (useCone) *useCone = dm->adjacency[0]; 5182 if (useClosure) *useClosure = dm->adjacency[1]; 5183 } else { 5184 PetscInt Nf; 5185 5186 PetscCall(DMGetNumFields(dm, &Nf)); 5187 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5188 if (useCone) *useCone = dm->fields[f].adjacency[0]; 5189 if (useClosure) *useClosure = dm->fields[f].adjacency[1]; 5190 } 5191 PetscFunctionReturn(PETSC_SUCCESS); 5192 } 5193 5194 /*@ 5195 DMSetAdjacency - Set the flags for determining variable influence 5196 5197 Not Collective 5198 5199 Input Parameters: 5200 + dm - The `DM` object 5201 . f - The field number 5202 . useCone - Flag for variable influence starting with the cone operation 5203 - useClosure - Flag for variable influence using transitive closure 5204 5205 Level: developer 5206 5207 Notes: 5208 .vb 5209 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5210 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5211 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5212 .ve 5213 Further explanation can be found in the User's Manual Section on the Influence of Variables on One Another. 5214 5215 .seealso: [](ch_dmbase), `DM`, `DMGetAdjacency()`, `DMGetField()`, `DMSetField()` 5216 @*/ 5217 PetscErrorCode DMSetAdjacency(DM dm, PetscInt f, PetscBool useCone, PetscBool useClosure) 5218 { 5219 PetscFunctionBegin; 5220 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5221 if (f < 0) { 5222 dm->adjacency[0] = useCone; 5223 dm->adjacency[1] = useClosure; 5224 } else { 5225 PetscInt Nf; 5226 5227 PetscCall(DMGetNumFields(dm, &Nf)); 5228 PetscCheck(f < Nf, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field number %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", f, Nf); 5229 dm->fields[f].adjacency[0] = useCone; 5230 dm->fields[f].adjacency[1] = useClosure; 5231 } 5232 PetscFunctionReturn(PETSC_SUCCESS); 5233 } 5234 5235 /*@ 5236 DMGetBasicAdjacency - Returns the flags for determining variable influence, using either the default or field 0 if it is defined 5237 5238 Not collective 5239 5240 Input Parameter: 5241 . dm - The `DM` object 5242 5243 Output Parameters: 5244 + useCone - Flag for variable influence starting with the cone operation 5245 - useClosure - Flag for variable influence using transitive closure 5246 5247 Level: developer 5248 5249 Notes: 5250 .vb 5251 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5252 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5253 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5254 .ve 5255 5256 .seealso: [](ch_dmbase), `DM`, `DMSetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5257 @*/ 5258 PetscErrorCode DMGetBasicAdjacency(DM dm, PetscBool *useCone, PetscBool *useClosure) 5259 { 5260 PetscInt Nf; 5261 5262 PetscFunctionBegin; 5263 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5264 if (useCone) PetscAssertPointer(useCone, 2); 5265 if (useClosure) PetscAssertPointer(useClosure, 3); 5266 PetscCall(DMGetNumFields(dm, &Nf)); 5267 if (!Nf) { 5268 PetscCall(DMGetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5269 } else { 5270 PetscCall(DMGetAdjacency(dm, 0, useCone, useClosure)); 5271 } 5272 PetscFunctionReturn(PETSC_SUCCESS); 5273 } 5274 5275 /*@ 5276 DMSetBasicAdjacency - Set the flags for determining variable influence, using either the default or field 0 if it is defined 5277 5278 Not Collective 5279 5280 Input Parameters: 5281 + dm - The `DM` object 5282 . useCone - Flag for variable influence starting with the cone operation 5283 - useClosure - Flag for variable influence using transitive closure 5284 5285 Level: developer 5286 5287 Notes: 5288 .vb 5289 FEM: Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE 5290 FVM: Two points p and q are adjacent if q \in support(p+cone(p)), useCone = PETSC_TRUE, useClosure = PETSC_FALSE 5291 FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE, useClosure = PETSC_TRUE 5292 .ve 5293 5294 .seealso: [](ch_dmbase), `DM`, `DMGetBasicAdjacency()`, `DMGetField()`, `DMSetField()` 5295 @*/ 5296 PetscErrorCode DMSetBasicAdjacency(DM dm, PetscBool useCone, PetscBool useClosure) 5297 { 5298 PetscInt Nf; 5299 5300 PetscFunctionBegin; 5301 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5302 PetscCall(DMGetNumFields(dm, &Nf)); 5303 if (!Nf) { 5304 PetscCall(DMSetAdjacency(dm, PETSC_DEFAULT, useCone, useClosure)); 5305 } else { 5306 PetscCall(DMSetAdjacency(dm, 0, useCone, useClosure)); 5307 } 5308 PetscFunctionReturn(PETSC_SUCCESS); 5309 } 5310 5311 PetscErrorCode DMCompleteBCLabels_Internal(DM dm) 5312 { 5313 DM plex; 5314 DMLabel *labels, *glabels; 5315 const char **names; 5316 char *sendNames, *recvNames; 5317 PetscInt Nds, s, maxLabels = 0, maxLen = 0, gmaxLen, Nl = 0, gNl, l, gl, m; 5318 size_t len; 5319 MPI_Comm comm; 5320 PetscMPIInt rank, size, p, *counts, *displs; 5321 5322 PetscFunctionBegin; 5323 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5324 PetscCallMPI(MPI_Comm_size(comm, &size)); 5325 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 5326 PetscCall(DMGetNumDS(dm, &Nds)); 5327 for (s = 0; s < Nds; ++s) { 5328 PetscDS dsBC; 5329 PetscInt numBd; 5330 5331 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5332 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5333 maxLabels += numBd; 5334 } 5335 PetscCall(PetscCalloc1(maxLabels, &labels)); 5336 /* Get list of labels to be completed */ 5337 for (s = 0; s < Nds; ++s) { 5338 PetscDS dsBC; 5339 PetscInt numBd, bd; 5340 5341 PetscCall(DMGetRegionNumDS(dm, s, NULL, NULL, &dsBC, NULL)); 5342 PetscCall(PetscDSGetNumBoundary(dsBC, &numBd)); 5343 for (bd = 0; bd < numBd; ++bd) { 5344 DMLabel label; 5345 PetscInt field; 5346 PetscObject obj; 5347 PetscClassId id; 5348 5349 PetscCall(PetscDSGetBoundary(dsBC, bd, NULL, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 5350 PetscCall(DMGetField(dm, field, NULL, &obj)); 5351 PetscCall(PetscObjectGetClassId(obj, &id)); 5352 if (!(id == PETSCFE_CLASSID) || !label) continue; 5353 for (l = 0; l < Nl; ++l) 5354 if (labels[l] == label) break; 5355 if (l == Nl) labels[Nl++] = label; 5356 } 5357 } 5358 /* Get label names */ 5359 PetscCall(PetscMalloc1(Nl, &names)); 5360 for (l = 0; l < Nl; ++l) PetscCall(PetscObjectGetName((PetscObject)labels[l], &names[l])); 5361 for (l = 0; l < Nl; ++l) { 5362 PetscCall(PetscStrlen(names[l], &len)); 5363 maxLen = PetscMax(maxLen, (PetscInt)len + 2); 5364 } 5365 PetscCall(PetscFree(labels)); 5366 PetscCall(MPIU_Allreduce(&maxLen, &gmaxLen, 1, MPIU_INT, MPI_MAX, comm)); 5367 PetscCall(PetscCalloc1(Nl * gmaxLen, &sendNames)); 5368 for (l = 0; l < Nl; ++l) PetscCall(PetscStrncpy(&sendNames[gmaxLen * l], names[l], gmaxLen)); 5369 PetscCall(PetscFree(names)); 5370 /* Put all names on all processes */ 5371 PetscCall(PetscCalloc2(size, &counts, size + 1, &displs)); 5372 PetscCallMPI(MPI_Allgather(&Nl, 1, MPI_INT, counts, 1, MPI_INT, comm)); 5373 for (p = 0; p < size; ++p) displs[p + 1] = displs[p] + counts[p]; 5374 gNl = displs[size]; 5375 for (p = 0; p < size; ++p) { 5376 counts[p] *= gmaxLen; 5377 displs[p] *= gmaxLen; 5378 } 5379 PetscCall(PetscCalloc2(gNl * gmaxLen, &recvNames, gNl, &glabels)); 5380 PetscCallMPI(MPI_Allgatherv(sendNames, counts[rank], MPI_CHAR, recvNames, counts, displs, MPI_CHAR, comm)); 5381 PetscCall(PetscFree2(counts, displs)); 5382 PetscCall(PetscFree(sendNames)); 5383 for (l = 0, gl = 0; l < gNl; ++l) { 5384 PetscCall(DMGetLabel(dm, &recvNames[l * gmaxLen], &glabels[gl])); 5385 PetscCheck(glabels[gl], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Label %s missing on rank %d", &recvNames[l * gmaxLen], rank); 5386 for (m = 0; m < gl; ++m) 5387 if (glabels[m] == glabels[gl]) continue; 5388 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5389 PetscCall(DMPlexLabelComplete(plex, glabels[gl])); 5390 PetscCall(DMDestroy(&plex)); 5391 ++gl; 5392 } 5393 PetscCall(PetscFree2(recvNames, glabels)); 5394 PetscFunctionReturn(PETSC_SUCCESS); 5395 } 5396 5397 static PetscErrorCode DMDSEnlarge_Static(DM dm, PetscInt NdsNew) 5398 { 5399 DMSpace *tmpd; 5400 PetscInt Nds = dm->Nds, s; 5401 5402 PetscFunctionBegin; 5403 if (Nds >= NdsNew) PetscFunctionReturn(PETSC_SUCCESS); 5404 PetscCall(PetscMalloc1(NdsNew, &tmpd)); 5405 for (s = 0; s < Nds; ++s) tmpd[s] = dm->probs[s]; 5406 for (s = Nds; s < NdsNew; ++s) { 5407 tmpd[s].ds = NULL; 5408 tmpd[s].label = NULL; 5409 tmpd[s].fields = NULL; 5410 } 5411 PetscCall(PetscFree(dm->probs)); 5412 dm->Nds = NdsNew; 5413 dm->probs = tmpd; 5414 PetscFunctionReturn(PETSC_SUCCESS); 5415 } 5416 5417 /*@ 5418 DMGetNumDS - Get the number of discrete systems in the `DM` 5419 5420 Not Collective 5421 5422 Input Parameter: 5423 . dm - The `DM` 5424 5425 Output Parameter: 5426 . Nds - The number of `PetscDS` objects 5427 5428 Level: intermediate 5429 5430 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMGetCellDS()` 5431 @*/ 5432 PetscErrorCode DMGetNumDS(DM dm, PetscInt *Nds) 5433 { 5434 PetscFunctionBegin; 5435 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5436 PetscAssertPointer(Nds, 2); 5437 *Nds = dm->Nds; 5438 PetscFunctionReturn(PETSC_SUCCESS); 5439 } 5440 5441 /*@ 5442 DMClearDS - Remove all discrete systems from the `DM` 5443 5444 Logically Collective 5445 5446 Input Parameter: 5447 . dm - The `DM` 5448 5449 Level: intermediate 5450 5451 .seealso: [](ch_dmbase), `DM`, `DMGetNumDS()`, `DMGetDS()`, `DMSetField()` 5452 @*/ 5453 PetscErrorCode DMClearDS(DM dm) 5454 { 5455 PetscInt s; 5456 5457 PetscFunctionBegin; 5458 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5459 for (s = 0; s < dm->Nds; ++s) { 5460 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5461 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5462 PetscCall(DMLabelDestroy(&dm->probs[s].label)); 5463 PetscCall(ISDestroy(&dm->probs[s].fields)); 5464 } 5465 PetscCall(PetscFree(dm->probs)); 5466 dm->probs = NULL; 5467 dm->Nds = 0; 5468 PetscFunctionReturn(PETSC_SUCCESS); 5469 } 5470 5471 /*@ 5472 DMGetDS - Get the default `PetscDS` 5473 5474 Not Collective 5475 5476 Input Parameter: 5477 . dm - The `DM` 5478 5479 Output Parameter: 5480 . ds - The default `PetscDS` 5481 5482 Level: intermediate 5483 5484 .seealso: [](ch_dmbase), `DM`, `DMGetCellDS()`, `DMGetRegionDS()` 5485 @*/ 5486 PetscErrorCode DMGetDS(DM dm, PetscDS *ds) 5487 { 5488 PetscFunctionBeginHot; 5489 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5490 PetscAssertPointer(ds, 2); 5491 PetscCheck(dm->Nds > 0, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Need to call DMCreateDS() before calling DMGetDS()"); 5492 *ds = dm->probs[0].ds; 5493 PetscFunctionReturn(PETSC_SUCCESS); 5494 } 5495 5496 /*@ 5497 DMGetCellDS - Get the `PetscDS` defined on a given cell 5498 5499 Not Collective 5500 5501 Input Parameters: 5502 + dm - The `DM` 5503 - point - Cell for the `PetscDS` 5504 5505 Output Parameters: 5506 + ds - The `PetscDS` defined on the given cell 5507 - dsIn - The `PetscDS` for input on the given cell, or NULL if the same ds 5508 5509 Level: developer 5510 5511 .seealso: [](ch_dmbase), `DM`, `DMGetDS()`, `DMSetRegionDS()` 5512 @*/ 5513 PetscErrorCode DMGetCellDS(DM dm, PetscInt point, PetscDS *ds, PetscDS *dsIn) 5514 { 5515 PetscDS dsDef = NULL; 5516 PetscInt s; 5517 5518 PetscFunctionBeginHot; 5519 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5520 if (ds) PetscAssertPointer(ds, 3); 5521 if (dsIn) PetscAssertPointer(dsIn, 4); 5522 PetscCheck(point >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point cannot be negative: %" PetscInt_FMT, point); 5523 if (ds) *ds = NULL; 5524 if (dsIn) *dsIn = NULL; 5525 for (s = 0; s < dm->Nds; ++s) { 5526 PetscInt val; 5527 5528 if (!dm->probs[s].label) { 5529 dsDef = dm->probs[s].ds; 5530 } else { 5531 PetscCall(DMLabelGetValue(dm->probs[s].label, point, &val)); 5532 if (val >= 0) { 5533 if (ds) *ds = dm->probs[s].ds; 5534 if (dsIn) *dsIn = dm->probs[s].dsIn; 5535 break; 5536 } 5537 } 5538 } 5539 if (ds && !*ds) *ds = dsDef; 5540 PetscFunctionReturn(PETSC_SUCCESS); 5541 } 5542 5543 /*@ 5544 DMGetRegionDS - Get the `PetscDS` for a given mesh region, defined by a `DMLabel` 5545 5546 Not Collective 5547 5548 Input Parameters: 5549 + dm - The `DM` 5550 - label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5551 5552 Output Parameters: 5553 + fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5554 . ds - The `PetscDS` defined on the given region, or `NULL` 5555 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5556 5557 Level: advanced 5558 5559 Note: 5560 If a non-`NULL` label is given, but there is no `PetscDS` on that specific label, 5561 the `PetscDS` for the full domain (if present) is returned. Returns with 5562 fields = `NULL` and ds = `NULL` if there is no `PetscDS` for the full domain. 5563 5564 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5565 @*/ 5566 PetscErrorCode DMGetRegionDS(DM dm, DMLabel label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5567 { 5568 PetscInt Nds = dm->Nds, s; 5569 5570 PetscFunctionBegin; 5571 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5572 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5573 if (fields) { 5574 PetscAssertPointer(fields, 3); 5575 *fields = NULL; 5576 } 5577 if (ds) { 5578 PetscAssertPointer(ds, 4); 5579 *ds = NULL; 5580 } 5581 if (dsIn) { 5582 PetscAssertPointer(dsIn, 5); 5583 *dsIn = NULL; 5584 } 5585 for (s = 0; s < Nds; ++s) { 5586 if (dm->probs[s].label == label || !dm->probs[s].label) { 5587 if (fields) *fields = dm->probs[s].fields; 5588 if (ds) *ds = dm->probs[s].ds; 5589 if (dsIn) *dsIn = dm->probs[s].dsIn; 5590 if (dm->probs[s].label) PetscFunctionReturn(PETSC_SUCCESS); 5591 } 5592 } 5593 PetscFunctionReturn(PETSC_SUCCESS); 5594 } 5595 5596 /*@ 5597 DMSetRegionDS - Set the `PetscDS` for a given mesh region, defined by a `DMLabel` 5598 5599 Collective 5600 5601 Input Parameters: 5602 + dm - The `DM` 5603 . label - The `DMLabel` defining the mesh region, or `NULL` for the entire mesh 5604 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` for all fields 5605 . ds - The `PetscDS` defined on the given region 5606 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5607 5608 Level: advanced 5609 5610 Note: 5611 If the label has a `PetscDS` defined, it will be replaced. Otherwise, it will be added to the `DM`. If the `PetscDS` is replaced, 5612 the fields argument is ignored. 5613 5614 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionNumDS()`, `DMGetDS()`, `DMGetCellDS()` 5615 @*/ 5616 PetscErrorCode DMSetRegionDS(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5617 { 5618 PetscInt Nds = dm->Nds, s; 5619 5620 PetscFunctionBegin; 5621 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5622 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 5623 if (fields) PetscValidHeaderSpecific(fields, IS_CLASSID, 3); 5624 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 4); 5625 if (dsIn) PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 5); 5626 for (s = 0; s < Nds; ++s) { 5627 if (dm->probs[s].label == label) { 5628 PetscCall(PetscDSDestroy(&dm->probs[s].ds)); 5629 PetscCall(PetscDSDestroy(&dm->probs[s].dsIn)); 5630 dm->probs[s].ds = ds; 5631 dm->probs[s].dsIn = dsIn; 5632 PetscFunctionReturn(PETSC_SUCCESS); 5633 } 5634 } 5635 PetscCall(DMDSEnlarge_Static(dm, Nds + 1)); 5636 PetscCall(PetscObjectReference((PetscObject)label)); 5637 PetscCall(PetscObjectReference((PetscObject)fields)); 5638 PetscCall(PetscObjectReference((PetscObject)ds)); 5639 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5640 if (!label) { 5641 /* Put the NULL label at the front, so it is returned as the default */ 5642 for (s = Nds - 1; s >= 0; --s) dm->probs[s + 1] = dm->probs[s]; 5643 Nds = 0; 5644 } 5645 dm->probs[Nds].label = label; 5646 dm->probs[Nds].fields = fields; 5647 dm->probs[Nds].ds = ds; 5648 dm->probs[Nds].dsIn = dsIn; 5649 PetscFunctionReturn(PETSC_SUCCESS); 5650 } 5651 5652 /*@ 5653 DMGetRegionNumDS - Get the `PetscDS` for a given mesh region, defined by the region number 5654 5655 Not Collective 5656 5657 Input Parameters: 5658 + dm - The `DM` 5659 - num - The region number, in [0, Nds) 5660 5661 Output Parameters: 5662 + label - The region label, or `NULL` 5663 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` 5664 . ds - The `PetscDS` defined on the given region, or `NULL` 5665 - dsIn - The `PetscDS` for input in the given region, or `NULL` 5666 5667 Level: advanced 5668 5669 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5670 @*/ 5671 PetscErrorCode DMGetRegionNumDS(DM dm, PetscInt num, DMLabel *label, IS *fields, PetscDS *ds, PetscDS *dsIn) 5672 { 5673 PetscInt Nds; 5674 5675 PetscFunctionBegin; 5676 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5677 PetscCall(DMGetNumDS(dm, &Nds)); 5678 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5679 if (label) { 5680 PetscAssertPointer(label, 3); 5681 *label = dm->probs[num].label; 5682 } 5683 if (fields) { 5684 PetscAssertPointer(fields, 4); 5685 *fields = dm->probs[num].fields; 5686 } 5687 if (ds) { 5688 PetscAssertPointer(ds, 5); 5689 *ds = dm->probs[num].ds; 5690 } 5691 if (dsIn) { 5692 PetscAssertPointer(dsIn, 6); 5693 *dsIn = dm->probs[num].dsIn; 5694 } 5695 PetscFunctionReturn(PETSC_SUCCESS); 5696 } 5697 5698 /*@ 5699 DMSetRegionNumDS - Set the `PetscDS` for a given mesh region, defined by the region number 5700 5701 Not Collective 5702 5703 Input Parameters: 5704 + dm - The `DM` 5705 . num - The region number, in [0, Nds) 5706 . label - The region label, or `NULL` 5707 . fields - The `IS` containing the `DM` field numbers for the fields in this `PetscDS`, or `NULL` to prevent setting 5708 . ds - The `PetscDS` defined on the given region, or `NULL` to prevent setting 5709 - dsIn - The `PetscDS` for input on the given cell, or `NULL` if it is the same `PetscDS` 5710 5711 Level: advanced 5712 5713 .seealso: [](ch_dmbase), `DM`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5714 @*/ 5715 PetscErrorCode DMSetRegionNumDS(DM dm, PetscInt num, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 5716 { 5717 PetscInt Nds; 5718 5719 PetscFunctionBegin; 5720 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5721 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 3); 5722 PetscCall(DMGetNumDS(dm, &Nds)); 5723 PetscCheck((num >= 0) && (num < Nds), PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Region number %" PetscInt_FMT " is not in [0, %" PetscInt_FMT ")", num, Nds); 5724 PetscCall(PetscObjectReference((PetscObject)label)); 5725 PetscCall(DMLabelDestroy(&dm->probs[num].label)); 5726 dm->probs[num].label = label; 5727 if (fields) { 5728 PetscValidHeaderSpecific(fields, IS_CLASSID, 4); 5729 PetscCall(PetscObjectReference((PetscObject)fields)); 5730 PetscCall(ISDestroy(&dm->probs[num].fields)); 5731 dm->probs[num].fields = fields; 5732 } 5733 if (ds) { 5734 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 5); 5735 PetscCall(PetscObjectReference((PetscObject)ds)); 5736 PetscCall(PetscDSDestroy(&dm->probs[num].ds)); 5737 dm->probs[num].ds = ds; 5738 } 5739 if (dsIn) { 5740 PetscValidHeaderSpecific(dsIn, PETSCDS_CLASSID, 6); 5741 PetscCall(PetscObjectReference((PetscObject)dsIn)); 5742 PetscCall(PetscDSDestroy(&dm->probs[num].dsIn)); 5743 dm->probs[num].dsIn = dsIn; 5744 } 5745 PetscFunctionReturn(PETSC_SUCCESS); 5746 } 5747 5748 /*@ 5749 DMFindRegionNum - Find the region number for a given `PetscDS`, or -1 if it is not found. 5750 5751 Not Collective 5752 5753 Input Parameters: 5754 + dm - The `DM` 5755 - ds - The `PetscDS` defined on the given region 5756 5757 Output Parameter: 5758 . num - The region number, in [0, Nds), or -1 if not found 5759 5760 Level: advanced 5761 5762 .seealso: [](ch_dmbase), `DM`, `DMGetRegionNumDS()`, `DMGetRegionDS()`, `DMSetRegionDS()`, `DMGetDS()`, `DMGetCellDS()` 5763 @*/ 5764 PetscErrorCode DMFindRegionNum(DM dm, PetscDS ds, PetscInt *num) 5765 { 5766 PetscInt Nds, n; 5767 5768 PetscFunctionBegin; 5769 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5770 PetscValidHeaderSpecific(ds, PETSCDS_CLASSID, 2); 5771 PetscAssertPointer(num, 3); 5772 PetscCall(DMGetNumDS(dm, &Nds)); 5773 for (n = 0; n < Nds; ++n) 5774 if (ds == dm->probs[n].ds) break; 5775 if (n >= Nds) *num = -1; 5776 else *num = n; 5777 PetscFunctionReturn(PETSC_SUCCESS); 5778 } 5779 5780 /*@C 5781 DMCreateFEDefault - Create a `PetscFE` based on the celltype for the mesh 5782 5783 Not Collective 5784 5785 Input Parameters: 5786 + dm - The `DM` 5787 . Nc - The number of components for the field 5788 . prefix - The options prefix for the output `PetscFE`, or `NULL` 5789 - qorder - The quadrature order or `PETSC_DETERMINE` to use `PetscSpace` polynomial degree 5790 5791 Output Parameter: 5792 . fem - The `PetscFE` 5793 5794 Level: intermediate 5795 5796 Note: 5797 This is a convenience method that just calls `PetscFECreateByCell()` underneath. 5798 5799 .seealso: [](ch_dmbase), `DM`, `PetscFECreateByCell()`, `DMAddField()`, `DMCreateDS()`, `DMGetCellDS()`, `DMGetRegionDS()` 5800 @*/ 5801 PetscErrorCode DMCreateFEDefault(DM dm, PetscInt Nc, const char prefix[], PetscInt qorder, PetscFE *fem) 5802 { 5803 DMPolytopeType ct; 5804 PetscInt dim, cStart; 5805 5806 PetscFunctionBegin; 5807 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5808 PetscValidLogicalCollectiveInt(dm, Nc, 2); 5809 if (prefix) PetscAssertPointer(prefix, 3); 5810 PetscValidLogicalCollectiveInt(dm, qorder, 4); 5811 PetscAssertPointer(fem, 5); 5812 PetscCall(DMGetDimension(dm, &dim)); 5813 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 5814 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 5815 PetscCall(PetscFECreateByCell(PETSC_COMM_SELF, dim, Nc, ct, prefix, qorder, fem)); 5816 PetscFunctionReturn(PETSC_SUCCESS); 5817 } 5818 5819 /*@ 5820 DMCreateDS - Create the discrete systems for the `DM` based upon the fields added to the `DM` 5821 5822 Collective 5823 5824 Input Parameter: 5825 . dm - The `DM` 5826 5827 Options Database Key: 5828 . -dm_petscds_view - View all the `PetscDS` objects in this `DM` 5829 5830 Level: intermediate 5831 5832 .seealso: [](ch_dmbase), `DM`, `DMSetField`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 5833 @*/ 5834 PetscErrorCode DMCreateDS(DM dm) 5835 { 5836 MPI_Comm comm; 5837 PetscDS dsDef; 5838 DMLabel *labelSet; 5839 PetscInt dE, Nf = dm->Nf, f, s, Nl, l, Ndef, k; 5840 PetscBool doSetup = PETSC_TRUE, flg; 5841 5842 PetscFunctionBegin; 5843 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 5844 if (!dm->fields) PetscFunctionReturn(PETSC_SUCCESS); 5845 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 5846 PetscCall(DMGetCoordinateDim(dm, &dE)); 5847 /* Determine how many regions we have */ 5848 PetscCall(PetscMalloc1(Nf, &labelSet)); 5849 Nl = 0; 5850 Ndef = 0; 5851 for (f = 0; f < Nf; ++f) { 5852 DMLabel label = dm->fields[f].label; 5853 PetscInt l; 5854 5855 #ifdef PETSC_HAVE_LIBCEED 5856 /* Move CEED context to discretizations */ 5857 { 5858 PetscClassId id; 5859 5860 PetscCall(PetscObjectGetClassId(dm->fields[f].disc, &id)); 5861 if (id == PETSCFE_CLASSID) { 5862 Ceed ceed; 5863 5864 PetscCall(DMGetCeed(dm, &ceed)); 5865 PetscCall(PetscFESetCeed((PetscFE)dm->fields[f].disc, ceed)); 5866 } 5867 } 5868 #endif 5869 if (!label) { 5870 ++Ndef; 5871 continue; 5872 } 5873 for (l = 0; l < Nl; ++l) 5874 if (label == labelSet[l]) break; 5875 if (l < Nl) continue; 5876 labelSet[Nl++] = label; 5877 } 5878 /* Create default DS if there are no labels to intersect with */ 5879 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5880 if (!dsDef && Ndef && !Nl) { 5881 IS fields; 5882 PetscInt *fld, nf; 5883 5884 for (f = 0, nf = 0; f < Nf; ++f) 5885 if (!dm->fields[f].label) ++nf; 5886 PetscCheck(nf, comm, PETSC_ERR_PLIB, "All fields have labels, but we are trying to create a default DS"); 5887 PetscCall(PetscMalloc1(nf, &fld)); 5888 for (f = 0, nf = 0; f < Nf; ++f) 5889 if (!dm->fields[f].label) fld[nf++] = f; 5890 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5891 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5892 PetscCall(ISSetType(fields, ISGENERAL)); 5893 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5894 5895 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5896 PetscCall(DMSetRegionDS(dm, NULL, fields, dsDef, NULL)); 5897 PetscCall(PetscDSDestroy(&dsDef)); 5898 PetscCall(ISDestroy(&fields)); 5899 } 5900 PetscCall(DMGetRegionDS(dm, NULL, NULL, &dsDef, NULL)); 5901 if (dsDef) PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5902 /* Intersect labels with default fields */ 5903 if (Ndef && Nl) { 5904 DM plex; 5905 DMLabel cellLabel; 5906 IS fieldIS, allcellIS, defcellIS = NULL; 5907 PetscInt *fields; 5908 const PetscInt *cells; 5909 PetscInt depth, nf = 0, n, c; 5910 5911 PetscCall(DMConvert(dm, DMPLEX, &plex)); 5912 PetscCall(DMPlexGetDepth(plex, &depth)); 5913 PetscCall(DMGetStratumIS(plex, "dim", depth, &allcellIS)); 5914 if (!allcellIS) PetscCall(DMGetStratumIS(plex, "depth", depth, &allcellIS)); 5915 /* TODO This looks like it only works for one label */ 5916 for (l = 0; l < Nl; ++l) { 5917 DMLabel label = labelSet[l]; 5918 IS pointIS; 5919 5920 PetscCall(ISDestroy(&defcellIS)); 5921 PetscCall(DMLabelGetStratumIS(label, 1, &pointIS)); 5922 PetscCall(ISDifference(allcellIS, pointIS, &defcellIS)); 5923 PetscCall(ISDestroy(&pointIS)); 5924 } 5925 PetscCall(ISDestroy(&allcellIS)); 5926 5927 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "defaultCells", &cellLabel)); 5928 PetscCall(ISGetLocalSize(defcellIS, &n)); 5929 PetscCall(ISGetIndices(defcellIS, &cells)); 5930 for (c = 0; c < n; ++c) PetscCall(DMLabelSetValue(cellLabel, cells[c], 1)); 5931 PetscCall(ISRestoreIndices(defcellIS, &cells)); 5932 PetscCall(ISDestroy(&defcellIS)); 5933 PetscCall(DMPlexLabelComplete(plex, cellLabel)); 5934 5935 PetscCall(PetscMalloc1(Ndef, &fields)); 5936 for (f = 0; f < Nf; ++f) 5937 if (!dm->fields[f].label) fields[nf++] = f; 5938 PetscCall(ISCreate(PETSC_COMM_SELF, &fieldIS)); 5939 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fieldIS, "dm_fields_")); 5940 PetscCall(ISSetType(fieldIS, ISGENERAL)); 5941 PetscCall(ISGeneralSetIndices(fieldIS, nf, fields, PETSC_OWN_POINTER)); 5942 5943 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsDef)); 5944 PetscCall(DMSetRegionDS(dm, cellLabel, fieldIS, dsDef, NULL)); 5945 PetscCall(PetscDSSetCoordinateDimension(dsDef, dE)); 5946 PetscCall(DMLabelDestroy(&cellLabel)); 5947 PetscCall(PetscDSDestroy(&dsDef)); 5948 PetscCall(ISDestroy(&fieldIS)); 5949 PetscCall(DMDestroy(&plex)); 5950 } 5951 /* Create label DSes 5952 - WE ONLY SUPPORT IDENTICAL OR DISJOINT LABELS 5953 */ 5954 /* TODO Should check that labels are disjoint */ 5955 for (l = 0; l < Nl; ++l) { 5956 DMLabel label = labelSet[l]; 5957 PetscDS ds, dsIn = NULL; 5958 IS fields; 5959 PetscInt *fld, nf; 5960 5961 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &ds)); 5962 for (f = 0, nf = 0; f < Nf; ++f) 5963 if (label == dm->fields[f].label || !dm->fields[f].label) ++nf; 5964 PetscCall(PetscMalloc1(nf, &fld)); 5965 for (f = 0, nf = 0; f < Nf; ++f) 5966 if (label == dm->fields[f].label || !dm->fields[f].label) fld[nf++] = f; 5967 PetscCall(ISCreate(PETSC_COMM_SELF, &fields)); 5968 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)fields, "dm_fields_")); 5969 PetscCall(ISSetType(fields, ISGENERAL)); 5970 PetscCall(ISGeneralSetIndices(fields, nf, fld, PETSC_OWN_POINTER)); 5971 PetscCall(PetscDSSetCoordinateDimension(ds, dE)); 5972 { 5973 DMPolytopeType ct; 5974 PetscInt lStart, lEnd; 5975 PetscBool isCohesiveLocal = PETSC_FALSE, isCohesive; 5976 5977 PetscCall(DMLabelGetBounds(label, &lStart, &lEnd)); 5978 if (lStart >= 0) { 5979 PetscCall(DMPlexGetCellType(dm, lStart, &ct)); 5980 switch (ct) { 5981 case DM_POLYTOPE_POINT_PRISM_TENSOR: 5982 case DM_POLYTOPE_SEG_PRISM_TENSOR: 5983 case DM_POLYTOPE_TRI_PRISM_TENSOR: 5984 case DM_POLYTOPE_QUAD_PRISM_TENSOR: 5985 isCohesiveLocal = PETSC_TRUE; 5986 break; 5987 default: 5988 break; 5989 } 5990 } 5991 PetscCall(MPIU_Allreduce(&isCohesiveLocal, &isCohesive, 1, MPIU_BOOL, MPI_LOR, comm)); 5992 if (isCohesive) { 5993 PetscCall(PetscDSCreate(PETSC_COMM_SELF, &dsIn)); 5994 PetscCall(PetscDSSetCoordinateDimension(dsIn, dE)); 5995 } 5996 for (f = 0, nf = 0; f < Nf; ++f) { 5997 if (label == dm->fields[f].label || !dm->fields[f].label) { 5998 if (label == dm->fields[f].label) { 5999 PetscCall(PetscDSSetDiscretization(ds, nf, NULL)); 6000 PetscCall(PetscDSSetCohesive(ds, nf, isCohesive)); 6001 if (dsIn) { 6002 PetscCall(PetscDSSetDiscretization(dsIn, nf, NULL)); 6003 PetscCall(PetscDSSetCohesive(dsIn, nf, isCohesive)); 6004 } 6005 } 6006 ++nf; 6007 } 6008 } 6009 } 6010 PetscCall(DMSetRegionDS(dm, label, fields, ds, dsIn)); 6011 PetscCall(ISDestroy(&fields)); 6012 PetscCall(PetscDSDestroy(&ds)); 6013 PetscCall(PetscDSDestroy(&dsIn)); 6014 } 6015 PetscCall(PetscFree(labelSet)); 6016 /* Set fields in DSes */ 6017 for (s = 0; s < dm->Nds; ++s) { 6018 PetscDS ds = dm->probs[s].ds; 6019 PetscDS dsIn = dm->probs[s].dsIn; 6020 IS fields = dm->probs[s].fields; 6021 const PetscInt *fld; 6022 PetscInt nf, dsnf; 6023 PetscBool isCohesive; 6024 6025 PetscCall(PetscDSGetNumFields(ds, &dsnf)); 6026 PetscCall(PetscDSIsCohesive(ds, &isCohesive)); 6027 PetscCall(ISGetLocalSize(fields, &nf)); 6028 PetscCall(ISGetIndices(fields, &fld)); 6029 for (f = 0; f < nf; ++f) { 6030 PetscObject disc = dm->fields[fld[f]].disc; 6031 PetscBool isCohesiveField; 6032 PetscClassId id; 6033 6034 /* Handle DS with no fields */ 6035 if (dsnf) PetscCall(PetscDSGetCohesive(ds, f, &isCohesiveField)); 6036 /* If this is a cohesive cell, then regular fields need the lower dimensional discretization */ 6037 if (isCohesive) { 6038 if (!isCohesiveField) { 6039 PetscObject bdDisc; 6040 6041 PetscCall(PetscFEGetHeightSubspace((PetscFE)disc, 1, (PetscFE *)&bdDisc)); 6042 PetscCall(PetscDSSetDiscretization(ds, f, bdDisc)); 6043 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6044 } else { 6045 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6046 PetscCall(PetscDSSetDiscretization(dsIn, f, disc)); 6047 } 6048 } else { 6049 PetscCall(PetscDSSetDiscretization(ds, f, disc)); 6050 } 6051 /* We allow people to have placeholder fields and construct the Section by hand */ 6052 PetscCall(PetscObjectGetClassId(disc, &id)); 6053 if ((id != PETSCFE_CLASSID) && (id != PETSCFV_CLASSID)) doSetup = PETSC_FALSE; 6054 } 6055 PetscCall(ISRestoreIndices(fields, &fld)); 6056 } 6057 /* Allow k-jet tabulation */ 6058 PetscCall(PetscOptionsGetInt(NULL, ((PetscObject)dm)->prefix, "-dm_ds_jet_degree", &k, &flg)); 6059 if (flg) { 6060 for (s = 0; s < dm->Nds; ++s) { 6061 PetscDS ds = dm->probs[s].ds; 6062 PetscDS dsIn = dm->probs[s].dsIn; 6063 PetscInt Nf, f; 6064 6065 PetscCall(PetscDSGetNumFields(ds, &Nf)); 6066 for (f = 0; f < Nf; ++f) { 6067 PetscCall(PetscDSSetJetDegree(ds, f, k)); 6068 if (dsIn) PetscCall(PetscDSSetJetDegree(dsIn, f, k)); 6069 } 6070 } 6071 } 6072 /* Setup DSes */ 6073 if (doSetup) { 6074 for (s = 0; s < dm->Nds; ++s) { 6075 if (dm->setfromoptionscalled) { 6076 PetscCall(PetscDSSetFromOptions(dm->probs[s].ds)); 6077 if (dm->probs[s].dsIn) PetscCall(PetscDSSetFromOptions(dm->probs[s].dsIn)); 6078 } 6079 PetscCall(PetscDSSetUp(dm->probs[s].ds)); 6080 if (dm->probs[s].dsIn) PetscCall(PetscDSSetUp(dm->probs[s].dsIn)); 6081 } 6082 } 6083 PetscFunctionReturn(PETSC_SUCCESS); 6084 } 6085 6086 /*@ 6087 DMUseTensorOrder - Use a tensor product closure ordering for the default section 6088 6089 Input Parameters: 6090 + dm - The DM 6091 - tensor - Flag for tensor order 6092 6093 Level: developer 6094 6095 .seealso: `DMPlexSetClosurePermutationTensor()`, `PetscSectionResetClosurePermutation()` 6096 @*/ 6097 PetscErrorCode DMUseTensorOrder(DM dm, PetscBool tensor) 6098 { 6099 PetscInt Nf; 6100 PetscBool reorder = PETSC_TRUE, isPlex; 6101 6102 PetscFunctionBegin; 6103 PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex)); 6104 PetscCall(DMGetNumFields(dm, &Nf)); 6105 for (PetscInt f = 0; f < Nf; ++f) { 6106 PetscObject obj; 6107 PetscClassId id; 6108 6109 PetscCall(DMGetField(dm, f, NULL, &obj)); 6110 PetscCall(PetscObjectGetClassId(obj, &id)); 6111 if (id == PETSCFE_CLASSID) { 6112 PetscSpace sp; 6113 PetscBool tensor; 6114 6115 PetscCall(PetscFEGetBasisSpace((PetscFE)obj, &sp)); 6116 PetscCall(PetscSpacePolynomialGetTensor(sp, &tensor)); 6117 reorder = reorder && tensor ? PETSC_TRUE : PETSC_FALSE; 6118 } else reorder = PETSC_FALSE; 6119 } 6120 if (tensor) { 6121 if (reorder && isPlex) PetscCall(DMPlexSetClosurePermutationTensor(dm, PETSC_DETERMINE, NULL)); 6122 } else { 6123 PetscSection s; 6124 6125 PetscCall(DMGetLocalSection(dm, &s)); 6126 if (s) PetscCall(PetscSectionResetClosurePermutation(s)); 6127 } 6128 PetscFunctionReturn(PETSC_SUCCESS); 6129 } 6130 6131 /*@ 6132 DMComputeExactSolution - Compute the exact solution for a given `DM`, using the `PetscDS` information. 6133 6134 Collective 6135 6136 Input Parameters: 6137 + dm - The `DM` 6138 - time - The time 6139 6140 Output Parameters: 6141 + u - The vector will be filled with exact solution values, or `NULL` 6142 - u_t - The vector will be filled with the time derivative of exact solution values, or `NULL` 6143 6144 Level: developer 6145 6146 Note: 6147 The user must call `PetscDSSetExactSolution()` before using this routine 6148 6149 .seealso: [](ch_dmbase), `DM`, `PetscDSSetExactSolution()` 6150 @*/ 6151 PetscErrorCode DMComputeExactSolution(DM dm, PetscReal time, Vec u, Vec u_t) 6152 { 6153 PetscErrorCode (**exacts)(PetscInt, PetscReal, const PetscReal x[], PetscInt, PetscScalar *u, void *ctx); 6154 void **ectxs; 6155 Vec locu, locu_t; 6156 PetscInt Nf, Nds, s; 6157 6158 PetscFunctionBegin; 6159 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6160 if (u) { 6161 PetscValidHeaderSpecific(u, VEC_CLASSID, 3); 6162 PetscCall(DMGetLocalVector(dm, &locu)); 6163 PetscCall(VecSet(locu, 0.)); 6164 } 6165 if (u_t) { 6166 PetscValidHeaderSpecific(u_t, VEC_CLASSID, 4); 6167 PetscCall(DMGetLocalVector(dm, &locu_t)); 6168 PetscCall(VecSet(locu_t, 0.)); 6169 } 6170 PetscCall(DMGetNumFields(dm, &Nf)); 6171 PetscCall(PetscMalloc2(Nf, &exacts, Nf, &ectxs)); 6172 PetscCall(DMGetNumDS(dm, &Nds)); 6173 for (s = 0; s < Nds; ++s) { 6174 PetscDS ds; 6175 DMLabel label; 6176 IS fieldIS; 6177 const PetscInt *fields, id = 1; 6178 PetscInt dsNf, f; 6179 6180 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 6181 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 6182 PetscCall(ISGetIndices(fieldIS, &fields)); 6183 PetscCall(PetscArrayzero(exacts, Nf)); 6184 PetscCall(PetscArrayzero(ectxs, Nf)); 6185 if (u) { 6186 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolution(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6187 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6188 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu)); 6189 } 6190 if (u_t) { 6191 PetscCall(PetscArrayzero(exacts, Nf)); 6192 PetscCall(PetscArrayzero(ectxs, Nf)); 6193 for (f = 0; f < dsNf; ++f) PetscCall(PetscDSGetExactSolutionTimeDerivative(ds, fields[f], &exacts[fields[f]], &ectxs[fields[f]])); 6194 if (label) PetscCall(DMProjectFunctionLabelLocal(dm, time, label, 1, &id, 0, NULL, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6195 else PetscCall(DMProjectFunctionLocal(dm, time, exacts, ectxs, INSERT_ALL_VALUES, locu_t)); 6196 } 6197 PetscCall(ISRestoreIndices(fieldIS, &fields)); 6198 } 6199 if (u) { 6200 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution")); 6201 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u, "exact_")); 6202 } 6203 if (u_t) { 6204 PetscCall(PetscObjectSetName((PetscObject)u, "Exact Solution Time Derivative")); 6205 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)u_t, "exact_t_")); 6206 } 6207 PetscCall(PetscFree2(exacts, ectxs)); 6208 if (u) { 6209 PetscCall(DMLocalToGlobalBegin(dm, locu, INSERT_ALL_VALUES, u)); 6210 PetscCall(DMLocalToGlobalEnd(dm, locu, INSERT_ALL_VALUES, u)); 6211 PetscCall(DMRestoreLocalVector(dm, &locu)); 6212 } 6213 if (u_t) { 6214 PetscCall(DMLocalToGlobalBegin(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6215 PetscCall(DMLocalToGlobalEnd(dm, locu_t, INSERT_ALL_VALUES, u_t)); 6216 PetscCall(DMRestoreLocalVector(dm, &locu_t)); 6217 } 6218 PetscFunctionReturn(PETSC_SUCCESS); 6219 } 6220 6221 static PetscErrorCode DMTransferDS_Internal(DM dm, DMLabel label, IS fields, PetscDS ds, PetscDS dsIn) 6222 { 6223 PetscDS dsNew, dsInNew = NULL; 6224 6225 PetscFunctionBegin; 6226 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)ds), &dsNew)); 6227 PetscCall(PetscDSCopy(ds, dm, dsNew)); 6228 if (dsIn) { 6229 PetscCall(PetscDSCreate(PetscObjectComm((PetscObject)dsIn), &dsInNew)); 6230 PetscCall(PetscDSCopy(dsIn, dm, dsInNew)); 6231 } 6232 PetscCall(DMSetRegionDS(dm, label, fields, dsNew, dsInNew)); 6233 PetscCall(PetscDSDestroy(&dsNew)); 6234 PetscCall(PetscDSDestroy(&dsInNew)); 6235 PetscFunctionReturn(PETSC_SUCCESS); 6236 } 6237 6238 /*@ 6239 DMCopyDS - Copy the discrete systems for the `DM` into another `DM` 6240 6241 Collective 6242 6243 Input Parameter: 6244 . dm - The `DM` 6245 6246 Output Parameter: 6247 . newdm - The `DM` 6248 6249 Level: advanced 6250 6251 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMAddField()`, `DMGetDS()`, `DMGetCellDS()`, `DMGetRegionDS()`, `DMSetRegionDS()` 6252 @*/ 6253 PetscErrorCode DMCopyDS(DM dm, DM newdm) 6254 { 6255 PetscInt Nds, s; 6256 6257 PetscFunctionBegin; 6258 if (dm == newdm) PetscFunctionReturn(PETSC_SUCCESS); 6259 PetscCall(DMGetNumDS(dm, &Nds)); 6260 PetscCall(DMClearDS(newdm)); 6261 for (s = 0; s < Nds; ++s) { 6262 DMLabel label; 6263 IS fields; 6264 PetscDS ds, dsIn, newds; 6265 PetscInt Nbd, bd; 6266 6267 PetscCall(DMGetRegionNumDS(dm, s, &label, &fields, &ds, &dsIn)); 6268 /* TODO: We need to change all keys from labels in the old DM to labels in the new DM */ 6269 PetscCall(DMTransferDS_Internal(newdm, label, fields, ds, dsIn)); 6270 /* Complete new labels in the new DS */ 6271 PetscCall(DMGetRegionDS(newdm, label, NULL, &newds, NULL)); 6272 PetscCall(PetscDSGetNumBoundary(newds, &Nbd)); 6273 for (bd = 0; bd < Nbd; ++bd) { 6274 PetscWeakForm wf; 6275 DMLabel label; 6276 PetscInt field; 6277 6278 PetscCall(PetscDSGetBoundary(newds, bd, &wf, NULL, NULL, &label, NULL, NULL, &field, NULL, NULL, NULL, NULL, NULL)); 6279 PetscCall(PetscWeakFormReplaceLabel(wf, label)); 6280 } 6281 } 6282 PetscCall(DMCompleteBCLabels_Internal(newdm)); 6283 PetscFunctionReturn(PETSC_SUCCESS); 6284 } 6285 6286 /*@ 6287 DMCopyDisc - Copy the fields and discrete systems for the `DM` into another `DM` 6288 6289 Collective 6290 6291 Input Parameter: 6292 . dm - The `DM` 6293 6294 Output Parameter: 6295 . newdm - The `DM` 6296 6297 Level: advanced 6298 6299 Developer Notes: 6300 Really ugly name, nothing in PETSc is called a `Disc` plus it is an ugly abbreviation 6301 6302 .seealso: [](ch_dmbase), `DM`, `DMCopyFields()`, `DMCopyDS()` 6303 @*/ 6304 PetscErrorCode DMCopyDisc(DM dm, DM newdm) 6305 { 6306 PetscFunctionBegin; 6307 PetscCall(DMCopyFields(dm, newdm)); 6308 PetscCall(DMCopyDS(dm, newdm)); 6309 PetscFunctionReturn(PETSC_SUCCESS); 6310 } 6311 6312 /*@ 6313 DMGetDimension - Return the topological dimension of the `DM` 6314 6315 Not Collective 6316 6317 Input Parameter: 6318 . dm - The `DM` 6319 6320 Output Parameter: 6321 . dim - The topological dimension 6322 6323 Level: beginner 6324 6325 .seealso: [](ch_dmbase), `DM`, `DMSetDimension()`, `DMCreate()` 6326 @*/ 6327 PetscErrorCode DMGetDimension(DM dm, PetscInt *dim) 6328 { 6329 PetscFunctionBegin; 6330 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6331 PetscAssertPointer(dim, 2); 6332 *dim = dm->dim; 6333 PetscFunctionReturn(PETSC_SUCCESS); 6334 } 6335 6336 /*@ 6337 DMSetDimension - Set the topological dimension of the `DM` 6338 6339 Collective 6340 6341 Input Parameters: 6342 + dm - The `DM` 6343 - dim - The topological dimension 6344 6345 Level: beginner 6346 6347 .seealso: [](ch_dmbase), `DM`, `DMGetDimension()`, `DMCreate()` 6348 @*/ 6349 PetscErrorCode DMSetDimension(DM dm, PetscInt dim) 6350 { 6351 PetscDS ds; 6352 PetscInt Nds, n; 6353 6354 PetscFunctionBegin; 6355 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6356 PetscValidLogicalCollectiveInt(dm, dim, 2); 6357 dm->dim = dim; 6358 if (dm->dim >= 0) { 6359 PetscCall(DMGetNumDS(dm, &Nds)); 6360 for (n = 0; n < Nds; ++n) { 6361 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 6362 if (ds->dimEmbed < 0) PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 6363 } 6364 } 6365 PetscFunctionReturn(PETSC_SUCCESS); 6366 } 6367 6368 /*@ 6369 DMGetDimPoints - Get the half-open interval for all points of a given dimension 6370 6371 Collective 6372 6373 Input Parameters: 6374 + dm - the `DM` 6375 - dim - the dimension 6376 6377 Output Parameters: 6378 + pStart - The first point of the given dimension 6379 - pEnd - The first point following points of the given dimension 6380 6381 Level: intermediate 6382 6383 Note: 6384 The points are vertices in the Hasse diagram encoding the topology. This is explained in 6385 https://arxiv.org/abs/0908.4427. If no points exist of this dimension in the storage scheme, 6386 then the interval is empty. 6387 6388 .seealso: [](ch_dmbase), `DM`, `DMPLEX`, `DMPlexGetDepthStratum()`, `DMPlexGetHeightStratum()` 6389 @*/ 6390 PetscErrorCode DMGetDimPoints(DM dm, PetscInt dim, PetscInt *pStart, PetscInt *pEnd) 6391 { 6392 PetscInt d; 6393 6394 PetscFunctionBegin; 6395 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6396 PetscCall(DMGetDimension(dm, &d)); 6397 PetscCheck((dim >= 0) && (dim <= d), PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid dimension %" PetscInt_FMT, dim); 6398 PetscUseTypeMethod(dm, getdimpoints, dim, pStart, pEnd); 6399 PetscFunctionReturn(PETSC_SUCCESS); 6400 } 6401 6402 /*@ 6403 DMGetOutputDM - Retrieve the `DM` associated with the layout for output 6404 6405 Collective 6406 6407 Input Parameter: 6408 . dm - The original `DM` 6409 6410 Output Parameter: 6411 . odm - The `DM` which provides the layout for output 6412 6413 Level: intermediate 6414 6415 Note: 6416 In some situations the vector obtained with `DMCreateGlobalVector()` excludes points for degrees of freedom that are associated with fixed (Dirichelet) boundary 6417 conditions since the algebraic solver does not solve for those variables. The output `DM` includes these excluded points and its global vector contains the 6418 locations for those dof so that they can be output to a file or other viewer along with the unconstrained dof. 6419 6420 .seealso: [](ch_dmbase), `DM`, `VecView()`, `DMGetGlobalSection()`, `DMCreateGlobalVector()`, `PetscSectionHasConstraints()`, `DMSetGlobalSection()` 6421 @*/ 6422 PetscErrorCode DMGetOutputDM(DM dm, DM *odm) 6423 { 6424 PetscSection section; 6425 IS perm; 6426 PetscBool hasConstraints, newDM, gnewDM; 6427 6428 PetscFunctionBegin; 6429 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6430 PetscAssertPointer(odm, 2); 6431 PetscCall(DMGetLocalSection(dm, §ion)); 6432 PetscCall(PetscSectionHasConstraints(section, &hasConstraints)); 6433 PetscCall(PetscSectionGetPermutation(section, &perm)); 6434 newDM = hasConstraints || perm ? PETSC_TRUE : PETSC_FALSE; 6435 PetscCall(MPIU_Allreduce(&newDM, &gnewDM, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm))); 6436 if (!gnewDM) { 6437 *odm = dm; 6438 PetscFunctionReturn(PETSC_SUCCESS); 6439 } 6440 if (!dm->dmBC) { 6441 PetscSection newSection, gsection; 6442 PetscSF sf; 6443 PetscBool usePerm = dm->ignorePermOutput ? PETSC_FALSE : PETSC_TRUE; 6444 6445 PetscCall(DMClone(dm, &dm->dmBC)); 6446 PetscCall(DMCopyDisc(dm, dm->dmBC)); 6447 PetscCall(PetscSectionClone(section, &newSection)); 6448 PetscCall(DMSetLocalSection(dm->dmBC, newSection)); 6449 PetscCall(PetscSectionDestroy(&newSection)); 6450 PetscCall(DMGetPointSF(dm->dmBC, &sf)); 6451 PetscCall(PetscSectionCreateGlobalSection(section, sf, usePerm, PETSC_TRUE, PETSC_FALSE, &gsection)); 6452 PetscCall(DMSetGlobalSection(dm->dmBC, gsection)); 6453 PetscCall(PetscSectionDestroy(&gsection)); 6454 } 6455 *odm = dm->dmBC; 6456 PetscFunctionReturn(PETSC_SUCCESS); 6457 } 6458 6459 /*@ 6460 DMGetOutputSequenceNumber - Retrieve the sequence number/value for output 6461 6462 Input Parameter: 6463 . dm - The original `DM` 6464 6465 Output Parameters: 6466 + num - The output sequence number 6467 - val - The output sequence value 6468 6469 Level: intermediate 6470 6471 Note: 6472 This is intended for output that should appear in sequence, for instance 6473 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6474 6475 Developer Notes: 6476 The `DM` serves as a convenient place to store the current iteration value. The iteration is not 6477 not directly related to the `DM`. 6478 6479 .seealso: [](ch_dmbase), `DM`, `VecView()` 6480 @*/ 6481 PetscErrorCode DMGetOutputSequenceNumber(DM dm, PetscInt *num, PetscReal *val) 6482 { 6483 PetscFunctionBegin; 6484 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6485 if (num) { 6486 PetscAssertPointer(num, 2); 6487 *num = dm->outputSequenceNum; 6488 } 6489 if (val) { 6490 PetscAssertPointer(val, 3); 6491 *val = dm->outputSequenceVal; 6492 } 6493 PetscFunctionReturn(PETSC_SUCCESS); 6494 } 6495 6496 /*@ 6497 DMSetOutputSequenceNumber - Set the sequence number/value for output 6498 6499 Input Parameters: 6500 + dm - The original `DM` 6501 . num - The output sequence number 6502 - val - The output sequence value 6503 6504 Level: intermediate 6505 6506 Note: 6507 This is intended for output that should appear in sequence, for instance 6508 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6509 6510 .seealso: [](ch_dmbase), `DM`, `VecView()` 6511 @*/ 6512 PetscErrorCode DMSetOutputSequenceNumber(DM dm, PetscInt num, PetscReal val) 6513 { 6514 PetscFunctionBegin; 6515 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6516 dm->outputSequenceNum = num; 6517 dm->outputSequenceVal = val; 6518 PetscFunctionReturn(PETSC_SUCCESS); 6519 } 6520 6521 /*@C 6522 DMOutputSequenceLoad - Retrieve the sequence value from a `PetscViewer` 6523 6524 Input Parameters: 6525 + dm - The original `DM` 6526 . viewer - The viewer to get it from 6527 . name - The sequence name 6528 - num - The output sequence number 6529 6530 Output Parameter: 6531 . val - The output sequence value 6532 6533 Level: intermediate 6534 6535 Note: 6536 This is intended for output that should appear in sequence, for instance 6537 a set of timesteps in an `PETSCVIEWERHDF5` file, or a set of realizations of a stochastic system. 6538 6539 Developer Notes: 6540 It is unclear at the user API level why a `DM` is needed as input 6541 6542 .seealso: [](ch_dmbase), `DM`, `DMGetOutputSequenceNumber()`, `DMSetOutputSequenceNumber()`, `VecView()` 6543 @*/ 6544 PetscErrorCode DMOutputSequenceLoad(DM dm, PetscViewer viewer, const char *name, PetscInt num, PetscReal *val) 6545 { 6546 PetscBool ishdf5; 6547 6548 PetscFunctionBegin; 6549 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6550 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 6551 PetscAssertPointer(val, 5); 6552 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5)); 6553 if (ishdf5) { 6554 #if defined(PETSC_HAVE_HDF5) 6555 PetscScalar value; 6556 6557 PetscCall(DMSequenceLoad_HDF5_Internal(dm, name, num, &value, viewer)); 6558 *val = PetscRealPart(value); 6559 #endif 6560 } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Invalid viewer; open viewer with PetscViewerHDF5Open()"); 6561 PetscFunctionReturn(PETSC_SUCCESS); 6562 } 6563 6564 /*@ 6565 DMGetUseNatural - Get the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6566 6567 Not Collective 6568 6569 Input Parameter: 6570 . dm - The `DM` 6571 6572 Output Parameter: 6573 . useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6574 6575 Level: beginner 6576 6577 .seealso: [](ch_dmbase), `DM`, `DMSetUseNatural()`, `DMCreate()` 6578 @*/ 6579 PetscErrorCode DMGetUseNatural(DM dm, PetscBool *useNatural) 6580 { 6581 PetscFunctionBegin; 6582 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6583 PetscAssertPointer(useNatural, 2); 6584 *useNatural = dm->useNatural; 6585 PetscFunctionReturn(PETSC_SUCCESS); 6586 } 6587 6588 /*@ 6589 DMSetUseNatural - Set the flag for creating a mapping to the natural order when a `DM` is (re)distributed in parallel 6590 6591 Collective 6592 6593 Input Parameters: 6594 + dm - The `DM` 6595 - useNatural - `PETSC_TRUE` to build the mapping to a natural order during distribution 6596 6597 Note: 6598 This also causes the map to be build after `DMCreateSubDM()` and `DMCreateSuperDM()` 6599 6600 Level: beginner 6601 6602 .seealso: [](ch_dmbase), `DM`, `DMGetUseNatural()`, `DMCreate()`, `DMPlexDistribute()`, `DMCreateSubDM()`, `DMCreateSuperDM()` 6603 @*/ 6604 PetscErrorCode DMSetUseNatural(DM dm, PetscBool useNatural) 6605 { 6606 PetscFunctionBegin; 6607 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6608 PetscValidLogicalCollectiveBool(dm, useNatural, 2); 6609 dm->useNatural = useNatural; 6610 PetscFunctionReturn(PETSC_SUCCESS); 6611 } 6612 6613 /*@C 6614 DMCreateLabel - Create a label of the given name if it does not already exist in the `DM` 6615 6616 Not Collective 6617 6618 Input Parameters: 6619 + dm - The `DM` object 6620 - name - The label name 6621 6622 Level: intermediate 6623 6624 .seealso: [](ch_dmbase), `DM`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6625 @*/ 6626 PetscErrorCode DMCreateLabel(DM dm, const char name[]) 6627 { 6628 PetscBool flg; 6629 DMLabel label; 6630 6631 PetscFunctionBegin; 6632 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6633 PetscAssertPointer(name, 2); 6634 PetscCall(DMHasLabel(dm, name, &flg)); 6635 if (!flg) { 6636 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6637 PetscCall(DMAddLabel(dm, label)); 6638 PetscCall(DMLabelDestroy(&label)); 6639 } 6640 PetscFunctionReturn(PETSC_SUCCESS); 6641 } 6642 6643 /*@C 6644 DMCreateLabelAtIndex - Create a label of the given name at the given index. If it already exists in the `DM`, move it to this index. 6645 6646 Not Collective 6647 6648 Input Parameters: 6649 + dm - The `DM` object 6650 . l - The index for the label 6651 - name - The label name 6652 6653 Level: intermediate 6654 6655 .seealso: [](ch_dmbase), `DM`, `DMCreateLabel()`, `DMLabelCreate()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6656 @*/ 6657 PetscErrorCode DMCreateLabelAtIndex(DM dm, PetscInt l, const char name[]) 6658 { 6659 DMLabelLink orig, prev = NULL; 6660 DMLabel label; 6661 PetscInt Nl, m; 6662 PetscBool flg, match; 6663 const char *lname; 6664 6665 PetscFunctionBegin; 6666 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6667 PetscAssertPointer(name, 3); 6668 PetscCall(DMHasLabel(dm, name, &flg)); 6669 if (!flg) { 6670 PetscCall(DMLabelCreate(PETSC_COMM_SELF, name, &label)); 6671 PetscCall(DMAddLabel(dm, label)); 6672 PetscCall(DMLabelDestroy(&label)); 6673 } 6674 PetscCall(DMGetNumLabels(dm, &Nl)); 6675 PetscCheck(l < Nl, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label index %" PetscInt_FMT " must be in [0, %" PetscInt_FMT ")", l, Nl); 6676 for (m = 0, orig = dm->labels; m < Nl; ++m, prev = orig, orig = orig->next) { 6677 PetscCall(PetscObjectGetName((PetscObject)orig->label, &lname)); 6678 PetscCall(PetscStrcmp(name, lname, &match)); 6679 if (match) break; 6680 } 6681 if (m == l) PetscFunctionReturn(PETSC_SUCCESS); 6682 if (!m) dm->labels = orig->next; 6683 else prev->next = orig->next; 6684 if (!l) { 6685 orig->next = dm->labels; 6686 dm->labels = orig; 6687 } else { 6688 for (m = 0, prev = dm->labels; m < l - 1; ++m, prev = prev->next) 6689 ; 6690 orig->next = prev->next; 6691 prev->next = orig; 6692 } 6693 PetscFunctionReturn(PETSC_SUCCESS); 6694 } 6695 6696 /*@C 6697 DMGetLabelValue - Get the value in a `DMLabel` for the given point, with -1 as the default 6698 6699 Not Collective 6700 6701 Input Parameters: 6702 + dm - The `DM` object 6703 . name - The label name 6704 - point - The mesh point 6705 6706 Output Parameter: 6707 . value - The label value for this point, or -1 if the point is not in the label 6708 6709 Level: beginner 6710 6711 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6712 @*/ 6713 PetscErrorCode DMGetLabelValue(DM dm, const char name[], PetscInt point, PetscInt *value) 6714 { 6715 DMLabel label; 6716 6717 PetscFunctionBegin; 6718 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6719 PetscAssertPointer(name, 2); 6720 PetscCall(DMGetLabel(dm, name, &label)); 6721 PetscCheck(label, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No label named %s was found", name); 6722 PetscCall(DMLabelGetValue(label, point, value)); 6723 PetscFunctionReturn(PETSC_SUCCESS); 6724 } 6725 6726 /*@C 6727 DMSetLabelValue - Add a point to a `DMLabel` with given value 6728 6729 Not Collective 6730 6731 Input Parameters: 6732 + dm - The `DM` object 6733 . name - The label name 6734 . point - The mesh point 6735 - value - The label value for this point 6736 6737 Output Parameter: 6738 6739 Level: beginner 6740 6741 .seealso: [](ch_dmbase), `DM`, `DMLabelSetValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6742 @*/ 6743 PetscErrorCode DMSetLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6744 { 6745 DMLabel label; 6746 6747 PetscFunctionBegin; 6748 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6749 PetscAssertPointer(name, 2); 6750 PetscCall(DMGetLabel(dm, name, &label)); 6751 if (!label) { 6752 PetscCall(DMCreateLabel(dm, name)); 6753 PetscCall(DMGetLabel(dm, name, &label)); 6754 } 6755 PetscCall(DMLabelSetValue(label, point, value)); 6756 PetscFunctionReturn(PETSC_SUCCESS); 6757 } 6758 6759 /*@C 6760 DMClearLabelValue - Remove a point from a `DMLabel` with given value 6761 6762 Not Collective 6763 6764 Input Parameters: 6765 + dm - The `DM` object 6766 . name - The label name 6767 . point - The mesh point 6768 - value - The label value for this point 6769 6770 Level: beginner 6771 6772 .seealso: [](ch_dmbase), `DM`, `DMLabelClearValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6773 @*/ 6774 PetscErrorCode DMClearLabelValue(DM dm, const char name[], PetscInt point, PetscInt value) 6775 { 6776 DMLabel label; 6777 6778 PetscFunctionBegin; 6779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6780 PetscAssertPointer(name, 2); 6781 PetscCall(DMGetLabel(dm, name, &label)); 6782 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6783 PetscCall(DMLabelClearValue(label, point, value)); 6784 PetscFunctionReturn(PETSC_SUCCESS); 6785 } 6786 6787 /*@C 6788 DMGetLabelSize - Get the value of `DMLabelGetNumValues()` of a `DMLabel` in the `DM` 6789 6790 Not Collective 6791 6792 Input Parameters: 6793 + dm - The `DM` object 6794 - name - The label name 6795 6796 Output Parameter: 6797 . size - The number of different integer ids, or 0 if the label does not exist 6798 6799 Level: beginner 6800 6801 Developer Notes: 6802 This should be renamed to something like `DMGetLabelNumValues()` or removed. 6803 6804 .seealso: [](ch_dmbase), `DM`, `DMLabelGetNumValues()`, `DMSetLabelValue()`, `DMGetLabel()` 6805 @*/ 6806 PetscErrorCode DMGetLabelSize(DM dm, const char name[], PetscInt *size) 6807 { 6808 DMLabel label; 6809 6810 PetscFunctionBegin; 6811 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6812 PetscAssertPointer(name, 2); 6813 PetscAssertPointer(size, 3); 6814 PetscCall(DMGetLabel(dm, name, &label)); 6815 *size = 0; 6816 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6817 PetscCall(DMLabelGetNumValues(label, size)); 6818 PetscFunctionReturn(PETSC_SUCCESS); 6819 } 6820 6821 /*@C 6822 DMGetLabelIdIS - Get the `DMLabelGetValueIS()` from a `DMLabel` in the `DM` 6823 6824 Not Collective 6825 6826 Input Parameters: 6827 + dm - The `DM` object 6828 - name - The label name 6829 6830 Output Parameter: 6831 . ids - The integer ids, or `NULL` if the label does not exist 6832 6833 Level: beginner 6834 6835 .seealso: [](ch_dmbase), `DM`, `DMLabelGetValueIS()`, `DMGetLabelSize()` 6836 @*/ 6837 PetscErrorCode DMGetLabelIdIS(DM dm, const char name[], IS *ids) 6838 { 6839 DMLabel label; 6840 6841 PetscFunctionBegin; 6842 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6843 PetscAssertPointer(name, 2); 6844 PetscAssertPointer(ids, 3); 6845 PetscCall(DMGetLabel(dm, name, &label)); 6846 *ids = NULL; 6847 if (label) { 6848 PetscCall(DMLabelGetValueIS(label, ids)); 6849 } else { 6850 /* returning an empty IS */ 6851 PetscCall(ISCreateGeneral(PETSC_COMM_SELF, 0, NULL, PETSC_USE_POINTER, ids)); 6852 } 6853 PetscFunctionReturn(PETSC_SUCCESS); 6854 } 6855 6856 /*@C 6857 DMGetStratumSize - Get the number of points in a label stratum 6858 6859 Not Collective 6860 6861 Input Parameters: 6862 + dm - The `DM` object 6863 . name - The label name 6864 - value - The stratum value 6865 6866 Output Parameter: 6867 . size - The number of points, also called the stratum size 6868 6869 Level: beginner 6870 6871 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumSize()`, `DMGetLabelSize()`, `DMGetLabelIds()` 6872 @*/ 6873 PetscErrorCode DMGetStratumSize(DM dm, const char name[], PetscInt value, PetscInt *size) 6874 { 6875 DMLabel label; 6876 6877 PetscFunctionBegin; 6878 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6879 PetscAssertPointer(name, 2); 6880 PetscAssertPointer(size, 4); 6881 PetscCall(DMGetLabel(dm, name, &label)); 6882 *size = 0; 6883 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6884 PetscCall(DMLabelGetStratumSize(label, value, size)); 6885 PetscFunctionReturn(PETSC_SUCCESS); 6886 } 6887 6888 /*@C 6889 DMGetStratumIS - Get the points in a label stratum 6890 6891 Not Collective 6892 6893 Input Parameters: 6894 + dm - The `DM` object 6895 . name - The label name 6896 - value - The stratum value 6897 6898 Output Parameter: 6899 . points - The stratum points, or `NULL` if the label does not exist or does not have that value 6900 6901 Level: beginner 6902 6903 .seealso: [](ch_dmbase), `DM`, `DMLabelGetStratumIS()`, `DMGetStratumSize()` 6904 @*/ 6905 PetscErrorCode DMGetStratumIS(DM dm, const char name[], PetscInt value, IS *points) 6906 { 6907 DMLabel label; 6908 6909 PetscFunctionBegin; 6910 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6911 PetscAssertPointer(name, 2); 6912 PetscAssertPointer(points, 4); 6913 PetscCall(DMGetLabel(dm, name, &label)); 6914 *points = NULL; 6915 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6916 PetscCall(DMLabelGetStratumIS(label, value, points)); 6917 PetscFunctionReturn(PETSC_SUCCESS); 6918 } 6919 6920 /*@C 6921 DMSetStratumIS - Set the points in a label stratum 6922 6923 Not Collective 6924 6925 Input Parameters: 6926 + dm - The `DM` object 6927 . name - The label name 6928 . value - The stratum value 6929 - points - The stratum points 6930 6931 Level: beginner 6932 6933 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMClearLabelStratum()`, `DMLabelClearStratum()`, `DMLabelSetStratumIS()`, `DMGetStratumSize()` 6934 @*/ 6935 PetscErrorCode DMSetStratumIS(DM dm, const char name[], PetscInt value, IS points) 6936 { 6937 DMLabel label; 6938 6939 PetscFunctionBegin; 6940 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6941 PetscAssertPointer(name, 2); 6942 PetscValidHeaderSpecific(points, IS_CLASSID, 4); 6943 PetscCall(DMGetLabel(dm, name, &label)); 6944 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6945 PetscCall(DMLabelSetStratumIS(label, value, points)); 6946 PetscFunctionReturn(PETSC_SUCCESS); 6947 } 6948 6949 /*@C 6950 DMClearLabelStratum - Remove all points from a stratum from a `DMLabel` 6951 6952 Not Collective 6953 6954 Input Parameters: 6955 + dm - The `DM` object 6956 . name - The label name 6957 - value - The label value for this point 6958 6959 Output Parameter: 6960 6961 Level: beginner 6962 6963 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMLabelClearStratum()`, `DMSetLabelValue()`, `DMGetStratumIS()`, `DMClearLabelValue()` 6964 @*/ 6965 PetscErrorCode DMClearLabelStratum(DM dm, const char name[], PetscInt value) 6966 { 6967 DMLabel label; 6968 6969 PetscFunctionBegin; 6970 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 6971 PetscAssertPointer(name, 2); 6972 PetscCall(DMGetLabel(dm, name, &label)); 6973 if (!label) PetscFunctionReturn(PETSC_SUCCESS); 6974 PetscCall(DMLabelClearStratum(label, value)); 6975 PetscFunctionReturn(PETSC_SUCCESS); 6976 } 6977 6978 /*@ 6979 DMGetNumLabels - Return the number of labels defined by on the `DM` 6980 6981 Not Collective 6982 6983 Input Parameter: 6984 . dm - The `DM` object 6985 6986 Output Parameter: 6987 . numLabels - the number of Labels 6988 6989 Level: intermediate 6990 6991 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabelName()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 6992 @*/ 6993 PetscErrorCode DMGetNumLabels(DM dm, PetscInt *numLabels) 6994 { 6995 DMLabelLink next = dm->labels; 6996 PetscInt n = 0; 6997 6998 PetscFunctionBegin; 6999 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7000 PetscAssertPointer(numLabels, 2); 7001 while (next) { 7002 ++n; 7003 next = next->next; 7004 } 7005 *numLabels = n; 7006 PetscFunctionReturn(PETSC_SUCCESS); 7007 } 7008 7009 /*@C 7010 DMGetLabelName - Return the name of nth label 7011 7012 Not Collective 7013 7014 Input Parameters: 7015 + dm - The `DM` object 7016 - n - the label number 7017 7018 Output Parameter: 7019 . name - the label name 7020 7021 Level: intermediate 7022 7023 Developer Notes: 7024 Some of the functions that appropriate on labels using their number have the suffix ByNum, others do not. 7025 7026 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabelByNum()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7027 @*/ 7028 PetscErrorCode DMGetLabelName(DM dm, PetscInt n, const char **name) 7029 { 7030 DMLabelLink next = dm->labels; 7031 PetscInt l = 0; 7032 7033 PetscFunctionBegin; 7034 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7035 PetscAssertPointer(name, 3); 7036 while (next) { 7037 if (l == n) { 7038 PetscCall(PetscObjectGetName((PetscObject)next->label, name)); 7039 PetscFunctionReturn(PETSC_SUCCESS); 7040 } 7041 ++l; 7042 next = next->next; 7043 } 7044 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7045 } 7046 7047 /*@C 7048 DMHasLabel - Determine whether the `DM` has a label of a given name 7049 7050 Not Collective 7051 7052 Input Parameters: 7053 + dm - The `DM` object 7054 - name - The label name 7055 7056 Output Parameter: 7057 . hasLabel - `PETSC_TRUE` if the label is present 7058 7059 Level: intermediate 7060 7061 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetLabel()`, `DMGetLabelByNum()`, `DMCreateLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7062 @*/ 7063 PetscErrorCode DMHasLabel(DM dm, const char name[], PetscBool *hasLabel) 7064 { 7065 DMLabelLink next = dm->labels; 7066 const char *lname; 7067 7068 PetscFunctionBegin; 7069 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7070 PetscAssertPointer(name, 2); 7071 PetscAssertPointer(hasLabel, 3); 7072 *hasLabel = PETSC_FALSE; 7073 while (next) { 7074 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7075 PetscCall(PetscStrcmp(name, lname, hasLabel)); 7076 if (*hasLabel) break; 7077 next = next->next; 7078 } 7079 PetscFunctionReturn(PETSC_SUCCESS); 7080 } 7081 7082 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7083 /*@C 7084 DMGetLabel - Return the label of a given name, or `NULL`, from a `DM` 7085 7086 Not Collective 7087 7088 Input Parameters: 7089 + dm - The `DM` object 7090 - name - The label name 7091 7092 Output Parameter: 7093 . label - The `DMLabel`, or `NULL` if the label is absent 7094 7095 Default labels in a `DMPLEX`: 7096 + "depth" - Holds the depth (co-dimension) of each mesh point 7097 . "celltype" - Holds the topological type of each cell 7098 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7099 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7100 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7101 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7102 7103 Level: intermediate 7104 7105 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMHasLabel()`, `DMGetLabelByNum()`, `DMAddLabel()`, `DMCreateLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7106 @*/ 7107 PetscErrorCode DMGetLabel(DM dm, const char name[], DMLabel *label) 7108 { 7109 DMLabelLink next = dm->labels; 7110 PetscBool hasLabel; 7111 const char *lname; 7112 7113 PetscFunctionBegin; 7114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7115 PetscAssertPointer(name, 2); 7116 PetscAssertPointer(label, 3); 7117 *label = NULL; 7118 while (next) { 7119 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7120 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7121 if (hasLabel) { 7122 *label = next->label; 7123 break; 7124 } 7125 next = next->next; 7126 } 7127 PetscFunctionReturn(PETSC_SUCCESS); 7128 } 7129 7130 /*@C 7131 DMGetLabelByNum - Return the nth label on a `DM` 7132 7133 Not Collective 7134 7135 Input Parameters: 7136 + dm - The `DM` object 7137 - n - the label number 7138 7139 Output Parameter: 7140 . label - the label 7141 7142 Level: intermediate 7143 7144 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7145 @*/ 7146 PetscErrorCode DMGetLabelByNum(DM dm, PetscInt n, DMLabel *label) 7147 { 7148 DMLabelLink next = dm->labels; 7149 PetscInt l = 0; 7150 7151 PetscFunctionBegin; 7152 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7153 PetscAssertPointer(label, 3); 7154 while (next) { 7155 if (l == n) { 7156 *label = next->label; 7157 PetscFunctionReturn(PETSC_SUCCESS); 7158 } 7159 ++l; 7160 next = next->next; 7161 } 7162 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %" PetscInt_FMT " does not exist in this DM", n); 7163 } 7164 7165 /*@C 7166 DMAddLabel - Add the label to this `DM` 7167 7168 Not Collective 7169 7170 Input Parameters: 7171 + dm - The `DM` object 7172 - label - The `DMLabel` 7173 7174 Level: developer 7175 7176 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7177 @*/ 7178 PetscErrorCode DMAddLabel(DM dm, DMLabel label) 7179 { 7180 DMLabelLink l, *p, tmpLabel; 7181 PetscBool hasLabel; 7182 const char *lname; 7183 PetscBool flg; 7184 7185 PetscFunctionBegin; 7186 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7187 PetscCall(PetscObjectGetName((PetscObject)label, &lname)); 7188 PetscCall(DMHasLabel(dm, lname, &hasLabel)); 7189 PetscCheck(!hasLabel, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in this DM", lname); 7190 PetscCall(PetscCalloc1(1, &tmpLabel)); 7191 tmpLabel->label = label; 7192 tmpLabel->output = PETSC_TRUE; 7193 for (p = &dm->labels; (l = *p); p = &l->next) { } 7194 *p = tmpLabel; 7195 PetscCall(PetscObjectReference((PetscObject)label)); 7196 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7197 if (flg) dm->depthLabel = label; 7198 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7199 if (flg) dm->celltypeLabel = label; 7200 PetscFunctionReturn(PETSC_SUCCESS); 7201 } 7202 7203 // PetscClangLinter pragma ignore: -fdoc-section-header-unknown 7204 /*@C 7205 DMSetLabel - Replaces the label of a given name, or ignores it if the name is not present 7206 7207 Not Collective 7208 7209 Input Parameters: 7210 + dm - The `DM` object 7211 - label - The `DMLabel`, having the same name, to substitute 7212 7213 Default labels in a `DMPLEX`: 7214 + "depth" - Holds the depth (co-dimension) of each mesh point 7215 . "celltype" - Holds the topological type of each cell 7216 . "ghost" - If the DM is distributed with overlap, this marks the cells and faces in the overlap 7217 . "Cell Sets" - Mirrors the cell sets defined by GMsh and ExodusII 7218 . "Face Sets" - Mirrors the face sets defined by GMsh and ExodusII 7219 - "Vertex Sets" - Mirrors the vertex sets defined by GMsh 7220 7221 Level: intermediate 7222 7223 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMPlexGetDepthLabel()`, `DMPlexGetCellType()` 7224 @*/ 7225 PetscErrorCode DMSetLabel(DM dm, DMLabel label) 7226 { 7227 DMLabelLink next = dm->labels; 7228 PetscBool hasLabel, flg; 7229 const char *name, *lname; 7230 7231 PetscFunctionBegin; 7232 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7233 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 7234 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7235 while (next) { 7236 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7237 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7238 if (hasLabel) { 7239 PetscCall(PetscObjectReference((PetscObject)label)); 7240 PetscCall(PetscStrcmp(lname, "depth", &flg)); 7241 if (flg) dm->depthLabel = label; 7242 PetscCall(PetscStrcmp(lname, "celltype", &flg)); 7243 if (flg) dm->celltypeLabel = label; 7244 PetscCall(DMLabelDestroy(&next->label)); 7245 next->label = label; 7246 break; 7247 } 7248 next = next->next; 7249 } 7250 PetscFunctionReturn(PETSC_SUCCESS); 7251 } 7252 7253 /*@C 7254 DMRemoveLabel - Remove the label given by name from this `DM` 7255 7256 Not Collective 7257 7258 Input Parameters: 7259 + dm - The `DM` object 7260 - name - The label name 7261 7262 Output Parameter: 7263 . label - The `DMLabel`, or `NULL` if the label is absent. Pass in `NULL` to call `DMLabelDestroy()` on the label, otherwise the 7264 caller is responsible for calling `DMLabelDestroy()`. 7265 7266 Level: developer 7267 7268 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabelBySelf()` 7269 @*/ 7270 PetscErrorCode DMRemoveLabel(DM dm, const char name[], DMLabel *label) 7271 { 7272 DMLabelLink link, *pnext; 7273 PetscBool hasLabel; 7274 const char *lname; 7275 7276 PetscFunctionBegin; 7277 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7278 PetscAssertPointer(name, 2); 7279 if (label) { 7280 PetscAssertPointer(label, 3); 7281 *label = NULL; 7282 } 7283 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7284 PetscCall(PetscObjectGetName((PetscObject)link->label, &lname)); 7285 PetscCall(PetscStrcmp(name, lname, &hasLabel)); 7286 if (hasLabel) { 7287 *pnext = link->next; /* Remove from list */ 7288 PetscCall(PetscStrcmp(name, "depth", &hasLabel)); 7289 if (hasLabel) dm->depthLabel = NULL; 7290 PetscCall(PetscStrcmp(name, "celltype", &hasLabel)); 7291 if (hasLabel) dm->celltypeLabel = NULL; 7292 if (label) *label = link->label; 7293 else PetscCall(DMLabelDestroy(&link->label)); 7294 PetscCall(PetscFree(link)); 7295 break; 7296 } 7297 } 7298 PetscFunctionReturn(PETSC_SUCCESS); 7299 } 7300 7301 /*@ 7302 DMRemoveLabelBySelf - Remove the label from this `DM` 7303 7304 Not Collective 7305 7306 Input Parameters: 7307 + dm - The `DM` object 7308 . label - The `DMLabel` to be removed from the `DM` 7309 - failNotFound - Should it fail if the label is not found in the `DM`? 7310 7311 Level: developer 7312 7313 Note: 7314 Only exactly the same instance is removed if found, name match is ignored. 7315 If the `DM` has an exclusive reference to the label, the label gets destroyed and 7316 *label nullified. 7317 7318 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabel()` `DMGetLabelValue()`, `DMSetLabelValue()`, `DMLabelDestroy()`, `DMRemoveLabel()` 7319 @*/ 7320 PetscErrorCode DMRemoveLabelBySelf(DM dm, DMLabel *label, PetscBool failNotFound) 7321 { 7322 DMLabelLink link, *pnext; 7323 PetscBool hasLabel = PETSC_FALSE; 7324 7325 PetscFunctionBegin; 7326 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7327 PetscAssertPointer(label, 2); 7328 if (!*label && !failNotFound) PetscFunctionReturn(PETSC_SUCCESS); 7329 PetscValidHeaderSpecific(*label, DMLABEL_CLASSID, 2); 7330 PetscValidLogicalCollectiveBool(dm, failNotFound, 3); 7331 for (pnext = &dm->labels; (link = *pnext); pnext = &link->next) { 7332 if (*label == link->label) { 7333 hasLabel = PETSC_TRUE; 7334 *pnext = link->next; /* Remove from list */ 7335 if (*label == dm->depthLabel) dm->depthLabel = NULL; 7336 if (*label == dm->celltypeLabel) dm->celltypeLabel = NULL; 7337 if (((PetscObject)link->label)->refct < 2) *label = NULL; /* nullify if exclusive reference */ 7338 PetscCall(DMLabelDestroy(&link->label)); 7339 PetscCall(PetscFree(link)); 7340 break; 7341 } 7342 } 7343 PetscCheck(hasLabel || !failNotFound, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Given label not found in DM"); 7344 PetscFunctionReturn(PETSC_SUCCESS); 7345 } 7346 7347 /*@C 7348 DMGetLabelOutput - Get the output flag for a given label 7349 7350 Not Collective 7351 7352 Input Parameters: 7353 + dm - The `DM` object 7354 - name - The label name 7355 7356 Output Parameter: 7357 . output - The flag for output 7358 7359 Level: developer 7360 7361 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMSetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7362 @*/ 7363 PetscErrorCode DMGetLabelOutput(DM dm, const char name[], PetscBool *output) 7364 { 7365 DMLabelLink next = dm->labels; 7366 const char *lname; 7367 7368 PetscFunctionBegin; 7369 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7370 PetscAssertPointer(name, 2); 7371 PetscAssertPointer(output, 3); 7372 while (next) { 7373 PetscBool flg; 7374 7375 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7376 PetscCall(PetscStrcmp(name, lname, &flg)); 7377 if (flg) { 7378 *output = next->output; 7379 PetscFunctionReturn(PETSC_SUCCESS); 7380 } 7381 next = next->next; 7382 } 7383 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7384 } 7385 7386 /*@C 7387 DMSetLabelOutput - Set if a given label should be saved to a `PetscViewer` in calls to `DMView()` 7388 7389 Not Collective 7390 7391 Input Parameters: 7392 + dm - The `DM` object 7393 . name - The label name 7394 - output - `PETSC_TRUE` to save the label to the viewer 7395 7396 Level: developer 7397 7398 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMGetOutputFlag()`, `DMGetLabelOutput()`, `DMCreateLabel()`, `DMHasLabel()`, `DMGetLabelValue()`, `DMSetLabelValue()`, `DMGetStratumIS()` 7399 @*/ 7400 PetscErrorCode DMSetLabelOutput(DM dm, const char name[], PetscBool output) 7401 { 7402 DMLabelLink next = dm->labels; 7403 const char *lname; 7404 7405 PetscFunctionBegin; 7406 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7407 PetscAssertPointer(name, 2); 7408 while (next) { 7409 PetscBool flg; 7410 7411 PetscCall(PetscObjectGetName((PetscObject)next->label, &lname)); 7412 PetscCall(PetscStrcmp(name, lname, &flg)); 7413 if (flg) { 7414 next->output = output; 7415 PetscFunctionReturn(PETSC_SUCCESS); 7416 } 7417 next = next->next; 7418 } 7419 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "No label named %s was present in this dm", name); 7420 } 7421 7422 /*@ 7423 DMCopyLabels - Copy labels from one `DM` mesh to another `DM` with a superset of the points 7424 7425 Collective 7426 7427 Input Parameters: 7428 + dmA - The `DM` object with initial labels 7429 . dmB - The `DM` object to which labels are copied 7430 . mode - Copy labels by pointers (`PETSC_OWN_POINTER`) or duplicate them (`PETSC_COPY_VALUES`) 7431 . all - Copy all labels including "depth", "dim", and "celltype" (`PETSC_TRUE`) which are otherwise ignored (`PETSC_FALSE`) 7432 - emode - How to behave when a `DMLabel` in the source and destination `DM`s with the same name is encountered (see `DMCopyLabelsMode`) 7433 7434 Level: intermediate 7435 7436 Note: 7437 This is typically used when interpolating or otherwise adding to a mesh, or testing. 7438 7439 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode` 7440 @*/ 7441 PetscErrorCode DMCopyLabels(DM dmA, DM dmB, PetscCopyMode mode, PetscBool all, DMCopyLabelsMode emode) 7442 { 7443 DMLabel label, labelNew, labelOld; 7444 const char *name; 7445 PetscBool flg; 7446 DMLabelLink link; 7447 7448 PetscFunctionBegin; 7449 PetscValidHeaderSpecific(dmA, DM_CLASSID, 1); 7450 PetscValidHeaderSpecific(dmB, DM_CLASSID, 2); 7451 PetscValidLogicalCollectiveEnum(dmA, mode, 3); 7452 PetscValidLogicalCollectiveBool(dmA, all, 4); 7453 PetscCheck(mode != PETSC_USE_POINTER, PetscObjectComm((PetscObject)dmA), PETSC_ERR_SUP, "PETSC_USE_POINTER not supported for objects"); 7454 if (dmA == dmB) PetscFunctionReturn(PETSC_SUCCESS); 7455 for (link = dmA->labels; link; link = link->next) { 7456 label = link->label; 7457 PetscCall(PetscObjectGetName((PetscObject)label, &name)); 7458 if (!all) { 7459 PetscCall(PetscStrcmp(name, "depth", &flg)); 7460 if (flg) continue; 7461 PetscCall(PetscStrcmp(name, "dim", &flg)); 7462 if (flg) continue; 7463 PetscCall(PetscStrcmp(name, "celltype", &flg)); 7464 if (flg) continue; 7465 } 7466 PetscCall(DMGetLabel(dmB, name, &labelOld)); 7467 if (labelOld) { 7468 switch (emode) { 7469 case DM_COPY_LABELS_KEEP: 7470 continue; 7471 case DM_COPY_LABELS_REPLACE: 7472 PetscCall(DMRemoveLabelBySelf(dmB, &labelOld, PETSC_TRUE)); 7473 break; 7474 case DM_COPY_LABELS_FAIL: 7475 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Label %s already exists in destination DM", name); 7476 default: 7477 SETERRQ(PetscObjectComm((PetscObject)dmA), PETSC_ERR_ARG_OUTOFRANGE, "Unhandled DMCopyLabelsMode %d", (int)emode); 7478 } 7479 } 7480 if (mode == PETSC_COPY_VALUES) { 7481 PetscCall(DMLabelDuplicate(label, &labelNew)); 7482 } else { 7483 labelNew = label; 7484 } 7485 PetscCall(DMAddLabel(dmB, labelNew)); 7486 if (mode == PETSC_COPY_VALUES) PetscCall(DMLabelDestroy(&labelNew)); 7487 } 7488 PetscFunctionReturn(PETSC_SUCCESS); 7489 } 7490 7491 /*@C 7492 DMCompareLabels - Compare labels between two `DM` objects 7493 7494 Collective; No Fortran Support 7495 7496 Input Parameters: 7497 + dm0 - First `DM` object 7498 - dm1 - Second `DM` object 7499 7500 Output Parameters: 7501 + equal - (Optional) Flag whether labels of dm0 and dm1 are the same 7502 - message - (Optional) Message describing the difference, or `NULL` if there is no difference 7503 7504 Level: intermediate 7505 7506 Notes: 7507 The output flag equal will be the same on all processes. 7508 7509 If equal is passed as `NULL` and difference is found, an error is thrown on all processes. 7510 7511 Make sure to pass equal is `NULL` on all processes or none of them. 7512 7513 The output message is set independently on each rank. 7514 7515 message must be freed with `PetscFree()` 7516 7517 If message is passed as `NULL` and a difference is found, the difference description is printed to stderr in synchronized manner. 7518 7519 Make sure to pass message as `NULL` on all processes or no processes. 7520 7521 Labels are matched by name. If the number of labels and their names are equal, 7522 `DMLabelCompare()` is used to compare each pair of labels with the same name. 7523 7524 .seealso: [](ch_dmbase), `DM`, `DMLabel`, `DMAddLabel()`, `DMCopyLabelsMode`, `DMLabelCompare()` 7525 @*/ 7526 PetscErrorCode DMCompareLabels(DM dm0, DM dm1, PetscBool *equal, char **message) 7527 { 7528 PetscInt n, i; 7529 char msg[PETSC_MAX_PATH_LEN] = ""; 7530 PetscBool eq; 7531 MPI_Comm comm; 7532 PetscMPIInt rank; 7533 7534 PetscFunctionBegin; 7535 PetscValidHeaderSpecific(dm0, DM_CLASSID, 1); 7536 PetscValidHeaderSpecific(dm1, DM_CLASSID, 2); 7537 PetscCheckSameComm(dm0, 1, dm1, 2); 7538 if (equal) PetscAssertPointer(equal, 3); 7539 if (message) PetscAssertPointer(message, 4); 7540 PetscCall(PetscObjectGetComm((PetscObject)dm0, &comm)); 7541 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 7542 { 7543 PetscInt n1; 7544 7545 PetscCall(DMGetNumLabels(dm0, &n)); 7546 PetscCall(DMGetNumLabels(dm1, &n1)); 7547 eq = (PetscBool)(n == n1); 7548 if (!eq) PetscCall(PetscSNPrintf(msg, sizeof(msg), "Number of labels in dm0 = %" PetscInt_FMT " != %" PetscInt_FMT " = Number of labels in dm1", n, n1)); 7549 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7550 if (!eq) goto finish; 7551 } 7552 for (i = 0; i < n; i++) { 7553 DMLabel l0, l1; 7554 const char *name; 7555 char *msgInner; 7556 7557 /* Ignore label order */ 7558 PetscCall(DMGetLabelByNum(dm0, i, &l0)); 7559 PetscCall(PetscObjectGetName((PetscObject)l0, &name)); 7560 PetscCall(DMGetLabel(dm1, name, &l1)); 7561 if (!l1) { 7562 PetscCall(PetscSNPrintf(msg, sizeof(msg), "Label \"%s\" (#%" PetscInt_FMT " in dm0) not found in dm1", name, i)); 7563 eq = PETSC_FALSE; 7564 break; 7565 } 7566 PetscCall(DMLabelCompare(comm, l0, l1, &eq, &msgInner)); 7567 PetscCall(PetscStrncpy(msg, msgInner, sizeof(msg))); 7568 PetscCall(PetscFree(msgInner)); 7569 if (!eq) break; 7570 } 7571 PetscCall(MPIU_Allreduce(MPI_IN_PLACE, &eq, 1, MPIU_BOOL, MPI_LAND, comm)); 7572 finish: 7573 /* If message output arg not set, print to stderr */ 7574 if (message) { 7575 *message = NULL; 7576 if (msg[0]) PetscCall(PetscStrallocpy(msg, message)); 7577 } else { 7578 if (msg[0]) PetscCall(PetscSynchronizedFPrintf(comm, PETSC_STDERR, "[%d] %s\n", rank, msg)); 7579 PetscCall(PetscSynchronizedFlush(comm, PETSC_STDERR)); 7580 } 7581 /* If same output arg not ser and labels are not equal, throw error */ 7582 if (equal) *equal = eq; 7583 else PetscCheck(eq, comm, PETSC_ERR_ARG_INCOMP, "DMLabels are not the same in dm0 and dm1"); 7584 PetscFunctionReturn(PETSC_SUCCESS); 7585 } 7586 7587 PetscErrorCode DMSetLabelValue_Fast(DM dm, DMLabel *label, const char name[], PetscInt point, PetscInt value) 7588 { 7589 PetscFunctionBegin; 7590 PetscAssertPointer(label, 2); 7591 if (!*label) { 7592 PetscCall(DMCreateLabel(dm, name)); 7593 PetscCall(DMGetLabel(dm, name, label)); 7594 } 7595 PetscCall(DMLabelSetValue(*label, point, value)); 7596 PetscFunctionReturn(PETSC_SUCCESS); 7597 } 7598 7599 /* 7600 Many mesh programs, such as Triangle and TetGen, allow only a single label for each mesh point. Therefore, we would 7601 like to encode all label IDs using a single, universal label. We can do this by assigning an integer to every 7602 (label, id) pair in the DM. 7603 7604 However, a mesh point can have multiple labels, so we must separate all these values. We will assign a bit range to 7605 each label. 7606 */ 7607 PetscErrorCode DMUniversalLabelCreate(DM dm, DMUniversalLabel *universal) 7608 { 7609 DMUniversalLabel ul; 7610 PetscBool *active; 7611 PetscInt pStart, pEnd, p, Nl, l, m; 7612 7613 PetscFunctionBegin; 7614 PetscCall(PetscMalloc1(1, &ul)); 7615 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "universal", &ul->label)); 7616 PetscCall(DMGetNumLabels(dm, &Nl)); 7617 PetscCall(PetscCalloc1(Nl, &active)); 7618 ul->Nl = 0; 7619 for (l = 0; l < Nl; ++l) { 7620 PetscBool isdepth, iscelltype; 7621 const char *name; 7622 7623 PetscCall(DMGetLabelName(dm, l, &name)); 7624 PetscCall(PetscStrncmp(name, "depth", 6, &isdepth)); 7625 PetscCall(PetscStrncmp(name, "celltype", 9, &iscelltype)); 7626 active[l] = !(isdepth || iscelltype) ? PETSC_TRUE : PETSC_FALSE; 7627 if (active[l]) ++ul->Nl; 7628 } 7629 PetscCall(PetscCalloc5(ul->Nl, &ul->names, ul->Nl, &ul->indices, ul->Nl + 1, &ul->offsets, ul->Nl + 1, &ul->bits, ul->Nl, &ul->masks)); 7630 ul->Nv = 0; 7631 for (l = 0, m = 0; l < Nl; ++l) { 7632 DMLabel label; 7633 PetscInt nv; 7634 const char *name; 7635 7636 if (!active[l]) continue; 7637 PetscCall(DMGetLabelName(dm, l, &name)); 7638 PetscCall(DMGetLabelByNum(dm, l, &label)); 7639 PetscCall(DMLabelGetNumValues(label, &nv)); 7640 PetscCall(PetscStrallocpy(name, &ul->names[m])); 7641 ul->indices[m] = l; 7642 ul->Nv += nv; 7643 ul->offsets[m + 1] = nv; 7644 ul->bits[m + 1] = PetscCeilReal(PetscLog2Real(nv + 1)); 7645 ++m; 7646 } 7647 for (l = 1; l <= ul->Nl; ++l) { 7648 ul->offsets[l] = ul->offsets[l - 1] + ul->offsets[l]; 7649 ul->bits[l] = ul->bits[l - 1] + ul->bits[l]; 7650 } 7651 for (l = 0; l < ul->Nl; ++l) { 7652 PetscInt b; 7653 7654 ul->masks[l] = 0; 7655 for (b = ul->bits[l]; b < ul->bits[l + 1]; ++b) ul->masks[l] |= 1 << b; 7656 } 7657 PetscCall(PetscMalloc1(ul->Nv, &ul->values)); 7658 for (l = 0, m = 0; l < Nl; ++l) { 7659 DMLabel label; 7660 IS valueIS; 7661 const PetscInt *varr; 7662 PetscInt nv, v; 7663 7664 if (!active[l]) continue; 7665 PetscCall(DMGetLabelByNum(dm, l, &label)); 7666 PetscCall(DMLabelGetNumValues(label, &nv)); 7667 PetscCall(DMLabelGetValueIS(label, &valueIS)); 7668 PetscCall(ISGetIndices(valueIS, &varr)); 7669 for (v = 0; v < nv; ++v) ul->values[ul->offsets[m] + v] = varr[v]; 7670 PetscCall(ISRestoreIndices(valueIS, &varr)); 7671 PetscCall(ISDestroy(&valueIS)); 7672 PetscCall(PetscSortInt(nv, &ul->values[ul->offsets[m]])); 7673 ++m; 7674 } 7675 PetscCall(DMPlexGetChart(dm, &pStart, &pEnd)); 7676 for (p = pStart; p < pEnd; ++p) { 7677 PetscInt uval = 0; 7678 PetscBool marked = PETSC_FALSE; 7679 7680 for (l = 0, m = 0; l < Nl; ++l) { 7681 DMLabel label; 7682 PetscInt val, defval, loc, nv; 7683 7684 if (!active[l]) continue; 7685 PetscCall(DMGetLabelByNum(dm, l, &label)); 7686 PetscCall(DMLabelGetValue(label, p, &val)); 7687 PetscCall(DMLabelGetDefaultValue(label, &defval)); 7688 if (val == defval) { 7689 ++m; 7690 continue; 7691 } 7692 nv = ul->offsets[m + 1] - ul->offsets[m]; 7693 marked = PETSC_TRUE; 7694 PetscCall(PetscFindInt(val, nv, &ul->values[ul->offsets[m]], &loc)); 7695 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Label value %" PetscInt_FMT " not found in compression array", val); 7696 uval += (loc + 1) << ul->bits[m]; 7697 ++m; 7698 } 7699 if (marked) PetscCall(DMLabelSetValue(ul->label, p, uval)); 7700 } 7701 PetscCall(PetscFree(active)); 7702 *universal = ul; 7703 PetscFunctionReturn(PETSC_SUCCESS); 7704 } 7705 7706 PetscErrorCode DMUniversalLabelDestroy(DMUniversalLabel *universal) 7707 { 7708 PetscInt l; 7709 7710 PetscFunctionBegin; 7711 for (l = 0; l < (*universal)->Nl; ++l) PetscCall(PetscFree((*universal)->names[l])); 7712 PetscCall(DMLabelDestroy(&(*universal)->label)); 7713 PetscCall(PetscFree5((*universal)->names, (*universal)->indices, (*universal)->offsets, (*universal)->bits, (*universal)->masks)); 7714 PetscCall(PetscFree((*universal)->values)); 7715 PetscCall(PetscFree(*universal)); 7716 *universal = NULL; 7717 PetscFunctionReturn(PETSC_SUCCESS); 7718 } 7719 7720 PetscErrorCode DMUniversalLabelGetLabel(DMUniversalLabel ul, DMLabel *ulabel) 7721 { 7722 PetscFunctionBegin; 7723 PetscAssertPointer(ulabel, 2); 7724 *ulabel = ul->label; 7725 PetscFunctionReturn(PETSC_SUCCESS); 7726 } 7727 7728 PetscErrorCode DMUniversalLabelCreateLabels(DMUniversalLabel ul, PetscBool preserveOrder, DM dm) 7729 { 7730 PetscInt Nl = ul->Nl, l; 7731 7732 PetscFunctionBegin; 7733 PetscValidHeaderSpecific(dm, DM_CLASSID, 3); 7734 for (l = 0; l < Nl; ++l) { 7735 if (preserveOrder) PetscCall(DMCreateLabelAtIndex(dm, ul->indices[l], ul->names[l])); 7736 else PetscCall(DMCreateLabel(dm, ul->names[l])); 7737 } 7738 if (preserveOrder) { 7739 for (l = 0; l < ul->Nl; ++l) { 7740 const char *name; 7741 PetscBool match; 7742 7743 PetscCall(DMGetLabelName(dm, ul->indices[l], &name)); 7744 PetscCall(PetscStrcmp(name, ul->names[l], &match)); 7745 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]); 7746 } 7747 } 7748 PetscFunctionReturn(PETSC_SUCCESS); 7749 } 7750 7751 PetscErrorCode DMUniversalLabelSetLabelValue(DMUniversalLabel ul, DM dm, PetscBool useIndex, PetscInt p, PetscInt value) 7752 { 7753 PetscInt l; 7754 7755 PetscFunctionBegin; 7756 for (l = 0; l < ul->Nl; ++l) { 7757 DMLabel label; 7758 PetscInt lval = (value & ul->masks[l]) >> ul->bits[l]; 7759 7760 if (lval) { 7761 if (useIndex) PetscCall(DMGetLabelByNum(dm, ul->indices[l], &label)); 7762 else PetscCall(DMGetLabel(dm, ul->names[l], &label)); 7763 PetscCall(DMLabelSetValue(label, p, ul->values[ul->offsets[l] + lval - 1])); 7764 } 7765 } 7766 PetscFunctionReturn(PETSC_SUCCESS); 7767 } 7768 7769 /*@ 7770 DMGetCoarseDM - Get the coarse `DM`from which this `DM` was obtained by refinement 7771 7772 Not Collective 7773 7774 Input Parameter: 7775 . dm - The `DM` object 7776 7777 Output Parameter: 7778 . cdm - The coarse `DM` 7779 7780 Level: intermediate 7781 7782 .seealso: [](ch_dmbase), `DM`, `DMSetCoarseDM()`, `DMCoarsen()` 7783 @*/ 7784 PetscErrorCode DMGetCoarseDM(DM dm, DM *cdm) 7785 { 7786 PetscFunctionBegin; 7787 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7788 PetscAssertPointer(cdm, 2); 7789 *cdm = dm->coarseMesh; 7790 PetscFunctionReturn(PETSC_SUCCESS); 7791 } 7792 7793 /*@ 7794 DMSetCoarseDM - Set the coarse `DM` from which this `DM` was obtained by refinement 7795 7796 Input Parameters: 7797 + dm - The `DM` object 7798 - cdm - The coarse `DM` 7799 7800 Level: intermediate 7801 7802 Note: 7803 Normally this is set automatically by `DMRefine()` 7804 7805 .seealso: [](ch_dmbase), `DM`, `DMGetCoarseDM()`, `DMCoarsen()`, `DMSetRefine()`, `DMSetFineDM()` 7806 @*/ 7807 PetscErrorCode DMSetCoarseDM(DM dm, DM cdm) 7808 { 7809 PetscFunctionBegin; 7810 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7811 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 7812 if (dm == cdm) cdm = NULL; 7813 PetscCall(PetscObjectReference((PetscObject)cdm)); 7814 PetscCall(DMDestroy(&dm->coarseMesh)); 7815 dm->coarseMesh = cdm; 7816 PetscFunctionReturn(PETSC_SUCCESS); 7817 } 7818 7819 /*@ 7820 DMGetFineDM - Get the fine mesh from which this `DM` was obtained by coarsening 7821 7822 Input Parameter: 7823 . dm - The `DM` object 7824 7825 Output Parameter: 7826 . fdm - The fine `DM` 7827 7828 Level: intermediate 7829 7830 .seealso: [](ch_dmbase), `DM`, `DMSetFineDM()`, `DMCoarsen()`, `DMRefine()` 7831 @*/ 7832 PetscErrorCode DMGetFineDM(DM dm, DM *fdm) 7833 { 7834 PetscFunctionBegin; 7835 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7836 PetscAssertPointer(fdm, 2); 7837 *fdm = dm->fineMesh; 7838 PetscFunctionReturn(PETSC_SUCCESS); 7839 } 7840 7841 /*@ 7842 DMSetFineDM - Set the fine mesh from which this was obtained by coarsening 7843 7844 Input Parameters: 7845 + dm - The `DM` object 7846 - fdm - The fine `DM` 7847 7848 Level: developer 7849 7850 Note: 7851 Normally this is set automatically by `DMCoarsen()` 7852 7853 .seealso: [](ch_dmbase), `DM`, `DMGetFineDM()`, `DMCoarsen()`, `DMRefine()` 7854 @*/ 7855 PetscErrorCode DMSetFineDM(DM dm, DM fdm) 7856 { 7857 PetscFunctionBegin; 7858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7859 if (fdm) PetscValidHeaderSpecific(fdm, DM_CLASSID, 2); 7860 if (dm == fdm) fdm = NULL; 7861 PetscCall(PetscObjectReference((PetscObject)fdm)); 7862 PetscCall(DMDestroy(&dm->fineMesh)); 7863 dm->fineMesh = fdm; 7864 PetscFunctionReturn(PETSC_SUCCESS); 7865 } 7866 7867 /*@C 7868 DMAddBoundary - Add a boundary condition to a model represented by a `DM` 7869 7870 Collective 7871 7872 Input Parameters: 7873 + dm - The `DM`, with a `PetscDS` that matches the problem being constrained 7874 . type - The type of condition, e.g. `DM_BC_ESSENTIAL_ANALYTIC`, `DM_BC_ESSENTIAL_FIELD` (Dirichlet), or `DM_BC_NATURAL` (Neumann) 7875 . name - The BC name 7876 . label - The label defining constrained points 7877 . Nv - The number of `DMLabel` values for constrained points 7878 . values - An array of values for constrained points 7879 . field - The field to constrain 7880 . Nc - The number of constrained field components (0 will constrain all fields) 7881 . comps - An array of constrained component numbers 7882 . bcFunc - A pointwise function giving boundary values 7883 . bcFunc_t - A pointwise function giving the time deriative of the boundary values, or NULL 7884 - ctx - An optional user context for bcFunc 7885 7886 Output Parameter: 7887 . bd - (Optional) Boundary number 7888 7889 Options Database Keys: 7890 + -bc_<boundary name> <num> - Overrides the boundary ids 7891 - -bc_<boundary name>_comp <num> - Overrides the boundary components 7892 7893 Level: intermediate 7894 7895 Notes: 7896 Both bcFunc abd bcFunc_t will depend on the boundary condition type. If the type if `DM_BC_ESSENTIAL`, then the calling sequence is\: 7897 7898 $ void bcFunc(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar bcval[]) 7899 7900 If the type is `DM_BC_ESSENTIAL_FIELD` or other _FIELD value, then the calling sequence is\: 7901 7902 .vb 7903 void bcFunc(PetscInt dim, PetscInt Nf, PetscInt NfAux, 7904 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 7905 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 7906 PetscReal time, const PetscReal x[], PetscScalar bcval[]) 7907 .ve 7908 + dim - the spatial dimension 7909 . Nf - the number of fields 7910 . uOff - the offset into u[] and u_t[] for each field 7911 . uOff_x - the offset into u_x[] for each field 7912 . u - each field evaluated at the current point 7913 . u_t - the time derivative of each field evaluated at the current point 7914 . u_x - the gradient of each field evaluated at the current point 7915 . aOff - the offset into a[] and a_t[] for each auxiliary field 7916 . aOff_x - the offset into a_x[] for each auxiliary field 7917 . a - each auxiliary field evaluated at the current point 7918 . a_t - the time derivative of each auxiliary field evaluated at the current point 7919 . a_x - the gradient of auxiliary each field evaluated at the current point 7920 . t - current time 7921 . x - coordinates of the current point 7922 . numConstants - number of constant parameters 7923 . constants - constant parameters 7924 - bcval - output values at the current point 7925 7926 .seealso: [](ch_dmbase), `DM`, `DSGetBoundary()`, `PetscDSAddBoundary()` 7927 @*/ 7928 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) 7929 { 7930 PetscDS ds; 7931 7932 PetscFunctionBegin; 7933 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 7934 PetscValidLogicalCollectiveEnum(dm, type, 2); 7935 PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 4); 7936 PetscValidLogicalCollectiveInt(dm, Nv, 5); 7937 PetscValidLogicalCollectiveInt(dm, field, 7); 7938 PetscValidLogicalCollectiveInt(dm, Nc, 8); 7939 PetscCheck(!dm->localSection, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Cannot add boundary to DM after creating local section"); 7940 PetscCall(DMGetDS(dm, &ds)); 7941 /* Complete label */ 7942 if (label) { 7943 PetscObject obj; 7944 PetscClassId id; 7945 7946 PetscCall(DMGetField(dm, field, NULL, &obj)); 7947 PetscCall(PetscObjectGetClassId(obj, &id)); 7948 if (id == PETSCFE_CLASSID) { 7949 DM plex; 7950 7951 PetscCall(DMConvert(dm, DMPLEX, &plex)); 7952 if (plex) PetscCall(DMPlexLabelComplete(plex, label)); 7953 PetscCall(DMDestroy(&plex)); 7954 } 7955 } 7956 PetscCall(PetscDSAddBoundary(ds, type, name, label, Nv, values, field, Nc, comps, bcFunc, bcFunc_t, ctx, bd)); 7957 PetscFunctionReturn(PETSC_SUCCESS); 7958 } 7959 7960 /* TODO Remove this since now the structures are the same */ 7961 static PetscErrorCode DMPopulateBoundary(DM dm) 7962 { 7963 PetscDS ds; 7964 DMBoundary *lastnext; 7965 DSBoundary dsbound; 7966 7967 PetscFunctionBegin; 7968 PetscCall(DMGetDS(dm, &ds)); 7969 dsbound = ds->boundary; 7970 if (dm->boundary) { 7971 DMBoundary next = dm->boundary; 7972 7973 /* quick check to see if the PetscDS has changed */ 7974 if (next->dsboundary == dsbound) PetscFunctionReturn(PETSC_SUCCESS); 7975 /* the PetscDS has changed: tear down and rebuild */ 7976 while (next) { 7977 DMBoundary b = next; 7978 7979 next = b->next; 7980 PetscCall(PetscFree(b)); 7981 } 7982 dm->boundary = NULL; 7983 } 7984 7985 lastnext = &dm->boundary; 7986 while (dsbound) { 7987 DMBoundary dmbound; 7988 7989 PetscCall(PetscNew(&dmbound)); 7990 dmbound->dsboundary = dsbound; 7991 dmbound->label = dsbound->label; 7992 /* push on the back instead of the front so that it is in the same order as in the PetscDS */ 7993 *lastnext = dmbound; 7994 lastnext = &dmbound->next; 7995 dsbound = dsbound->next; 7996 } 7997 PetscFunctionReturn(PETSC_SUCCESS); 7998 } 7999 8000 /* TODO: missing manual page */ 8001 PetscErrorCode DMIsBoundaryPoint(DM dm, PetscInt point, PetscBool *isBd) 8002 { 8003 DMBoundary b; 8004 8005 PetscFunctionBegin; 8006 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8007 PetscAssertPointer(isBd, 3); 8008 *isBd = PETSC_FALSE; 8009 PetscCall(DMPopulateBoundary(dm)); 8010 b = dm->boundary; 8011 while (b && !(*isBd)) { 8012 DMLabel label = b->label; 8013 DSBoundary dsb = b->dsboundary; 8014 PetscInt i; 8015 8016 if (label) { 8017 for (i = 0; i < dsb->Nv && !(*isBd); ++i) PetscCall(DMLabelStratumHasPoint(label, dsb->values[i], point, isBd)); 8018 } 8019 b = b->next; 8020 } 8021 PetscFunctionReturn(PETSC_SUCCESS); 8022 } 8023 8024 /*@C 8025 DMProjectFunction - This projects the given function into the function space provided by a `DM`, putting the coefficients in a global vector. 8026 8027 Collective 8028 8029 Input Parameters: 8030 + dm - The `DM` 8031 . time - The time 8032 . funcs - The coordinate functions to evaluate, one per field 8033 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8034 - mode - The insertion mode for values 8035 8036 Output Parameter: 8037 . X - vector 8038 8039 Calling sequence of `funcs`: 8040 + dim - The spatial dimension 8041 . time - The time at which to sample 8042 . x - The coordinates 8043 . Nc - The number of components 8044 . u - The output field values 8045 - ctx - optional user-defined function context 8046 8047 Level: developer 8048 8049 Developer Notes: 8050 This API is specific to only particular usage of `DM` 8051 8052 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8053 8054 .seealso: [](ch_dmbase), `DM`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8055 @*/ 8056 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) 8057 { 8058 Vec localX; 8059 8060 PetscFunctionBegin; 8061 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8062 PetscCall(PetscLogEventBegin(DM_ProjectFunction, dm, X, 0, 0)); 8063 PetscCall(DMGetLocalVector(dm, &localX)); 8064 PetscCall(VecSet(localX, 0.)); 8065 PetscCall(DMProjectFunctionLocal(dm, time, funcs, ctxs, mode, localX)); 8066 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8067 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8068 PetscCall(DMRestoreLocalVector(dm, &localX)); 8069 PetscCall(PetscLogEventEnd(DM_ProjectFunction, dm, X, 0, 0)); 8070 PetscFunctionReturn(PETSC_SUCCESS); 8071 } 8072 8073 /*@C 8074 DMProjectFunctionLocal - This projects the given function into the function space provided by a `DM`, putting the coefficients in a local vector. 8075 8076 Not Collective 8077 8078 Input Parameters: 8079 + dm - The `DM` 8080 . time - The time 8081 . funcs - The coordinate functions to evaluate, one per field 8082 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8083 - mode - The insertion mode for values 8084 8085 Output Parameter: 8086 . localX - vector 8087 8088 Calling sequence of `funcs`: 8089 + dim - The spatial dimension 8090 . time - The current timestep 8091 . x - The coordinates 8092 . Nc - The number of components 8093 . u - The output field values 8094 - ctx - optional user-defined function context 8095 8096 Level: developer 8097 8098 Developer Notes: 8099 This API is specific to only particular usage of `DM` 8100 8101 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8102 8103 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8104 @*/ 8105 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) 8106 { 8107 PetscFunctionBegin; 8108 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8109 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8110 PetscUseTypeMethod(dm, projectfunctionlocal, time, funcs, ctxs, mode, localX); 8111 PetscFunctionReturn(PETSC_SUCCESS); 8112 } 8113 8114 /*@C 8115 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. 8116 8117 Collective 8118 8119 Input Parameters: 8120 + dm - The `DM` 8121 . time - The time 8122 . numIds - The number of ids 8123 . ids - The ids 8124 . Nc - The number of components 8125 . comps - The components 8126 . label - The `DMLabel` selecting the portion of the mesh for projection 8127 . funcs - The coordinate functions to evaluate, one per field 8128 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs may be null. 8129 - mode - The insertion mode for values 8130 8131 Output Parameter: 8132 . X - vector 8133 8134 Calling sequence of `funcs`: 8135 + dim - The spatial dimension 8136 . time - The current timestep 8137 . x - The coordinates 8138 . Nc - The number of components 8139 . u - The output field values 8140 - ctx - optional user-defined function context 8141 8142 Level: developer 8143 8144 Developer Notes: 8145 This API is specific to only particular usage of `DM` 8146 8147 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8148 8149 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabelLocal()`, `DMComputeL2Diff()` 8150 @*/ 8151 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) 8152 { 8153 Vec localX; 8154 8155 PetscFunctionBegin; 8156 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8157 PetscCall(DMGetLocalVector(dm, &localX)); 8158 PetscCall(VecSet(localX, 0.)); 8159 PetscCall(DMProjectFunctionLabelLocal(dm, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX)); 8160 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8161 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8162 PetscCall(DMRestoreLocalVector(dm, &localX)); 8163 PetscFunctionReturn(PETSC_SUCCESS); 8164 } 8165 8166 /*@C 8167 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. 8168 8169 Not Collective 8170 8171 Input Parameters: 8172 + dm - The `DM` 8173 . time - The time 8174 . label - The `DMLabel` selecting the portion of the mesh for projection 8175 . numIds - The number of ids 8176 . ids - The ids 8177 . Nc - The number of components 8178 . comps - The components 8179 . funcs - The coordinate functions to evaluate, one per field 8180 . ctxs - Optional array of contexts to pass to each coordinate function. ctxs itself may be null. 8181 - mode - The insertion mode for values 8182 8183 Output Parameter: 8184 . localX - vector 8185 8186 Calling sequence of `funcs`: 8187 + dim - The spatial dimension 8188 . time - The current time 8189 . x - The coordinates 8190 . Nc - The number of components 8191 . u - The output field values 8192 - ctx - optional user-defined function context 8193 8194 Level: developer 8195 8196 Developer Notes: 8197 This API is specific to only particular usage of `DM` 8198 8199 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8200 8201 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMProjectFunctionLocal()`, `DMProjectFunctionLabel()`, `DMComputeL2Diff()` 8202 @*/ 8203 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) 8204 { 8205 PetscFunctionBegin; 8206 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8207 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8208 PetscUseTypeMethod(dm, projectfunctionlabellocal, time, label, numIds, ids, Nc, comps, funcs, ctxs, mode, localX); 8209 PetscFunctionReturn(PETSC_SUCCESS); 8210 } 8211 8212 /*@C 8213 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. 8214 8215 Not Collective 8216 8217 Input Parameters: 8218 + dm - The `DM` 8219 . time - The time 8220 . localU - The input field vector; may be `NULL` if projection is defined purely by coordinates 8221 . funcs - The functions to evaluate, one per field 8222 - mode - The insertion mode for values 8223 8224 Output Parameter: 8225 . localX - The output vector 8226 8227 Calling sequence of `funcs`: 8228 + dim - The spatial dimension 8229 . Nf - The number of input fields 8230 . NfAux - The number of input auxiliary fields 8231 . uOff - The offset of each field in u[] 8232 . uOff_x - The offset of each field in u_x[] 8233 . u - The field values at this point in space 8234 . u_t - The field time derivative at this point in space (or NULL) 8235 . u_x - The field derivatives at this point in space 8236 . aOff - The offset of each auxiliary field in u[] 8237 . aOff_x - The offset of each auxiliary field in u_x[] 8238 . a - The auxiliary field values at this point in space 8239 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8240 . a_x - The auxiliary field derivatives at this point in space 8241 . t - The current time 8242 . x - The coordinates of this point 8243 . numConstants - The number of constants 8244 . constants - The value of each constant 8245 - f - The value of the function at this point in space 8246 8247 Note: 8248 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. 8249 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 8250 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8251 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8252 8253 Level: intermediate 8254 8255 Developer Notes: 8256 This API is specific to only particular usage of `DM` 8257 8258 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8259 8260 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, 8261 `DMProjectFunction()`, `DMComputeL2Diff()` 8262 @*/ 8263 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) 8264 { 8265 PetscFunctionBegin; 8266 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8267 if (localU) PetscValidHeaderSpecific(localU, VEC_CLASSID, 3); 8268 PetscValidHeaderSpecific(localX, VEC_CLASSID, 6); 8269 PetscUseTypeMethod(dm, projectfieldlocal, time, localU, funcs, mode, localX); 8270 PetscFunctionReturn(PETSC_SUCCESS); 8271 } 8272 8273 /*@C 8274 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. 8275 8276 Not Collective 8277 8278 Input Parameters: 8279 + dm - The `DM` 8280 . time - The time 8281 . label - The `DMLabel` marking the portion of the domain to output 8282 . numIds - The number of label ids to use 8283 . ids - The label ids to use for marking 8284 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8285 . comps - The components to set in the output, or `NULL` for all components 8286 . localU - The input field vector 8287 . funcs - The functions to evaluate, one per field 8288 - mode - The insertion mode for values 8289 8290 Output Parameter: 8291 . localX - The output vector 8292 8293 Calling sequence of `funcs`: 8294 + dim - The spatial dimension 8295 . Nf - The number of input fields 8296 . NfAux - The number of input auxiliary fields 8297 . uOff - The offset of each field in u[] 8298 . uOff_x - The offset of each field in u_x[] 8299 . u - The field values at this point in space 8300 . u_t - The field time derivative at this point in space (or NULL) 8301 . u_x - The field derivatives at this point in space 8302 . aOff - The offset of each auxiliary field in u[] 8303 . aOff_x - The offset of each auxiliary field in u_x[] 8304 . a - The auxiliary field values at this point in space 8305 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8306 . a_x - The auxiliary field derivatives at this point in space 8307 . t - The current time 8308 . x - The coordinates of this point 8309 . numConstants - The number of constants 8310 . constants - The value of each constant 8311 - f - The value of the function at this point in space 8312 8313 Note: 8314 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. 8315 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 8316 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8317 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8318 8319 Level: intermediate 8320 8321 Developer Notes: 8322 This API is specific to only particular usage of `DM` 8323 8324 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8325 8326 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabel()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8327 @*/ 8328 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) 8329 { 8330 PetscFunctionBegin; 8331 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8332 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8333 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8334 PetscUseTypeMethod(dm, projectfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8335 PetscFunctionReturn(PETSC_SUCCESS); 8336 } 8337 8338 /*@C 8339 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. 8340 8341 Not Collective 8342 8343 Input Parameters: 8344 + dm - The `DM` 8345 . time - The time 8346 . label - The `DMLabel` marking the portion of the domain to output 8347 . numIds - The number of label ids to use 8348 . ids - The label ids to use for marking 8349 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8350 . comps - The components to set in the output, or `NULL` for all components 8351 . U - The input field vector 8352 . funcs - The functions to evaluate, one per field 8353 - mode - The insertion mode for values 8354 8355 Output Parameter: 8356 . X - The output vector 8357 8358 Calling sequence of `funcs`: 8359 + dim - The spatial dimension 8360 . Nf - The number of input fields 8361 . NfAux - The number of input auxiliary fields 8362 . uOff - The offset of each field in u[] 8363 . uOff_x - The offset of each field in u_x[] 8364 . u - The field values at this point in space 8365 . u_t - The field time derivative at this point in space (or NULL) 8366 . u_x - The field derivatives at this point in space 8367 . aOff - The offset of each auxiliary field in u[] 8368 . aOff_x - The offset of each auxiliary field in u_x[] 8369 . a - The auxiliary field values at this point in space 8370 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8371 . a_x - The auxiliary field derivatives at this point in space 8372 . t - The current time 8373 . x - The coordinates of this point 8374 . numConstants - The number of constants 8375 . constants - The value of each constant 8376 - f - The value of the function at this point in space 8377 8378 Note: 8379 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. 8380 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 8381 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8382 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8383 8384 Level: intermediate 8385 8386 Developer Notes: 8387 This API is specific to only particular usage of `DM` 8388 8389 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8390 8391 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8392 @*/ 8393 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) 8394 { 8395 DM dmIn; 8396 Vec localU, localX; 8397 8398 PetscFunctionBegin; 8399 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8400 PetscCall(VecGetDM(U, &dmIn)); 8401 PetscCall(DMGetLocalVector(dmIn, &localU)); 8402 PetscCall(DMGetLocalVector(dm, &localX)); 8403 PetscCall(VecSet(localX, 0.)); 8404 PetscCall(DMGlobalToLocalBegin(dmIn, U, mode, localU)); 8405 PetscCall(DMGlobalToLocalEnd(dmIn, U, mode, localU)); 8406 PetscCall(DMProjectFieldLabelLocal(dm, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX)); 8407 PetscCall(DMLocalToGlobalBegin(dm, localX, mode, X)); 8408 PetscCall(DMLocalToGlobalEnd(dm, localX, mode, X)); 8409 PetscCall(DMRestoreLocalVector(dm, &localX)); 8410 PetscCall(DMRestoreLocalVector(dmIn, &localU)); 8411 PetscFunctionReturn(PETSC_SUCCESS); 8412 } 8413 8414 /*@C 8415 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. 8416 8417 Not Collective 8418 8419 Input Parameters: 8420 + dm - The `DM` 8421 . time - The time 8422 . label - The `DMLabel` marking the portion of the domain boundary to output 8423 . numIds - The number of label ids to use 8424 . ids - The label ids to use for marking 8425 . Nc - The number of components to set in the output, or `PETSC_DETERMINE` for all components 8426 . comps - The components to set in the output, or `NULL` for all components 8427 . localU - The input field vector 8428 . funcs - The functions to evaluate, one per field 8429 - mode - The insertion mode for values 8430 8431 Output Parameter: 8432 . localX - The output vector 8433 8434 Calling sequence of `funcs`: 8435 + dim - The spatial dimension 8436 . Nf - The number of input fields 8437 . NfAux - The number of input auxiliary fields 8438 . uOff - The offset of each field in u[] 8439 . uOff_x - The offset of each field in u_x[] 8440 . u - The field values at this point in space 8441 . u_t - The field time derivative at this point in space (or NULL) 8442 . u_x - The field derivatives at this point in space 8443 . aOff - The offset of each auxiliary field in u[] 8444 . aOff_x - The offset of each auxiliary field in u_x[] 8445 . a - The auxiliary field values at this point in space 8446 . a_t - The auxiliary field time derivative at this point in space (or NULL) 8447 . a_x - The auxiliary field derivatives at this point in space 8448 . t - The current time 8449 . x - The coordinates of this point 8450 . n - The face normal 8451 . numConstants - The number of constants 8452 . constants - The value of each constant 8453 - f - The value of the function at this point in space 8454 8455 Note: 8456 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. 8457 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 8458 a subdomain. You can also output a different number of fields than the input, with different discretizations. Last the auxiliary `DM`, attached to the 8459 auxiliary field vector, which is attached to dm, can also be different. It can have a different topology, number of fields, and discretizations. 8460 8461 Level: intermediate 8462 8463 Developer Notes: 8464 This API is specific to only particular usage of `DM` 8465 8466 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8467 8468 .seealso: [](ch_dmbase), `DM`, `DMProjectField()`, `DMProjectFieldLabelLocal()`, `DMProjectFunction()`, `DMComputeL2Diff()` 8469 @*/ 8470 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) 8471 { 8472 PetscFunctionBegin; 8473 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8474 PetscValidHeaderSpecific(localU, VEC_CLASSID, 8); 8475 PetscValidHeaderSpecific(localX, VEC_CLASSID, 11); 8476 PetscUseTypeMethod(dm, projectbdfieldlabellocal, time, label, numIds, ids, Nc, comps, localU, funcs, mode, localX); 8477 PetscFunctionReturn(PETSC_SUCCESS); 8478 } 8479 8480 /*@C 8481 DMComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h. 8482 8483 Collective 8484 8485 Input Parameters: 8486 + dm - The `DM` 8487 . time - The time 8488 . funcs - The functions to evaluate for each field component 8489 . ctxs - Optional array of contexts to pass to each function, or NULL. 8490 - X - The coefficient vector u_h, a global vector 8491 8492 Output Parameter: 8493 . diff - The diff ||u - u_h||_2 8494 8495 Level: developer 8496 8497 Developer Notes: 8498 This API is specific to only particular usage of `DM` 8499 8500 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8501 8502 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2FieldDiff()`, `DMComputeL2GradientDiff()` 8503 @*/ 8504 PetscErrorCode DMComputeL2Diff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) 8505 { 8506 PetscFunctionBegin; 8507 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8508 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8509 PetscUseTypeMethod(dm, computel2diff, time, funcs, ctxs, X, diff); 8510 PetscFunctionReturn(PETSC_SUCCESS); 8511 } 8512 8513 /*@C 8514 DMComputeL2GradientDiff - This function computes the L_2 difference between the gradient of a function u and an FEM interpolant solution grad u_h. 8515 8516 Collective 8517 8518 Input Parameters: 8519 + dm - The `DM` 8520 . time - The time 8521 . funcs - The gradient functions to evaluate for each field component 8522 . ctxs - Optional array of contexts to pass to each function, or NULL. 8523 . X - The coefficient vector u_h, a global vector 8524 - n - The vector to project along 8525 8526 Output Parameter: 8527 . diff - The diff ||(grad u - grad u_h) . n||_2 8528 8529 Level: developer 8530 8531 Developer Notes: 8532 This API is specific to only particular usage of `DM` 8533 8534 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8535 8536 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2Diff()`, `DMComputeL2FieldDiff()` 8537 @*/ 8538 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) 8539 { 8540 PetscFunctionBegin; 8541 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8542 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8543 PetscUseTypeMethod(dm, computel2gradientdiff, time, funcs, ctxs, X, n, diff); 8544 PetscFunctionReturn(PETSC_SUCCESS); 8545 } 8546 8547 /*@C 8548 DMComputeL2FieldDiff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h, separated into field components. 8549 8550 Collective 8551 8552 Input Parameters: 8553 + dm - The `DM` 8554 . time - The time 8555 . funcs - The functions to evaluate for each field component 8556 . ctxs - Optional array of contexts to pass to each function, or NULL. 8557 - X - The coefficient vector u_h, a global vector 8558 8559 Output Parameter: 8560 . diff - The array of differences, ||u^f - u^f_h||_2 8561 8562 Level: developer 8563 8564 Developer Notes: 8565 This API is specific to only particular usage of `DM` 8566 8567 The notes need to provide some information about what has to be provided to the `DM` to be able to perform the computation. 8568 8569 .seealso: [](ch_dmbase), `DM`, `DMProjectFunction()`, `DMComputeL2GradientDiff()` 8570 @*/ 8571 PetscErrorCode DMComputeL2FieldDiff(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) 8572 { 8573 PetscFunctionBegin; 8574 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8575 PetscValidHeaderSpecific(X, VEC_CLASSID, 5); 8576 PetscUseTypeMethod(dm, computel2fielddiff, time, funcs, ctxs, X, diff); 8577 PetscFunctionReturn(PETSC_SUCCESS); 8578 } 8579 8580 /*@C 8581 DMGetNeighbors - Gets an array containing the MPI ranks of all the processes neighbors 8582 8583 Not Collective 8584 8585 Input Parameter: 8586 . dm - The `DM` 8587 8588 Output Parameters: 8589 + nranks - the number of neighbours 8590 - ranks - the neighbors ranks 8591 8592 Level: beginner 8593 8594 Note: 8595 Do not free the array, it is freed when the `DM` is destroyed. 8596 8597 .seealso: [](ch_dmbase), `DM`, `DMDAGetNeighbors()`, `PetscSFGetRootRanks()` 8598 @*/ 8599 PetscErrorCode DMGetNeighbors(DM dm, PetscInt *nranks, const PetscMPIInt *ranks[]) 8600 { 8601 PetscFunctionBegin; 8602 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8603 PetscUseTypeMethod(dm, getneighbors, nranks, ranks); 8604 PetscFunctionReturn(PETSC_SUCCESS); 8605 } 8606 8607 #include <petsc/private/matimpl.h> /* Needed because of coloring->ctype below */ 8608 8609 /* 8610 Converts the input vector to a ghosted vector and then calls the standard coloring code. 8611 This must be a different function because it requires DM which is not defined in the Mat library 8612 */ 8613 static PetscErrorCode MatFDColoringApply_AIJDM(Mat J, MatFDColoring coloring, Vec x1, void *sctx) 8614 { 8615 PetscFunctionBegin; 8616 if (coloring->ctype == IS_COLORING_LOCAL) { 8617 Vec x1local; 8618 DM dm; 8619 PetscCall(MatGetDM(J, &dm)); 8620 PetscCheck(dm, PetscObjectComm((PetscObject)J), PETSC_ERR_ARG_INCOMP, "IS_COLORING_LOCAL requires a DM"); 8621 PetscCall(DMGetLocalVector(dm, &x1local)); 8622 PetscCall(DMGlobalToLocalBegin(dm, x1, INSERT_VALUES, x1local)); 8623 PetscCall(DMGlobalToLocalEnd(dm, x1, INSERT_VALUES, x1local)); 8624 x1 = x1local; 8625 } 8626 PetscCall(MatFDColoringApply_AIJ(J, coloring, x1, sctx)); 8627 if (coloring->ctype == IS_COLORING_LOCAL) { 8628 DM dm; 8629 PetscCall(MatGetDM(J, &dm)); 8630 PetscCall(DMRestoreLocalVector(dm, &x1)); 8631 } 8632 PetscFunctionReturn(PETSC_SUCCESS); 8633 } 8634 8635 /*@ 8636 MatFDColoringUseDM - allows a `MatFDColoring` object to use the `DM` associated with the matrix to compute a `IS_COLORING_LOCAL` coloring 8637 8638 Input Parameters: 8639 + coloring - The matrix to get the `DM` from 8640 - fdcoloring - the `MatFDColoring` object 8641 8642 Level: advanced 8643 8644 Developer Notes: 8645 this routine exists because the PETSc `Mat` library does not know about the `DM` objects 8646 8647 .seealso: [](ch_dmbase), `DM`, `MatFDColoring`, `MatFDColoringCreate()`, `ISColoringType` 8648 @*/ 8649 PetscErrorCode MatFDColoringUseDM(Mat coloring, MatFDColoring fdcoloring) 8650 { 8651 PetscFunctionBegin; 8652 coloring->ops->fdcoloringapply = MatFDColoringApply_AIJDM; 8653 PetscFunctionReturn(PETSC_SUCCESS); 8654 } 8655 8656 /*@ 8657 DMGetCompatibility - determine if two `DM`s are compatible 8658 8659 Collective 8660 8661 Input Parameters: 8662 + dm1 - the first `DM` 8663 - dm2 - the second `DM` 8664 8665 Output Parameters: 8666 + compatible - whether or not the two `DM`s are compatible 8667 - set - whether or not the compatible value was actually determined and set 8668 8669 Level: advanced 8670 8671 Notes: 8672 Two `DM`s are deemed compatible if they represent the same parallel decomposition 8673 of the same topology. This implies that the section (field data) on one 8674 "makes sense" with respect to the topology and parallel decomposition of the other. 8675 Loosely speaking, compatible `DM`s represent the same domain and parallel 8676 decomposition, but hold different data. 8677 8678 Typically, one would confirm compatibility if intending to simultaneously iterate 8679 over a pair of vectors obtained from different `DM`s. 8680 8681 For example, two `DMDA` objects are compatible if they have the same local 8682 and global sizes and the same stencil width. They can have different numbers 8683 of degrees of freedom per node. Thus, one could use the node numbering from 8684 either `DM` in bounds for a loop over vectors derived from either `DM`. 8685 8686 Consider the operation of summing data living on a 2-dof `DMDA` to data living 8687 on a 1-dof `DMDA`, which should be compatible, as in the following snippet. 8688 .vb 8689 ... 8690 PetscCall(DMGetCompatibility(da1,da2,&compatible,&set)); 8691 if (set && compatible) { 8692 PetscCall(DMDAVecGetArrayDOF(da1,vec1,&arr1)); 8693 PetscCall(DMDAVecGetArrayDOF(da2,vec2,&arr2)); 8694 PetscCall(DMDAGetCorners(da1,&x,&y,NULL,&m,&n,NULL)); 8695 for (j=y; j<y+n; ++j) { 8696 for (i=x; i<x+m, ++i) { 8697 arr1[j][i][0] = arr2[j][i][0] + arr2[j][i][1]; 8698 } 8699 } 8700 PetscCall(DMDAVecRestoreArrayDOF(da1,vec1,&arr1)); 8701 PetscCall(DMDAVecRestoreArrayDOF(da2,vec2,&arr2)); 8702 } else { 8703 SETERRQ(PetscObjectComm((PetscObject)da1,PETSC_ERR_ARG_INCOMP,"DMDA objects incompatible"); 8704 } 8705 ... 8706 .ve 8707 8708 Checking compatibility might be expensive for a given implementation of `DM`, 8709 or might be impossible to unambiguously confirm or deny. For this reason, 8710 this function may decline to determine compatibility, and hence users should 8711 always check the "set" output parameter. 8712 8713 A `DM` is always compatible with itself. 8714 8715 In the current implementation, `DM`s which live on "unequal" communicators 8716 (MPI_UNEQUAL in the terminology of MPI_Comm_compare()) are always deemed 8717 incompatible. 8718 8719 This function is labeled "Collective," as information about all subdomains 8720 is required on each rank. However, in `DM` implementations which store all this 8721 information locally, this function may be merely "Logically Collective". 8722 8723 Developer Notes: 8724 Compatibility is assumed to be a symmetric concept; `DM` A is compatible with `DM` B 8725 iff B is compatible with A. Thus, this function checks the implementations 8726 of both dm and dmc (if they are of different types), attempting to determine 8727 compatibility. It is left to `DM` implementers to ensure that symmetry is 8728 preserved. The simplest way to do this is, when implementing type-specific 8729 logic for this function, is to check for existing logic in the implementation 8730 of other `DM` types and let *set = PETSC_FALSE if found. 8731 8732 .seealso: [](ch_dmbase), `DM`, `DMDACreateCompatibleDMDA()`, `DMStagCreateCompatibleDMStag()` 8733 @*/ 8734 PetscErrorCode DMGetCompatibility(DM dm1, DM dm2, PetscBool *compatible, PetscBool *set) 8735 { 8736 PetscMPIInt compareResult; 8737 DMType type, type2; 8738 PetscBool sameType; 8739 8740 PetscFunctionBegin; 8741 PetscValidHeaderSpecific(dm1, DM_CLASSID, 1); 8742 PetscValidHeaderSpecific(dm2, DM_CLASSID, 2); 8743 8744 /* Declare a DM compatible with itself */ 8745 if (dm1 == dm2) { 8746 *set = PETSC_TRUE; 8747 *compatible = PETSC_TRUE; 8748 PetscFunctionReturn(PETSC_SUCCESS); 8749 } 8750 8751 /* Declare a DM incompatible with a DM that lives on an "unequal" 8752 communicator. Note that this does not preclude compatibility with 8753 DMs living on "congruent" or "similar" communicators, but this must be 8754 determined by the implementation-specific logic */ 8755 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)dm1), PetscObjectComm((PetscObject)dm2), &compareResult)); 8756 if (compareResult == MPI_UNEQUAL) { 8757 *set = PETSC_TRUE; 8758 *compatible = PETSC_FALSE; 8759 PetscFunctionReturn(PETSC_SUCCESS); 8760 } 8761 8762 /* Pass to the implementation-specific routine, if one exists. */ 8763 if (dm1->ops->getcompatibility) { 8764 PetscUseTypeMethod(dm1, getcompatibility, dm2, compatible, set); 8765 if (*set) PetscFunctionReturn(PETSC_SUCCESS); 8766 } 8767 8768 /* If dm1 and dm2 are of different types, then attempt to check compatibility 8769 with an implementation of this function from dm2 */ 8770 PetscCall(DMGetType(dm1, &type)); 8771 PetscCall(DMGetType(dm2, &type2)); 8772 PetscCall(PetscStrcmp(type, type2, &sameType)); 8773 if (!sameType && dm2->ops->getcompatibility) { 8774 PetscUseTypeMethod(dm2, getcompatibility, dm1, compatible, set); /* Note argument order */ 8775 } else { 8776 *set = PETSC_FALSE; 8777 } 8778 PetscFunctionReturn(PETSC_SUCCESS); 8779 } 8780 8781 /*@C 8782 DMMonitorSet - Sets an additional monitor function that is to be used after a solve to monitor discretization performance. 8783 8784 Logically Collective 8785 8786 Input Parameters: 8787 + dm - the `DM` 8788 . f - the monitor function 8789 . mctx - [optional] user-defined context for private data for the monitor routine (use `NULL` if no context is desired) 8790 - monitordestroy - [optional] routine that frees monitor context (may be `NULL`) 8791 8792 Options Database Key: 8793 . -dm_monitor_cancel - cancels all monitors that have been hardwired into a code by calls to `DMMonitorSet()`, but 8794 does not cancel those set via the options database. 8795 8796 Level: intermediate 8797 8798 Note: 8799 Several different monitoring routines may be set by calling 8800 `DMMonitorSet()` multiple times or with `DMMonitorSetFromOptions()`; all will be called in the 8801 order in which they were set. 8802 8803 Fortran Notes: 8804 Only a single monitor function can be set for each `DM` object 8805 8806 Developer Notes: 8807 This API has a generic name but seems specific to a very particular aspect of the use of `DM` 8808 8809 .seealso: [](ch_dmbase), `DM`, `DMMonitorCancel()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8810 @*/ 8811 PetscErrorCode DMMonitorSet(DM dm, PetscErrorCode (*f)(DM, void *), void *mctx, PetscErrorCode (*monitordestroy)(void **)) 8812 { 8813 PetscInt m; 8814 8815 PetscFunctionBegin; 8816 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8817 for (m = 0; m < dm->numbermonitors; ++m) { 8818 PetscBool identical; 8819 8820 PetscCall(PetscMonitorCompare((PetscErrorCode(*)(void))f, mctx, monitordestroy, (PetscErrorCode(*)(void))dm->monitor[m], dm->monitorcontext[m], dm->monitordestroy[m], &identical)); 8821 if (identical) PetscFunctionReturn(PETSC_SUCCESS); 8822 } 8823 PetscCheck(dm->numbermonitors < MAXDMMONITORS, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Too many monitors set"); 8824 dm->monitor[dm->numbermonitors] = f; 8825 dm->monitordestroy[dm->numbermonitors] = monitordestroy; 8826 dm->monitorcontext[dm->numbermonitors++] = (void *)mctx; 8827 PetscFunctionReturn(PETSC_SUCCESS); 8828 } 8829 8830 /*@ 8831 DMMonitorCancel - Clears all the monitor functions for a `DM` object. 8832 8833 Logically Collective 8834 8835 Input Parameter: 8836 . dm - the DM 8837 8838 Options Database Key: 8839 . -dm_monitor_cancel - cancels all monitors that have been hardwired 8840 into a code by calls to `DMonitorSet()`, but does not cancel those 8841 set via the options database 8842 8843 Level: intermediate 8844 8845 Note: 8846 There is no way to clear one specific monitor from a `DM` object. 8847 8848 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()`, `DMMonitor()` 8849 @*/ 8850 PetscErrorCode DMMonitorCancel(DM dm) 8851 { 8852 PetscInt m; 8853 8854 PetscFunctionBegin; 8855 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8856 for (m = 0; m < dm->numbermonitors; ++m) { 8857 if (dm->monitordestroy[m]) PetscCall((*dm->monitordestroy[m])(&dm->monitorcontext[m])); 8858 } 8859 dm->numbermonitors = 0; 8860 PetscFunctionReturn(PETSC_SUCCESS); 8861 } 8862 8863 /*@C 8864 DMMonitorSetFromOptions - Sets a monitor function and viewer appropriate for the type indicated by the user 8865 8866 Collective 8867 8868 Input Parameters: 8869 + dm - `DM` object you wish to monitor 8870 . name - the monitor type one is seeking 8871 . help - message indicating what monitoring is done 8872 . manual - manual page for the monitor 8873 . monitor - the monitor function 8874 - 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 8875 8876 Output Parameter: 8877 . flg - Flag set if the monitor was created 8878 8879 Level: developer 8880 8881 .seealso: [](ch_dmbase), `DM`, `PetscOptionsGetViewer()`, `PetscOptionsGetReal()`, `PetscOptionsHasName()`, `PetscOptionsGetString()`, 8882 `PetscOptionsGetIntArray()`, `PetscOptionsGetRealArray()`, `PetscOptionsBool()` 8883 `PetscOptionsInt()`, `PetscOptionsString()`, `PetscOptionsReal()`, 8884 `PetscOptionsName()`, `PetscOptionsBegin()`, `PetscOptionsEnd()`, `PetscOptionsHeadBegin()`, 8885 `PetscOptionsStringArray()`, `PetscOptionsRealArray()`, `PetscOptionsScalar()`, 8886 `PetscOptionsBoolGroupBegin()`, `PetscOptionsBoolGroup()`, `PetscOptionsBoolGroupEnd()`, 8887 `PetscOptionsFList()`, `PetscOptionsEList()`, `DMMonitor()`, `DMMonitorSet()` 8888 @*/ 8889 PetscErrorCode DMMonitorSetFromOptions(DM dm, const char name[], const char help[], const char manual[], PetscErrorCode (*monitor)(DM, void *), PetscErrorCode (*monitorsetup)(DM, PetscViewerAndFormat *), PetscBool *flg) 8890 { 8891 PetscViewer viewer; 8892 PetscViewerFormat format; 8893 8894 PetscFunctionBegin; 8895 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8896 PetscCall(PetscOptionsGetViewer(PetscObjectComm((PetscObject)dm), ((PetscObject)dm)->options, ((PetscObject)dm)->prefix, name, &viewer, &format, flg)); 8897 if (*flg) { 8898 PetscViewerAndFormat *vf; 8899 8900 PetscCall(PetscViewerAndFormatCreate(viewer, format, &vf)); 8901 PetscCall(PetscOptionsRestoreViewer(&viewer)); 8902 if (monitorsetup) PetscCall((*monitorsetup)(dm, vf)); 8903 PetscCall(DMMonitorSet(dm, (PetscErrorCode(*)(DM, void *))monitor, vf, (PetscErrorCode(*)(void **))PetscViewerAndFormatDestroy)); 8904 } 8905 PetscFunctionReturn(PETSC_SUCCESS); 8906 } 8907 8908 /*@ 8909 DMMonitor - runs the user provided monitor routines, if they exist 8910 8911 Collective 8912 8913 Input Parameter: 8914 . dm - The `DM` 8915 8916 Level: developer 8917 8918 Developer Notes: 8919 Note should indicate when during the life of the `DM` the monitor is run. It appears to be 8920 related to the discretization process seems rather specialized since some `DM` have no 8921 concept of discretization. 8922 8923 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMMonitorSetFromOptions()` 8924 @*/ 8925 PetscErrorCode DMMonitor(DM dm) 8926 { 8927 PetscInt m; 8928 8929 PetscFunctionBegin; 8930 if (!dm) PetscFunctionReturn(PETSC_SUCCESS); 8931 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 8932 for (m = 0; m < dm->numbermonitors; ++m) PetscCall((*dm->monitor[m])(dm, dm->monitorcontext[m])); 8933 PetscFunctionReturn(PETSC_SUCCESS); 8934 } 8935 8936 /*@ 8937 DMComputeError - Computes the error assuming the user has provided the exact solution functions 8938 8939 Collective 8940 8941 Input Parameters: 8942 + dm - The `DM` 8943 - sol - The solution vector 8944 8945 Input/Output Parameter: 8946 . errors - An array of length Nf, the number of fields, or `NULL` for no output; on output 8947 contains the error in each field 8948 8949 Output Parameter: 8950 . errorVec - A vector to hold the cellwise error (may be `NULL`) 8951 8952 Level: developer 8953 8954 Note: 8955 The exact solutions come from the `PetscDS` object, and the time comes from `DMGetOutputSequenceNumber()`. 8956 8957 .seealso: [](ch_dmbase), `DM`, `DMMonitorSet()`, `DMGetRegionNumDS()`, `PetscDSGetExactSolution()`, `DMGetOutputSequenceNumber()` 8958 @*/ 8959 PetscErrorCode DMComputeError(DM dm, Vec sol, PetscReal errors[], Vec *errorVec) 8960 { 8961 PetscErrorCode (**exactSol)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar[], void *); 8962 void **ctxs; 8963 PetscReal time; 8964 PetscInt Nf, f, Nds, s; 8965 8966 PetscFunctionBegin; 8967 PetscCall(DMGetNumFields(dm, &Nf)); 8968 PetscCall(PetscCalloc2(Nf, &exactSol, Nf, &ctxs)); 8969 PetscCall(DMGetNumDS(dm, &Nds)); 8970 for (s = 0; s < Nds; ++s) { 8971 PetscDS ds; 8972 DMLabel label; 8973 IS fieldIS; 8974 const PetscInt *fields; 8975 PetscInt dsNf; 8976 8977 PetscCall(DMGetRegionNumDS(dm, s, &label, &fieldIS, &ds, NULL)); 8978 PetscCall(PetscDSGetNumFields(ds, &dsNf)); 8979 if (fieldIS) PetscCall(ISGetIndices(fieldIS, &fields)); 8980 for (f = 0; f < dsNf; ++f) { 8981 const PetscInt field = fields[f]; 8982 PetscCall(PetscDSGetExactSolution(ds, field, &exactSol[field], &ctxs[field])); 8983 } 8984 if (fieldIS) PetscCall(ISRestoreIndices(fieldIS, &fields)); 8985 } 8986 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); 8987 PetscCall(DMGetOutputSequenceNumber(dm, NULL, &time)); 8988 if (errors) PetscCall(DMComputeL2FieldDiff(dm, time, exactSol, ctxs, sol, errors)); 8989 if (errorVec) { 8990 DM edm; 8991 DMPolytopeType ct; 8992 PetscBool simplex; 8993 PetscInt dim, cStart, Nf; 8994 8995 PetscCall(DMClone(dm, &edm)); 8996 PetscCall(DMGetDimension(edm, &dim)); 8997 PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, NULL)); 8998 PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 8999 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct) + 1 ? PETSC_TRUE : PETSC_FALSE; 9000 PetscCall(DMGetNumFields(dm, &Nf)); 9001 for (f = 0; f < Nf; ++f) { 9002 PetscFE fe, efe; 9003 PetscQuadrature q; 9004 const char *name; 9005 9006 PetscCall(DMGetField(dm, f, NULL, (PetscObject *)&fe)); 9007 PetscCall(PetscFECreateLagrange(PETSC_COMM_SELF, dim, Nf, simplex, 0, PETSC_DETERMINE, &efe)); 9008 PetscCall(PetscObjectGetName((PetscObject)fe, &name)); 9009 PetscCall(PetscObjectSetName((PetscObject)efe, name)); 9010 PetscCall(PetscFEGetQuadrature(fe, &q)); 9011 PetscCall(PetscFESetQuadrature(efe, q)); 9012 PetscCall(DMSetField(edm, f, NULL, (PetscObject)efe)); 9013 PetscCall(PetscFEDestroy(&efe)); 9014 } 9015 PetscCall(DMCreateDS(edm)); 9016 9017 PetscCall(DMCreateGlobalVector(edm, errorVec)); 9018 PetscCall(PetscObjectSetName((PetscObject)*errorVec, "Error")); 9019 PetscCall(DMPlexComputeL2DiffVec(dm, time, exactSol, ctxs, sol, *errorVec)); 9020 PetscCall(DMDestroy(&edm)); 9021 } 9022 PetscCall(PetscFree2(exactSol, ctxs)); 9023 PetscFunctionReturn(PETSC_SUCCESS); 9024 } 9025 9026 /*@ 9027 DMGetNumAuxiliaryVec - Get the number of auxiliary vectors associated with this `DM` 9028 9029 Not Collective 9030 9031 Input Parameter: 9032 . dm - The `DM` 9033 9034 Output Parameter: 9035 . numAux - The number of auxiliary data vectors 9036 9037 Level: advanced 9038 9039 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMGetAuxiliaryVec()` 9040 @*/ 9041 PetscErrorCode DMGetNumAuxiliaryVec(DM dm, PetscInt *numAux) 9042 { 9043 PetscFunctionBegin; 9044 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9045 PetscCall(PetscHMapAuxGetSize(dm->auxData, numAux)); 9046 PetscFunctionReturn(PETSC_SUCCESS); 9047 } 9048 9049 /*@ 9050 DMGetAuxiliaryVec - Get the auxiliary vector for region specified by the given label and value, and equation part 9051 9052 Not Collective 9053 9054 Input Parameters: 9055 + dm - The `DM` 9056 . label - The `DMLabel` 9057 . value - The label value indicating the region 9058 - part - The equation part, or 0 if unused 9059 9060 Output Parameter: 9061 . aux - The `Vec` holding auxiliary field data 9062 9063 Level: advanced 9064 9065 Note: 9066 If no auxiliary vector is found for this (label, value), (NULL, 0, 0) is checked as well. 9067 9068 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryLabels()` 9069 @*/ 9070 PetscErrorCode DMGetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec *aux) 9071 { 9072 PetscHashAuxKey key, wild = {NULL, 0, 0}; 9073 PetscBool has; 9074 9075 PetscFunctionBegin; 9076 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9077 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9078 key.label = label; 9079 key.value = value; 9080 key.part = part; 9081 PetscCall(PetscHMapAuxHas(dm->auxData, key, &has)); 9082 if (has) PetscCall(PetscHMapAuxGet(dm->auxData, key, aux)); 9083 else PetscCall(PetscHMapAuxGet(dm->auxData, wild, aux)); 9084 PetscFunctionReturn(PETSC_SUCCESS); 9085 } 9086 9087 /*@ 9088 DMSetAuxiliaryVec - Set an auxiliary vector for region specified by the given label and value, and equation part 9089 9090 Not Collective because auxiliary vectors are not parallel 9091 9092 Input Parameters: 9093 + dm - The `DM` 9094 . label - The `DMLabel` 9095 . value - The label value indicating the region 9096 . part - The equation part, or 0 if unused 9097 - aux - The `Vec` holding auxiliary field data 9098 9099 Level: advanced 9100 9101 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMGetAuxiliaryLabels()`, `DMCopyAuxiliaryVec()` 9102 @*/ 9103 PetscErrorCode DMSetAuxiliaryVec(DM dm, DMLabel label, PetscInt value, PetscInt part, Vec aux) 9104 { 9105 Vec old; 9106 PetscHashAuxKey key; 9107 9108 PetscFunctionBegin; 9109 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9110 if (label) PetscValidHeaderSpecific(label, DMLABEL_CLASSID, 2); 9111 key.label = label; 9112 key.value = value; 9113 key.part = part; 9114 PetscCall(PetscHMapAuxGet(dm->auxData, key, &old)); 9115 PetscCall(PetscObjectReference((PetscObject)aux)); 9116 if (!aux) PetscCall(PetscHMapAuxDel(dm->auxData, key)); 9117 else PetscCall(PetscHMapAuxSet(dm->auxData, key, aux)); 9118 PetscCall(VecDestroy(&old)); 9119 PetscFunctionReturn(PETSC_SUCCESS); 9120 } 9121 9122 /*@C 9123 DMGetAuxiliaryLabels - Get the labels, values, and parts for all auxiliary vectors in this `DM` 9124 9125 Not Collective 9126 9127 Input Parameter: 9128 . dm - The `DM` 9129 9130 Output Parameters: 9131 + labels - The `DMLabel`s for each `Vec` 9132 . values - The label values for each `Vec` 9133 - parts - The equation parts for each `Vec` 9134 9135 Level: advanced 9136 9137 Note: 9138 The arrays passed in must be at least as large as `DMGetNumAuxiliaryVec()`. 9139 9140 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()`, `DMCopyAuxiliaryVec()` 9141 @*/ 9142 PetscErrorCode DMGetAuxiliaryLabels(DM dm, DMLabel labels[], PetscInt values[], PetscInt parts[]) 9143 { 9144 PetscHashAuxKey *keys; 9145 PetscInt n, i, off = 0; 9146 9147 PetscFunctionBegin; 9148 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9149 PetscAssertPointer(labels, 2); 9150 PetscAssertPointer(values, 3); 9151 PetscAssertPointer(parts, 4); 9152 PetscCall(DMGetNumAuxiliaryVec(dm, &n)); 9153 PetscCall(PetscMalloc1(n, &keys)); 9154 PetscCall(PetscHMapAuxGetKeys(dm->auxData, &off, keys)); 9155 for (i = 0; i < n; ++i) { 9156 labels[i] = keys[i].label; 9157 values[i] = keys[i].value; 9158 parts[i] = keys[i].part; 9159 } 9160 PetscCall(PetscFree(keys)); 9161 PetscFunctionReturn(PETSC_SUCCESS); 9162 } 9163 9164 /*@ 9165 DMCopyAuxiliaryVec - Copy the auxiliary vector data on a `DM` to a new `DM` 9166 9167 Not Collective 9168 9169 Input Parameter: 9170 . dm - The `DM` 9171 9172 Output Parameter: 9173 . dmNew - The new `DM`, now with the same auxiliary data 9174 9175 Level: advanced 9176 9177 Note: 9178 This is a shallow copy of the auxiliary vectors 9179 9180 .seealso: [](ch_dmbase), `DM`, `DMClearAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9181 @*/ 9182 PetscErrorCode DMCopyAuxiliaryVec(DM dm, DM dmNew) 9183 { 9184 PetscFunctionBegin; 9185 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9186 PetscValidHeaderSpecific(dmNew, DM_CLASSID, 2); 9187 if (dm == dmNew) PetscFunctionReturn(PETSC_SUCCESS); 9188 PetscCall(DMClearAuxiliaryVec(dmNew)); 9189 9190 PetscCall(PetscHMapAuxDestroy(&dmNew->auxData)); 9191 PetscCall(PetscHMapAuxDuplicate(dm->auxData, &dmNew->auxData)); 9192 { 9193 Vec *auxData; 9194 PetscInt n, i, off = 0; 9195 9196 PetscCall(PetscHMapAuxGetSize(dmNew->auxData, &n)); 9197 PetscCall(PetscMalloc1(n, &auxData)); 9198 PetscCall(PetscHMapAuxGetVals(dmNew->auxData, &off, auxData)); 9199 for (i = 0; i < n; ++i) PetscCall(PetscObjectReference((PetscObject)auxData[i])); 9200 PetscCall(PetscFree(auxData)); 9201 } 9202 PetscFunctionReturn(PETSC_SUCCESS); 9203 } 9204 9205 /*@ 9206 DMClearAuxiliaryVec - Destroys the auxiliary vector information and creates a new empty one 9207 9208 Not Collective 9209 9210 Input Parameter: 9211 . dm - The `DM` 9212 9213 Level: advanced 9214 9215 .seealso: [](ch_dmbase), `DM`, `DMCopyAuxiliaryVec()`, `DMGetNumAuxiliaryVec()`, `DMGetAuxiliaryVec()`, `DMSetAuxiliaryVec()` 9216 @*/ 9217 PetscErrorCode DMClearAuxiliaryVec(DM dm) 9218 { 9219 Vec *auxData; 9220 PetscInt n, i, off = 0; 9221 9222 PetscFunctionBegin; 9223 PetscCall(PetscHMapAuxGetSize(dm->auxData, &n)); 9224 PetscCall(PetscMalloc1(n, &auxData)); 9225 PetscCall(PetscHMapAuxGetVals(dm->auxData, &off, auxData)); 9226 for (i = 0; i < n; ++i) PetscCall(VecDestroy(&auxData[i])); 9227 PetscCall(PetscFree(auxData)); 9228 PetscCall(PetscHMapAuxDestroy(&dm->auxData)); 9229 PetscCall(PetscHMapAuxCreate(&dm->auxData)); 9230 PetscFunctionReturn(PETSC_SUCCESS); 9231 } 9232 9233 /*@C 9234 DMPolytopeMatchOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9235 9236 Not Collective 9237 9238 Input Parameters: 9239 + ct - The `DMPolytopeType` 9240 . sourceCone - The source arrangement of faces 9241 - targetCone - The target arrangement of faces 9242 9243 Output Parameters: 9244 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9245 - found - Flag indicating that a suitable orientation was found 9246 9247 Level: advanced 9248 9249 Note: 9250 An arrangement is a face order combined with an orientation for each face 9251 9252 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9253 that labels each arrangement (face ordering plus orientation for each face). 9254 9255 See `DMPolytopeMatchVertexOrientation()` to find a new vertex orientation that takes the source vertex arrangement to the target vertex arrangement 9256 9257 .seealso: [](ch_dmbase), `DM`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetVertexOrientation()` 9258 @*/ 9259 PetscErrorCode DMPolytopeMatchOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt, PetscBool *found) 9260 { 9261 const PetscInt cS = DMPolytopeTypeGetConeSize(ct); 9262 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9263 PetscInt o, c; 9264 9265 PetscFunctionBegin; 9266 if (!nO) { 9267 *ornt = 0; 9268 *found = PETSC_TRUE; 9269 PetscFunctionReturn(PETSC_SUCCESS); 9270 } 9271 for (o = -nO; o < nO; ++o) { 9272 const PetscInt *arr = DMPolytopeTypeGetArrangement(ct, o); 9273 9274 for (c = 0; c < cS; ++c) 9275 if (sourceCone[arr[c * 2]] != targetCone[c]) break; 9276 if (c == cS) { 9277 *ornt = o; 9278 break; 9279 } 9280 } 9281 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9282 PetscFunctionReturn(PETSC_SUCCESS); 9283 } 9284 9285 /*@C 9286 DMPolytopeGetOrientation - Determine an orientation (transformation) that takes the source face arrangement to the target face arrangement 9287 9288 Not Collective 9289 9290 Input Parameters: 9291 + ct - The `DMPolytopeType` 9292 . sourceCone - The source arrangement of faces 9293 - targetCone - The target arrangement of faces 9294 9295 Output Parameter: 9296 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9297 9298 Level: advanced 9299 9300 Note: 9301 This function is the same as `DMPolytopeMatchOrientation()` except it will generate an error if no suitable orientation can be found. 9302 9303 Developer Notes: 9304 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchOrientation()` and error if none is found 9305 9306 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchOrientation()`, `DMPolytopeGetVertexOrientation()`, `DMPolytopeMatchVertexOrientation()` 9307 @*/ 9308 PetscErrorCode DMPolytopeGetOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9309 { 9310 PetscBool found; 9311 9312 PetscFunctionBegin; 9313 PetscCall(DMPolytopeMatchOrientation(ct, sourceCone, targetCone, ornt, &found)); 9314 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9315 PetscFunctionReturn(PETSC_SUCCESS); 9316 } 9317 9318 /*@C 9319 DMPolytopeMatchVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9320 9321 Not Collective 9322 9323 Input Parameters: 9324 + ct - The `DMPolytopeType` 9325 . sourceVert - The source arrangement of vertices 9326 - targetVert - The target arrangement of vertices 9327 9328 Output Parameters: 9329 + ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9330 - found - Flag indicating that a suitable orientation was found 9331 9332 Level: advanced 9333 9334 Note: 9335 An arrangement is a vertex order 9336 9337 Each orientation (transformation) is labeled with an integer from negative `DMPolytopeTypeGetNumArrangements(ct)`/2 to `DMPolytopeTypeGetNumArrangements(ct)`/2 9338 that labels each arrangement (vertex ordering). 9339 9340 See `DMPolytopeMatchOrientation()` to find a new face orientation that takes the source face arrangement to the target face arrangement 9341 9342 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeGetOrientation()`, `DMPolytopeMatchOrientation()`, `DMPolytopeTypeGetNumVertices()`, `DMPolytopeTypeGetVertexArrangement()` 9343 @*/ 9344 PetscErrorCode DMPolytopeMatchVertexOrientation(DMPolytopeType ct, const PetscInt sourceVert[], const PetscInt targetVert[], PetscInt *ornt, PetscBool *found) 9345 { 9346 const PetscInt cS = DMPolytopeTypeGetNumVertices(ct); 9347 const PetscInt nO = DMPolytopeTypeGetNumArrangements(ct) / 2; 9348 PetscInt o, c; 9349 9350 PetscFunctionBegin; 9351 if (!nO) { 9352 *ornt = 0; 9353 *found = PETSC_TRUE; 9354 PetscFunctionReturn(PETSC_SUCCESS); 9355 } 9356 for (o = -nO; o < nO; ++o) { 9357 const PetscInt *arr = DMPolytopeTypeGetVertexArrangement(ct, o); 9358 9359 for (c = 0; c < cS; ++c) 9360 if (sourceVert[arr[c]] != targetVert[c]) break; 9361 if (c == cS) { 9362 *ornt = o; 9363 break; 9364 } 9365 } 9366 *found = o == nO ? PETSC_FALSE : PETSC_TRUE; 9367 PetscFunctionReturn(PETSC_SUCCESS); 9368 } 9369 9370 /*@C 9371 DMPolytopeGetVertexOrientation - Determine an orientation (transformation) that takes the source vertex arrangement to the target vertex arrangement 9372 9373 Not Collective 9374 9375 Input Parameters: 9376 + ct - The `DMPolytopeType` 9377 . sourceCone - The source arrangement of vertices 9378 - targetCone - The target arrangement of vertices 9379 9380 Output Parameter: 9381 . ornt - The orientation (transformation) which will take the source arrangement to the target arrangement 9382 9383 Level: advanced 9384 9385 Note: 9386 This function is the same as `DMPolytopeMatchVertexOrientation()` except it errors if not orientation is possible. 9387 9388 Developer Notes: 9389 It is unclear why this function needs to exist since one can simply call `DMPolytopeMatchVertexOrientation()` and error if none is found 9390 9391 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMPolytopeMatchVertexOrientation()`, `DMPolytopeGetOrientation()` 9392 @*/ 9393 PetscErrorCode DMPolytopeGetVertexOrientation(DMPolytopeType ct, const PetscInt sourceCone[], const PetscInt targetCone[], PetscInt *ornt) 9394 { 9395 PetscBool found; 9396 9397 PetscFunctionBegin; 9398 PetscCall(DMPolytopeMatchVertexOrientation(ct, sourceCone, targetCone, ornt, &found)); 9399 PetscCheck(found, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Could not find orientation for %s", DMPolytopeTypes[ct]); 9400 PetscFunctionReturn(PETSC_SUCCESS); 9401 } 9402 9403 /*@C 9404 DMPolytopeInCellTest - Check whether a point lies inside the reference cell of given type 9405 9406 Not Collective 9407 9408 Input Parameters: 9409 + ct - The `DMPolytopeType` 9410 - point - Coordinates of the point 9411 9412 Output Parameter: 9413 . inside - Flag indicating whether the point is inside the reference cell of given type 9414 9415 Level: advanced 9416 9417 .seealso: [](ch_dmbase), `DM`, `DMPolytopeType`, `DMLocatePoints()` 9418 @*/ 9419 PetscErrorCode DMPolytopeInCellTest(DMPolytopeType ct, const PetscReal point[], PetscBool *inside) 9420 { 9421 PetscReal sum = 0.0; 9422 PetscInt d; 9423 9424 PetscFunctionBegin; 9425 *inside = PETSC_TRUE; 9426 switch (ct) { 9427 case DM_POLYTOPE_TRIANGLE: 9428 case DM_POLYTOPE_TETRAHEDRON: 9429 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) { 9430 if (point[d] < -1.0) { 9431 *inside = PETSC_FALSE; 9432 break; 9433 } 9434 sum += point[d]; 9435 } 9436 if (sum > PETSC_SMALL) { 9437 *inside = PETSC_FALSE; 9438 break; 9439 } 9440 break; 9441 case DM_POLYTOPE_QUADRILATERAL: 9442 case DM_POLYTOPE_HEXAHEDRON: 9443 for (d = 0; d < DMPolytopeTypeGetDim(ct); ++d) 9444 if (PetscAbsReal(point[d]) > 1. + PETSC_SMALL) { 9445 *inside = PETSC_FALSE; 9446 break; 9447 } 9448 break; 9449 default: 9450 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unsupported polytope type %s", DMPolytopeTypes[ct]); 9451 } 9452 PetscFunctionReturn(PETSC_SUCCESS); 9453 } 9454 9455 /*@ 9456 DMReorderSectionSetDefault - Set flag indicating whether the local section should be reordered by default 9457 9458 Logically collective 9459 9460 Input Parameters: 9461 + dm - The DM 9462 - reorder - Flag for reordering 9463 9464 Level: intermediate 9465 9466 .seealso: `DMReorderSectionGetDefault()` 9467 @*/ 9468 PetscErrorCode DMReorderSectionSetDefault(DM dm, DMReorderDefaultFlag reorder) 9469 { 9470 PetscFunctionBegin; 9471 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9472 PetscTryMethod(dm, "DMReorderSectionSetDefault_C", (DM, DMReorderDefaultFlag), (dm, reorder)); 9473 PetscFunctionReturn(PETSC_SUCCESS); 9474 } 9475 9476 /*@ 9477 DMReorderSectionGetDefault - Get flag indicating whether the local section should be reordered by default 9478 9479 Not collective 9480 9481 Input Parameter: 9482 . dm - The DM 9483 9484 Output Parameter: 9485 . reorder - Flag for reordering 9486 9487 Level: intermediate 9488 9489 .seealso: `DMReorderSetDefault()` 9490 @*/ 9491 PetscErrorCode DMReorderSectionGetDefault(DM dm, DMReorderDefaultFlag *reorder) 9492 { 9493 PetscFunctionBegin; 9494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9495 PetscAssertPointer(reorder, 2); 9496 *reorder = DM_REORDER_DEFAULT_NOTSET; 9497 PetscTryMethod(dm, "DMReorderSectionGetDefault_C", (DM, DMReorderDefaultFlag *), (dm, reorder)); 9498 PetscFunctionReturn(PETSC_SUCCESS); 9499 } 9500 9501 /*@C 9502 DMReorderSectionSetType - Set the type of local section reordering 9503 9504 Logically collective 9505 9506 Input Parameters: 9507 + dm - The DM 9508 - reorder - The reordering method 9509 9510 Level: intermediate 9511 9512 .seealso: `DMReorderSectionGetType()`, `DMReorderSectionSetDefault()` 9513 @*/ 9514 PetscErrorCode DMReorderSectionSetType(DM dm, MatOrderingType reorder) 9515 { 9516 PetscFunctionBegin; 9517 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9518 PetscTryMethod(dm, "DMReorderSectionSetType_C", (DM, MatOrderingType), (dm, reorder)); 9519 PetscFunctionReturn(PETSC_SUCCESS); 9520 } 9521 9522 /*@C 9523 DMReorderSectionGetType - Get the reordering type for the local section 9524 9525 Not collective 9526 9527 Input Parameter: 9528 . dm - The DM 9529 9530 Output Parameter: 9531 . reorder - The reordering method 9532 9533 Level: intermediate 9534 9535 .seealso: `DMReorderSetDefault()`, `DMReorderSectionGetDefault()` 9536 @*/ 9537 PetscErrorCode DMReorderSectionGetType(DM dm, MatOrderingType *reorder) 9538 { 9539 PetscFunctionBegin; 9540 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 9541 PetscAssertPointer(reorder, 2); 9542 *reorder = NULL; 9543 PetscTryMethod(dm, "DMReorderSectionGetType_C", (DM, MatOrderingType *), (dm, reorder)); 9544 PetscFunctionReturn(PETSC_SUCCESS); 9545 } 9546