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