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