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