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