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