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