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