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