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