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