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