1 #include <petsc/private/dmimpl.h> /*I "petscdm.h" I*/ 2 3 #include <petscdmplex.h> /* For DMCreateAffineCoordinates_Internal() */ 4 #include <petscsf.h> /* For DMLocatePoints() */ 5 6 PetscErrorCode DMRestrictHook_Coordinates(DM dm, DM dmc, void *ctx) 7 { 8 DM dm_coord, dmc_coord; 9 Vec coords, ccoords; 10 Mat inject; 11 12 PetscFunctionBegin; 13 PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 14 PetscCall(DMGetCoordinateDM(dmc, &dmc_coord)); 15 PetscCall(DMGetCoordinates(dm, &coords)); 16 PetscCall(DMGetCoordinates(dmc, &ccoords)); 17 if (coords && !ccoords) { 18 PetscCall(DMCreateGlobalVector(dmc_coord, &ccoords)); 19 PetscCall(PetscObjectSetName((PetscObject)ccoords, "coordinates")); 20 PetscCall(DMCreateInjection(dmc_coord, dm_coord, &inject)); 21 PetscCall(MatRestrict(inject, coords, ccoords)); 22 PetscCall(MatDestroy(&inject)); 23 PetscCall(DMSetCoordinates(dmc, ccoords)); 24 PetscCall(VecDestroy(&ccoords)); 25 } 26 PetscFunctionReturn(PETSC_SUCCESS); 27 } 28 29 static PetscErrorCode DMSubDomainHook_Coordinates(DM dm, DM subdm, void *ctx) 30 { 31 DM dm_coord, subdm_coord; 32 Vec coords, ccoords, clcoords; 33 VecScatter *scat_i, *scat_g; 34 35 PetscFunctionBegin; 36 PetscCall(DMGetCoordinateDM(dm, &dm_coord)); 37 PetscCall(DMGetCoordinateDM(subdm, &subdm_coord)); 38 PetscCall(DMGetCoordinates(dm, &coords)); 39 PetscCall(DMGetCoordinates(subdm, &ccoords)); 40 if (coords && !ccoords) { 41 PetscCall(DMCreateGlobalVector(subdm_coord, &ccoords)); 42 PetscCall(PetscObjectSetName((PetscObject)ccoords, "coordinates")); 43 PetscCall(DMCreateLocalVector(subdm_coord, &clcoords)); 44 PetscCall(PetscObjectSetName((PetscObject)clcoords, "coordinates")); 45 PetscCall(DMCreateDomainDecompositionScatters(dm_coord, 1, &subdm_coord, NULL, &scat_i, &scat_g)); 46 PetscCall(VecScatterBegin(scat_i[0], coords, ccoords, INSERT_VALUES, SCATTER_FORWARD)); 47 PetscCall(VecScatterEnd(scat_i[0], coords, ccoords, INSERT_VALUES, SCATTER_FORWARD)); 48 PetscCall(VecScatterBegin(scat_g[0], coords, clcoords, INSERT_VALUES, SCATTER_FORWARD)); 49 PetscCall(VecScatterEnd(scat_g[0], coords, clcoords, INSERT_VALUES, SCATTER_FORWARD)); 50 PetscCall(DMSetCoordinates(subdm, ccoords)); 51 PetscCall(DMSetCoordinatesLocal(subdm, clcoords)); 52 PetscCall(VecScatterDestroy(&scat_i[0])); 53 PetscCall(VecScatterDestroy(&scat_g[0])); 54 PetscCall(VecDestroy(&ccoords)); 55 PetscCall(VecDestroy(&clcoords)); 56 PetscCall(PetscFree(scat_i)); 57 PetscCall(PetscFree(scat_g)); 58 } 59 PetscFunctionReturn(PETSC_SUCCESS); 60 } 61 62 /*@ 63 DMGetCoordinateDM - Gets the `DM` that prescribes coordinate layout and scatters between global and local coordinates 64 65 Collective 66 67 Input Parameter: 68 . dm - the `DM` 69 70 Output Parameter: 71 . cdm - coordinate `DM` 72 73 Level: intermediate 74 75 .seealso: `DM`, `DMSetCoordinateDM()`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGSetCellCoordinateDM()`, 76 77 @*/ 78 PetscErrorCode DMGetCoordinateDM(DM dm, DM *cdm) 79 { 80 PetscFunctionBegin; 81 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 82 PetscAssertPointer(cdm, 2); 83 if (!dm->coordinates[0].dm) { 84 DM cdm; 85 86 PetscUseTypeMethod(dm, createcoordinatedm, &cdm); 87 PetscCall(PetscObjectSetName((PetscObject)cdm, "coordinateDM")); 88 /* Just in case the DM sets the coordinate DM when creating it (DMP4est can do this, because it may not setup 89 * until the call to CreateCoordinateDM) */ 90 PetscCall(DMDestroy(&dm->coordinates[0].dm)); 91 dm->coordinates[0].dm = cdm; 92 } 93 *cdm = dm->coordinates[0].dm; 94 PetscFunctionReturn(PETSC_SUCCESS); 95 } 96 97 /*@ 98 DMSetCoordinateDM - Sets the `DM` that prescribes coordinate layout and scatters between global and local coordinates 99 100 Logically Collective 101 102 Input Parameters: 103 + dm - the `DM` 104 - cdm - coordinate `DM` 105 106 Level: intermediate 107 108 .seealso: `DM`, `DMGetCoordinateDM()`, `DMSetCoordinates()`, `DMGetCellCoordinateDM()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, 109 `DMGSetCellCoordinateDM()` 110 @*/ 111 PetscErrorCode DMSetCoordinateDM(DM dm, DM cdm) 112 { 113 PetscFunctionBegin; 114 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 115 if (cdm) PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 116 PetscCall(PetscObjectReference((PetscObject)cdm)); 117 PetscCall(DMDestroy(&dm->coordinates[0].dm)); 118 dm->coordinates[0].dm = cdm; 119 PetscFunctionReturn(PETSC_SUCCESS); 120 } 121 122 /*@ 123 DMGetCellCoordinateDM - Gets the `DM` that prescribes cellwise coordinate layout and scatters between global and local cellwise coordinates 124 125 Collective 126 127 Input Parameter: 128 . dm - the `DM` 129 130 Output Parameter: 131 . cdm - cellwise coordinate `DM`, or `NULL` if they are not defined 132 133 Level: intermediate 134 135 Note: 136 Call `DMLocalizeCoordinates()` to automatically create cellwise coordinates for periodic geometries. 137 138 .seealso: `DM`, `DMSetCellCoordinateDM()`, `DMSetCellCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, 139 `DMLocalizeCoordinates()`, `DMSetCoordinateDM()`, `DMGetCoordinateDM()` 140 @*/ 141 PetscErrorCode DMGetCellCoordinateDM(DM dm, DM *cdm) 142 { 143 PetscFunctionBegin; 144 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 145 PetscAssertPointer(cdm, 2); 146 *cdm = dm->coordinates[1].dm; 147 PetscFunctionReturn(PETSC_SUCCESS); 148 } 149 150 /*@ 151 DMSetCellCoordinateDM - Sets the `DM` that prescribes cellwise coordinate layout and scatters between global and local cellwise coordinates 152 153 Logically Collective 154 155 Input Parameters: 156 + dm - the `DM` 157 - cdm - cellwise coordinate `DM` 158 159 Level: intermediate 160 161 Note: 162 As opposed to `DMSetCoordinateDM()` these coordinates are useful for discontinuous Galerkin methods since they support coordinate fields that are discontinuous at cell boundaries. 163 164 .seealso: `DMGetCellCoordinateDM()`, `DMSetCellCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, 165 `DMSetCoordinateDM()`, `DMGetCoordinateDM()` 166 @*/ 167 PetscErrorCode DMSetCellCoordinateDM(DM dm, DM cdm) 168 { 169 PetscInt dim; 170 171 PetscFunctionBegin; 172 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 173 if (cdm) { 174 PetscValidHeaderSpecific(cdm, DM_CLASSID, 2); 175 PetscCall(DMGetCoordinateDim(dm, &dim)); 176 dm->coordinates[1].dim = dim; 177 } 178 PetscCall(PetscObjectReference((PetscObject)cdm)); 179 PetscCall(DMDestroy(&dm->coordinates[1].dm)); 180 dm->coordinates[1].dm = cdm; 181 PetscFunctionReturn(PETSC_SUCCESS); 182 } 183 184 /*@ 185 DMGetCoordinateDim - Retrieve the dimension of the embedding space for coordinate values. For example a mesh on the surface of a sphere would have a 3 dimensional embedding space 186 187 Not Collective 188 189 Input Parameter: 190 . dm - The `DM` object 191 192 Output Parameter: 193 . dim - The embedding dimension 194 195 Level: intermediate 196 197 .seealso: `DM`, `DMSetCoordinateDim()`, `DMGetCoordinateSection()`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()` 198 @*/ 199 PetscErrorCode DMGetCoordinateDim(DM dm, PetscInt *dim) 200 { 201 PetscFunctionBegin; 202 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 203 PetscAssertPointer(dim, 2); 204 if (dm->coordinates[0].dim == PETSC_DEFAULT) dm->coordinates[0].dim = dm->dim; 205 *dim = dm->coordinates[0].dim; 206 PetscFunctionReturn(PETSC_SUCCESS); 207 } 208 209 /*@ 210 DMSetCoordinateDim - Set the dimension of the embedding space for coordinate values. 211 212 Not Collective 213 214 Input Parameters: 215 + dm - The `DM` object 216 - dim - The embedding dimension 217 218 Level: intermediate 219 220 .seealso: `DM`, `DMGetCoordinateDim()`, `DMSetCoordinateSection()`, `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()` 221 @*/ 222 PetscErrorCode DMSetCoordinateDim(DM dm, PetscInt dim) 223 { 224 PetscDS ds; 225 PetscInt Nds, n; 226 227 PetscFunctionBegin; 228 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 229 dm->coordinates[0].dim = dim; 230 if (dm->dim >= 0) { 231 PetscCall(DMGetNumDS(dm, &Nds)); 232 for (n = 0; n < Nds; ++n) { 233 PetscCall(DMGetRegionNumDS(dm, n, NULL, NULL, &ds, NULL)); 234 PetscCall(PetscDSSetCoordinateDimension(ds, dim)); 235 } 236 } 237 PetscFunctionReturn(PETSC_SUCCESS); 238 } 239 240 /*@ 241 DMGetCoordinateSection - Retrieve the `PetscSection` of coordinate values over the mesh. 242 243 Collective 244 245 Input Parameter: 246 . dm - The `DM` object 247 248 Output Parameter: 249 . section - The `PetscSection` object 250 251 Level: intermediate 252 253 Note: 254 This just retrieves the local section from the coordinate `DM`. In other words, 255 .vb 256 DMGetCoordinateDM(dm, &cdm); 257 DMGetLocalSection(cdm, §ion); 258 .ve 259 260 .seealso: `DM`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()` 261 @*/ 262 PetscErrorCode DMGetCoordinateSection(DM dm, PetscSection *section) 263 { 264 DM cdm; 265 266 PetscFunctionBegin; 267 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 268 PetscAssertPointer(section, 2); 269 PetscCall(DMGetCoordinateDM(dm, &cdm)); 270 PetscCall(DMGetLocalSection(cdm, section)); 271 PetscFunctionReturn(PETSC_SUCCESS); 272 } 273 274 /*@ 275 DMSetCoordinateSection - Set the `PetscSection` of coordinate values over the mesh. 276 277 Not Collective 278 279 Input Parameters: 280 + dm - The `DM` object 281 . dim - The embedding dimension, or `PETSC_DETERMINE` 282 - section - The `PetscSection` object 283 284 Level: intermediate 285 286 .seealso: `DM`, `DMGetCoordinateDim()`, `DMGetCoordinateSection()`, `DMGetLocalSection()`, `DMSetLocalSection()` 287 @*/ 288 PetscErrorCode DMSetCoordinateSection(DM dm, PetscInt dim, PetscSection section) 289 { 290 DM cdm; 291 292 PetscFunctionBegin; 293 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 294 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3); 295 PetscCall(DMGetCoordinateDM(dm, &cdm)); 296 PetscCall(DMSetLocalSection(cdm, section)); 297 if (dim == PETSC_DETERMINE) { 298 PetscInt d = PETSC_DEFAULT; 299 PetscInt pStart, pEnd, vStart, vEnd, v, dd; 300 301 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 302 PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd)); 303 pStart = PetscMax(vStart, pStart); 304 pEnd = PetscMin(vEnd, pEnd); 305 for (v = pStart; v < pEnd; ++v) { 306 PetscCall(PetscSectionGetDof(section, v, &dd)); 307 if (dd) { 308 d = dd; 309 break; 310 } 311 } 312 if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d)); 313 } 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 /*@ 318 DMGetCellCoordinateSection - Retrieve the `PetscSection` of cellwise coordinate values over the mesh. 319 320 Collective 321 322 Input Parameter: 323 . dm - The `DM` object 324 325 Output Parameter: 326 . section - The `PetscSection` object, or `NULL` if no cellwise coordinates are defined 327 328 Level: intermediate 329 330 Note: 331 This just retrieves the local section from the cell coordinate `DM`. In other words, 332 .vb 333 DMGetCellCoordinateDM(dm, &cdm); 334 DMGetLocalSection(cdm, §ion); 335 .ve 336 337 .seealso: `DM`, `DMGetCoordinateSection()`, `DMSetCellCoordinateSection()`, `DMGetCellCoordinateDM()`, `DMGetCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()` 338 @*/ 339 PetscErrorCode DMGetCellCoordinateSection(DM dm, PetscSection *section) 340 { 341 DM cdm; 342 343 PetscFunctionBegin; 344 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 345 PetscAssertPointer(section, 2); 346 *section = NULL; 347 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 348 if (cdm) PetscCall(DMGetLocalSection(cdm, section)); 349 PetscFunctionReturn(PETSC_SUCCESS); 350 } 351 352 /*@ 353 DMSetCellCoordinateSection - Set the `PetscSection` of cellwise coordinate values over the mesh. 354 355 Not Collective 356 357 Input Parameters: 358 + dm - The `DM` object 359 . dim - The embedding dimension, or `PETSC_DETERMINE` 360 - section - The `PetscSection` object for a cellwise layout 361 362 Level: intermediate 363 364 .seealso: `DM`, `DMGetCoordinateDim()`, `DMSetCoordinateSection()`, `DMGetCellCoordinateSection()`, `DMGetCoordinateSection()`, `DMGetCellCoordinateDM()`, `DMGetLocalSection()`, `DMSetLocalSection()` 365 @*/ 366 PetscErrorCode DMSetCellCoordinateSection(DM dm, PetscInt dim, PetscSection section) 367 { 368 DM cdm; 369 370 PetscFunctionBegin; 371 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 372 PetscValidHeaderSpecific(section, PETSC_SECTION_CLASSID, 3); 373 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 374 PetscCheck(cdm, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "No DM defined for cellwise coordinates"); 375 PetscCall(DMSetLocalSection(cdm, section)); 376 if (dim == PETSC_DETERMINE) { 377 PetscInt d = PETSC_DEFAULT; 378 PetscInt pStart, pEnd, vStart, vEnd, v, dd; 379 380 PetscCall(PetscSectionGetChart(section, &pStart, &pEnd)); 381 PetscCall(DMGetDimPoints(dm, 0, &vStart, &vEnd)); 382 pStart = PetscMax(vStart, pStart); 383 pEnd = PetscMin(vEnd, pEnd); 384 for (v = pStart; v < pEnd; ++v) { 385 PetscCall(PetscSectionGetDof(section, v, &dd)); 386 if (dd) { 387 d = dd; 388 break; 389 } 390 } 391 if (d >= 0) PetscCall(DMSetCoordinateDim(dm, d)); 392 } 393 PetscFunctionReturn(PETSC_SUCCESS); 394 } 395 396 /*@ 397 DMGetCoordinates - Gets a global vector with the coordinates associated with the `DM`. 398 399 Collective if the global vector with coordinates has not been set yet but the local vector with coordinates has been set 400 401 Input Parameter: 402 . dm - the `DM` 403 404 Output Parameter: 405 . c - global coordinate vector 406 407 Level: intermediate 408 409 Notes: 410 This is a borrowed reference, so the user should NOT destroy this vector. When the `DM` is 411 destroyed `c` will no longer be valid. 412 413 Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates), see `DMGetCoordinatesLocal()`. 414 415 For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 416 and (x_0,y_0,z_0,x_1,y_1,z_1...) 417 418 Does not work for `DMSTAG` 419 420 .seealso: `DM`, `DMDA`, `DMSetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()` 421 @*/ 422 PetscErrorCode DMGetCoordinates(DM dm, Vec *c) 423 { 424 PetscFunctionBegin; 425 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 426 PetscAssertPointer(c, 2); 427 if (!dm->coordinates[0].x && dm->coordinates[0].xl) { 428 DM cdm = NULL; 429 430 PetscCall(DMGetCoordinateDM(dm, &cdm)); 431 PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[0].x)); 432 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].x, "coordinates")); 433 PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x)); 434 PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x)); 435 } 436 *c = dm->coordinates[0].x; 437 PetscFunctionReturn(PETSC_SUCCESS); 438 } 439 440 /*@ 441 DMSetCoordinates - Sets into the `DM` a global vector that holds the coordinates 442 443 Logically Collective 444 445 Input Parameters: 446 + dm - the `DM` 447 - c - coordinate vector 448 449 Level: intermediate 450 451 Notes: 452 The coordinates do not include those for ghost points, which are in the local vector. 453 454 The vector `c` can be destroyed after the call 455 456 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()` 457 @*/ 458 PetscErrorCode DMSetCoordinates(DM dm, Vec c) 459 { 460 PetscFunctionBegin; 461 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 462 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 463 PetscCall(PetscObjectReference((PetscObject)c)); 464 PetscCall(VecDestroy(&dm->coordinates[0].x)); 465 dm->coordinates[0].x = c; 466 PetscCall(VecDestroy(&dm->coordinates[0].xl)); 467 PetscCall(DMCoarsenHookAdd(dm, DMRestrictHook_Coordinates, NULL, NULL)); 468 PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_Coordinates, NULL, NULL)); 469 PetscFunctionReturn(PETSC_SUCCESS); 470 } 471 472 /*@ 473 DMGetCellCoordinates - Gets a global vector with the cellwise coordinates associated with the `DM`. 474 475 Collective 476 477 Input Parameter: 478 . dm - the `DM` 479 480 Output Parameter: 481 . c - global coordinate vector 482 483 Level: intermediate 484 485 Notes: 486 This is a borrowed reference, so the user should NOT destroy this vector. When the `DM` is 487 destroyed `c` will no longer be valid. 488 489 Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates). 490 491 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()` 492 @*/ 493 PetscErrorCode DMGetCellCoordinates(DM dm, Vec *c) 494 { 495 PetscFunctionBegin; 496 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 497 PetscAssertPointer(c, 2); 498 if (!dm->coordinates[1].x && dm->coordinates[1].xl) { 499 DM cdm = NULL; 500 501 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 502 PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[1].x)); 503 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].x, "DG coordinates")); 504 PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x)); 505 PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x)); 506 } 507 *c = dm->coordinates[1].x; 508 PetscFunctionReturn(PETSC_SUCCESS); 509 } 510 511 /*@ 512 DMSetCellCoordinates - Sets into the `DM` a global vector that holds the cellwise coordinates 513 514 Collective 515 516 Input Parameters: 517 + dm - the `DM` 518 - c - cellwise coordinate vector 519 520 Level: intermediate 521 522 Notes: 523 The coordinates do not include those for ghost points, which are in the local vector. 524 525 The vector `c` should be destroyed by the caller. 526 527 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()` 528 @*/ 529 PetscErrorCode DMSetCellCoordinates(DM dm, Vec c) 530 { 531 PetscFunctionBegin; 532 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 533 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 534 PetscCall(PetscObjectReference((PetscObject)c)); 535 PetscCall(VecDestroy(&dm->coordinates[1].x)); 536 dm->coordinates[1].x = c; 537 PetscCall(VecDestroy(&dm->coordinates[1].xl)); 538 PetscFunctionReturn(PETSC_SUCCESS); 539 } 540 541 /*@ 542 DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that `DMGetCoordinatesLocalNoncollective()` can be used as non-collective afterwards. 543 544 Collective 545 546 Input Parameter: 547 . dm - the `DM` 548 549 Level: advanced 550 551 .seealso: `DM`, `DMSetCoordinates()`, `DMGetCoordinatesLocalNoncollective()` 552 @*/ 553 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm) 554 { 555 PetscFunctionBegin; 556 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 557 if (!dm->coordinates[0].xl && dm->coordinates[0].x) { 558 DM cdm = NULL; 559 PetscInt bs; 560 561 PetscCall(DMGetCoordinateDM(dm, &cdm)); 562 PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[0].xl)); 563 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].xl, "Local Coordinates")); 564 // If the size of the vector is 0, it will not get the right block size 565 PetscCall(VecGetBlockSize(dm->coordinates[0].x, &bs)); 566 PetscCall(VecSetBlockSize(dm->coordinates[0].xl, bs)); 567 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].xl, "coordinates")); 568 PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl)); 569 PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl)); 570 } 571 PetscFunctionReturn(PETSC_SUCCESS); 572 } 573 574 /*@ 575 DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the `DM`. 576 577 Collective the first time it is called 578 579 Input Parameter: 580 . dm - the `DM` 581 582 Output Parameter: 583 . c - coordinate vector 584 585 Level: intermediate 586 587 Notes: 588 This is a borrowed reference, so the user should NOT destroy `c` 589 590 Each process has the local and ghost coordinates 591 592 For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 593 and (x_0,y_0,z_0,x_1,y_1,z_1...) 594 595 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`, `DMGetCoordinatesLocalNoncollective()` 596 @*/ 597 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c) 598 { 599 PetscFunctionBegin; 600 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 601 PetscAssertPointer(c, 2); 602 PetscCall(DMGetCoordinatesLocalSetUp(dm)); 603 *c = dm->coordinates[0].xl; 604 PetscFunctionReturn(PETSC_SUCCESS); 605 } 606 607 /*@ 608 DMGetCoordinatesLocalNoncollective - Non-collective version of `DMGetCoordinatesLocal()`. Fails if global coordinates have been set and `DMGetCoordinatesLocalSetUp()` not called. 609 610 Not Collective 611 612 Input Parameter: 613 . dm - the `DM` 614 615 Output Parameter: 616 . c - coordinate vector 617 618 Level: advanced 619 620 Note: 621 A previous call to `DMGetCoordinatesLocal()` or `DMGetCoordinatesLocalSetUp()` ensures that a call to this function will not error. 622 623 .seealso: `DM`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinatesLocal()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()` 624 @*/ 625 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c) 626 { 627 PetscFunctionBegin; 628 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 629 PetscAssertPointer(c, 2); 630 PetscCheck(dm->coordinates[0].xl || !dm->coordinates[0].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called"); 631 *c = dm->coordinates[0].xl; 632 PetscFunctionReturn(PETSC_SUCCESS); 633 } 634 635 /*@ 636 DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and the section describing its layout. 637 638 Not Collective 639 640 Input Parameters: 641 + dm - the `DM` 642 - p - the `IS` of points whose coordinates will be returned 643 644 Output Parameters: 645 + pCoordSection - the `PetscSection` describing the layout of pCoord, i.e. each point corresponds to one point in `p`, and DOFs correspond to coordinates 646 - pCoord - the `Vec` with coordinates of points in `p` 647 648 Level: advanced 649 650 Notes: 651 `DMGetCoordinatesLocalSetUp()` must be called first. This function employs `DMGetCoordinatesLocalNoncollective()` so it is not collective. 652 653 This creates a new vector, so the user SHOULD destroy this vector 654 655 Each process has the local and ghost coordinates 656 657 For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 658 and (x_0,y_0,z_0,x_1,y_1,z_1...) 659 660 .seealso: `DM`, `DMDA`, `DMSetCoordinatesLocal()`, `DMGetCoordinatesLocal()`, `DMGetCoordinatesLocalNoncollective()`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()` 661 @*/ 662 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord) 663 { 664 DM cdm; 665 PetscSection cs, newcs; 666 Vec coords; 667 const PetscScalar *arr; 668 PetscScalar *newarr = NULL; 669 PetscInt n; 670 671 PetscFunctionBegin; 672 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 673 PetscValidHeaderSpecific(p, IS_CLASSID, 2); 674 if (pCoordSection) PetscAssertPointer(pCoordSection, 3); 675 if (pCoord) PetscAssertPointer(pCoord, 4); 676 PetscCall(DMGetCoordinateDM(dm, &cdm)); 677 PetscCall(DMGetLocalSection(cdm, &cs)); 678 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 679 PetscCheck(coords, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set"); 680 PetscCheck(cdm && cs, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported"); 681 PetscCall(VecGetArrayRead(coords, &arr)); 682 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void **)&newarr) : NULL)); 683 PetscCall(VecRestoreArrayRead(coords, &arr)); 684 if (pCoord) { 685 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 686 /* set array in two steps to mimic PETSC_OWN_POINTER */ 687 PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord)); 688 PetscCall(VecReplaceArray(*pCoord, newarr)); 689 } else { 690 PetscCall(PetscFree(newarr)); 691 } 692 if (pCoordSection) { 693 *pCoordSection = newcs; 694 } else PetscCall(PetscSectionDestroy(&newcs)); 695 PetscFunctionReturn(PETSC_SUCCESS); 696 } 697 698 /*@ 699 DMSetCoordinatesLocal - Sets into the `DM` a local vector, including ghost points, that holds the coordinates 700 701 Not Collective 702 703 Input Parameters: 704 + dm - the `DM` 705 - c - coordinate vector 706 707 Level: intermediate 708 709 Notes: 710 The coordinates of ghost points can be set using `DMSetCoordinates()` 711 followed by `DMGetCoordinatesLocal()`. This is intended to enable the 712 setting of ghost coordinates outside of the domain. 713 714 The vector `c` should be destroyed by the caller. 715 716 .seealso: `DM`, `DMGetCoordinatesLocal()`, `DMSetCoordinates()`, `DMGetCoordinates()`, `DMGetCoordinateDM()` 717 @*/ 718 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c) 719 { 720 PetscFunctionBegin; 721 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 722 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 723 PetscCall(PetscObjectReference((PetscObject)c)); 724 PetscCall(VecDestroy(&dm->coordinates[0].xl)); 725 dm->coordinates[0].xl = c; 726 PetscCall(VecDestroy(&dm->coordinates[0].x)); 727 PetscFunctionReturn(PETSC_SUCCESS); 728 } 729 730 /*@ 731 DMGetCellCoordinatesLocalSetUp - Prepares a local vector of cellwise coordinates, so that `DMGetCellCoordinatesLocalNoncollective()` can be used as non-collective afterwards. 732 733 Collective 734 735 Input Parameter: 736 . dm - the `DM` 737 738 Level: advanced 739 740 .seealso: `DM`, `DMGetCellCoordinatesLocalNoncollective()` 741 @*/ 742 PetscErrorCode DMGetCellCoordinatesLocalSetUp(DM dm) 743 { 744 PetscFunctionBegin; 745 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 746 if (!dm->coordinates[1].xl && dm->coordinates[1].x) { 747 DM cdm = NULL; 748 749 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 750 PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[1].xl)); 751 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].xl, "DG coordinates")); 752 PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl)); 753 PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl)); 754 } 755 PetscFunctionReturn(PETSC_SUCCESS); 756 } 757 758 /*@ 759 DMGetCellCoordinatesLocal - Gets a local vector with the cellwise coordinates associated with the `DM`. 760 761 Collective 762 763 Input Parameter: 764 . dm - the `DM` 765 766 Output Parameter: 767 . c - coordinate vector 768 769 Level: intermediate 770 771 Notes: 772 This is a borrowed reference, so the user should NOT destroy this vector 773 774 Each process has the local and ghost coordinates 775 776 .seealso: `DM`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()`, `DMGetCellCoordinatesLocalNoncollective()` 777 @*/ 778 PetscErrorCode DMGetCellCoordinatesLocal(DM dm, Vec *c) 779 { 780 PetscFunctionBegin; 781 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 782 PetscAssertPointer(c, 2); 783 PetscCall(DMGetCellCoordinatesLocalSetUp(dm)); 784 *c = dm->coordinates[1].xl; 785 PetscFunctionReturn(PETSC_SUCCESS); 786 } 787 788 /*@ 789 DMGetCellCoordinatesLocalNoncollective - Non-collective version of `DMGetCellCoordinatesLocal()`. Fails if global cellwise coordinates have been set and `DMGetCellCoordinatesLocalSetUp()` not called. 790 791 Not Collective 792 793 Input Parameter: 794 . dm - the `DM` 795 796 Output Parameter: 797 . c - cellwise coordinate vector 798 799 Level: advanced 800 801 .seealso: `DM`, `DMGetCellCoordinatesLocalSetUp()`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()` 802 @*/ 803 PetscErrorCode DMGetCellCoordinatesLocalNoncollective(DM dm, Vec *c) 804 { 805 PetscFunctionBegin; 806 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 807 PetscAssertPointer(c, 2); 808 PetscCheck(dm->coordinates[1].xl || !dm->coordinates[1].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCellCoordinatesLocalSetUp() has not been called"); 809 *c = dm->coordinates[1].xl; 810 PetscFunctionReturn(PETSC_SUCCESS); 811 } 812 813 /*@ 814 DMSetCellCoordinatesLocal - Sets into the `DM` a local vector including ghost points that holds the cellwise coordinates 815 816 Not Collective 817 818 Input Parameters: 819 + dm - the `DM` 820 - c - cellwise coordinate vector 821 822 Level: intermediate 823 824 Notes: 825 The coordinates of ghost points can be set using `DMSetCoordinates()` 826 followed by `DMGetCoordinatesLocal()`. This is intended to enable the 827 setting of ghost coordinates outside of the domain. 828 829 The vector `c` should be destroyed by the caller. 830 831 .seealso: `DM`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinates()`, `DMGetCellCoordinates()`, `DMGetCellCoordinateDM()` 832 @*/ 833 PetscErrorCode DMSetCellCoordinatesLocal(DM dm, Vec c) 834 { 835 PetscFunctionBegin; 836 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 837 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 838 PetscCall(PetscObjectReference((PetscObject)c)); 839 PetscCall(VecDestroy(&dm->coordinates[1].xl)); 840 dm->coordinates[1].xl = c; 841 PetscCall(VecDestroy(&dm->coordinates[1].x)); 842 PetscFunctionReturn(PETSC_SUCCESS); 843 } 844 845 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field) 846 { 847 PetscFunctionBegin; 848 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 849 PetscAssertPointer(field, 2); 850 if (!dm->coordinates[0].field) PetscTryTypeMethod(dm, createcoordinatefield, &dm->coordinates[0].field); 851 *field = dm->coordinates[0].field; 852 PetscFunctionReturn(PETSC_SUCCESS); 853 } 854 855 PetscErrorCode DMSetCoordinateField(DM dm, DMField field) 856 { 857 PetscFunctionBegin; 858 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 859 if (field) PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 2); 860 PetscCall(PetscObjectReference((PetscObject)field)); 861 PetscCall(DMFieldDestroy(&dm->coordinates[0].field)); 862 dm->coordinates[0].field = field; 863 PetscFunctionReturn(PETSC_SUCCESS); 864 } 865 866 PetscErrorCode DMGetLocalBoundingBox_Coordinates(DM dm, PetscReal lmin[], PetscReal lmax[], PetscInt cs[], PetscInt ce[]) 867 { 868 Vec coords = NULL; 869 PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}; 870 PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 871 PetscInt cdim, i, j; 872 PetscMPIInt size; 873 874 PetscFunctionBegin; 875 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 876 PetscCall(DMGetCoordinateDim(dm, &cdim)); 877 if (size == 1) { 878 const PetscReal *L, *Lstart; 879 880 PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L)); 881 if (L) { 882 for (PetscInt d = 0; d < cdim; ++d) 883 if (L[d] > 0.0) { 884 min[d] = Lstart[d]; 885 max[d] = Lstart[d] + L[d]; 886 } 887 } 888 } 889 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 890 if (coords) { 891 const PetscScalar *local_coords; 892 PetscInt N, Ni; 893 894 for (j = cdim; j < 3; ++j) { 895 min[j] = 0; 896 max[j] = 0; 897 } 898 PetscCall(VecGetArrayRead(coords, &local_coords)); 899 PetscCall(VecGetLocalSize(coords, &N)); 900 Ni = N / cdim; 901 for (i = 0; i < Ni; ++i) { 902 for (j = 0; j < cdim; ++j) { 903 min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j])); 904 max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j])); 905 } 906 } 907 PetscCall(VecRestoreArrayRead(coords, &local_coords)); 908 PetscCall(DMGetCellCoordinatesLocal(dm, &coords)); 909 if (coords) { 910 PetscCall(VecGetArrayRead(coords, &local_coords)); 911 PetscCall(VecGetLocalSize(coords, &N)); 912 Ni = N / cdim; 913 for (i = 0; i < Ni; ++i) { 914 for (j = 0; j < cdim; ++j) { 915 min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j])); 916 max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j])); 917 } 918 } 919 PetscCall(VecRestoreArrayRead(coords, &local_coords)); 920 } 921 if (lmin) PetscCall(PetscArraycpy(lmin, min, cdim)); 922 if (lmax) PetscCall(PetscArraycpy(lmax, max, cdim)); 923 } 924 PetscFunctionReturn(PETSC_SUCCESS); 925 } 926 927 /*@ 928 DMGetLocalBoundingBox - Returns the bounding box for the piece of the `DM` on this process. 929 930 Not Collective 931 932 Input Parameter: 933 . dm - the `DM` 934 935 Output Parameters: 936 + lmin - local minimum coordinates (length coord dim, optional) 937 - lmax - local maximum coordinates (length coord dim, optional) 938 939 Level: beginner 940 941 Note: 942 If the `DM` is a `DMDA` and has no coordinates, the index bounds are returned instead. 943 944 .seealso: `DM`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetBoundingBox()` 945 @*/ 946 PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[]) 947 { 948 PetscFunctionBegin; 949 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 950 PetscUseTypeMethod(dm, getlocalboundingbox, lmin, lmax, NULL, NULL); 951 PetscFunctionReturn(PETSC_SUCCESS); 952 } 953 954 /*@ 955 DMGetBoundingBox - Returns the global bounding box for the `DM`. 956 957 Collective 958 959 Input Parameter: 960 . dm - the `DM` 961 962 Output Parameters: 963 + gmin - global minimum coordinates (length coord dim, optional) 964 - gmax - global maximum coordinates (length coord dim, optional) 965 966 Level: beginner 967 968 .seealso: `DM`, `DMGetLocalBoundingBox()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()` 969 @*/ 970 PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[]) 971 { 972 PetscReal lmin[3], lmax[3]; 973 const PetscReal *L, *Lstart; 974 PetscInt cdim; 975 976 PetscFunctionBegin; 977 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 978 PetscCall(DMGetCoordinateDim(dm, &cdim)); 979 PetscCall(DMGetLocalBoundingBox(dm, lmin, lmax)); 980 if (gmin) PetscCallMPI(MPIU_Allreduce(lmin, gmin, cdim, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 981 if (gmax) PetscCallMPI(MPIU_Allreduce(lmax, gmax, cdim, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 982 PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L)); 983 if (L) { 984 for (PetscInt d = 0; d < cdim; ++d) 985 if (L[d] > 0.0) { 986 gmin[d] = Lstart[d]; 987 gmax[d] = Lstart[d] + L[d]; 988 } 989 } 990 PetscFunctionReturn(PETSC_SUCCESS); 991 } 992 993 static PetscErrorCode DMCreateAffineCoordinates_Internal(DM dm) 994 { 995 DM cdm; 996 PetscFE feLinear; 997 DMPolytopeType ct; 998 PetscInt dim, dE, height, cStart, cEnd, gct; 999 1000 PetscFunctionBegin; 1001 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1002 PetscCall(DMGetDimension(dm, &dim)); 1003 PetscCall(DMGetCoordinateDim(dm, &dE)); 1004 PetscCall(DMPlexGetVTKCellHeight(dm, &height)); 1005 PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd)); 1006 if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 1007 else ct = DM_POLYTOPE_UNKNOWN; 1008 gct = (PetscInt)ct; 1009 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm))); 1010 ct = (DMPolytopeType)gct; 1011 // Work around current bug in PetscDualSpaceSetUp_Lagrange() 1012 // Can be seen in plex_tutorials-ex10_1 1013 if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1014 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, 1, -1, &feLinear)); 1015 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)feLinear)); 1016 PetscCall(PetscFEDestroy(&feLinear)); 1017 PetscCall(DMCreateDS(cdm)); 1018 } 1019 PetscFunctionReturn(PETSC_SUCCESS); 1020 } 1021 1022 PetscErrorCode DMGetCoordinateDegree_Internal(DM dm, PetscInt *degree) 1023 { 1024 DM cdm; 1025 PetscFE fe; 1026 PetscSpace sp; 1027 PetscClassId id; 1028 1029 PetscFunctionBegin; 1030 *degree = 1; 1031 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1032 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1033 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1034 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1035 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1036 PetscCall(PetscSpaceGetDegree(sp, degree, NULL)); 1037 PetscFunctionReturn(PETSC_SUCCESS); 1038 } 1039 1040 static void evaluate_coordinates(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar xnew[]) 1041 { 1042 for (PetscInt i = 0; i < dim; i++) xnew[i] = x[i]; 1043 } 1044 1045 /*@ 1046 DMSetCoordinateDisc - Set a coordinate space 1047 1048 Input Parameters: 1049 + dm - The `DM` object 1050 . disc - The new coordinate discretization or `NULL` to ensure a coordinate discretization exists 1051 - project - Project coordinates to new discretization 1052 1053 Level: intermediate 1054 1055 Notes: 1056 A `PetscFE` defines an approximation space using a `PetscSpace`, which represents the basis functions, and a `PetscDualSpace`, which defines the interpolation operation in the space. 1057 1058 This function takes the current mesh coordinates, which are discretized using some `PetscFE` space, and projects this function into a new `PetscFE` space. 1059 The coordinate projection is done on the continuous coordinates, but the discontinuous coordinates are not updated. 1060 1061 Developer Note: 1062 With more effort, we could directly project the discontinuous coordinates also. 1063 1064 .seealso: `DM`, `PetscFE`, `DMGetCoordinateField()` 1065 @*/ 1066 PetscErrorCode DMSetCoordinateDisc(DM dm, PetscFE disc, PetscBool project) 1067 { 1068 DM cdmOld, cdmNew; 1069 PetscFE discOld; 1070 PetscClassId classid; 1071 PetscBool same_space = PETSC_TRUE; 1072 const char *prefix; 1073 1074 PetscFunctionBegin; 1075 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1076 if (disc) PetscValidHeaderSpecific(disc, PETSCFE_CLASSID, 2); 1077 1078 PetscCall(DMGetCoordinateDM(dm, &cdmOld)); 1079 /* Check current discretization is compatible */ 1080 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld)); 1081 PetscCall(PetscObjectGetClassId((PetscObject)discOld, &classid)); 1082 if (classid != PETSCFE_CLASSID) { 1083 if (classid == PETSC_CONTAINER_CLASSID) { 1084 PetscCall(DMCreateAffineCoordinates_Internal(dm)); 1085 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld)); 1086 } else { 1087 const char *discname; 1088 1089 PetscCall(PetscObjectGetType((PetscObject)discOld, &discname)); 1090 SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname); 1091 } 1092 } 1093 // Linear space has been created by now 1094 if (!disc) PetscFunctionReturn(PETSC_SUCCESS); 1095 // Check if the new space is the same as the old modulo quadrature 1096 { 1097 PetscDualSpace dsOld, ds; 1098 PetscCall(PetscFEGetDualSpace(discOld, &dsOld)); 1099 PetscCall(PetscFEGetDualSpace(disc, &ds)); 1100 PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space)); 1101 } 1102 // Make a fresh clone of the coordinate DM 1103 PetscCall(DMClone(cdmOld, &cdmNew)); 1104 cdmNew->cloneOpts = PETSC_TRUE; 1105 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdmOld, &prefix)); 1106 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdmNew, prefix)); 1107 PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject)disc)); 1108 PetscCall(DMCreateDS(cdmNew)); 1109 { 1110 PetscDS ds, nds; 1111 1112 PetscCall(DMGetDS(cdmOld, &ds)); 1113 PetscCall(DMGetDS(cdmNew, &nds)); 1114 PetscCall(PetscDSCopyConstants(ds, nds)); 1115 } 1116 if (cdmOld->periodic.setup) { 1117 PetscSF dummy; 1118 // Force IsoperiodicPointSF to be built, required for periodic coordinate setup 1119 PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &dummy)); 1120 cdmNew->periodic.setup = cdmOld->periodic.setup; 1121 PetscCall(cdmNew->periodic.setup(cdmNew)); 1122 } 1123 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(cdmNew)); 1124 if (project) { 1125 Vec coordsOld, coordsNew; 1126 PetscInt num_face_sfs = 0; 1127 1128 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL)); 1129 if (num_face_sfs) { // Isoperiodicity requires projecting the local coordinates 1130 PetscCall(DMGetCoordinatesLocal(dm, &coordsOld)); 1131 PetscCall(DMCreateLocalVector(cdmNew, &coordsNew)); 1132 PetscCall(PetscObjectSetName((PetscObject)coordsNew, "coordinates")); 1133 if (same_space) { 1134 // Need to copy so that the new vector has the right dm 1135 PetscCall(VecCopy(coordsOld, coordsNew)); 1136 } else { 1137 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[]) = {evaluate_coordinates}; 1138 1139 // We can't call DMProjectField directly because it depends on KSP for DMGlobalToLocalSolve(), but we can use the core strategy 1140 PetscCall(DMSetCoordinateDM(cdmNew, cdmOld)); 1141 // See DMPlexRemapGeometry() for a similar pattern handling the coordinate field 1142 DMField cf; 1143 PetscCall(DMGetCoordinateField(dm, &cf)); 1144 cdmNew->coordinates[0].field = cf; 1145 PetscCall(DMProjectFieldLocal(cdmNew, 0.0, NULL, funcs, INSERT_VALUES, coordsNew)); 1146 cdmNew->coordinates[0].field = NULL; 1147 PetscCall(DMSetCoordinateDM(cdmNew, NULL)); 1148 } 1149 PetscCall(DMSetCoordinatesLocal(dm, coordsNew)); 1150 PetscCall(VecDestroy(&coordsNew)); 1151 } else { 1152 PetscCall(DMGetCoordinates(dm, &coordsOld)); 1153 PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew)); 1154 if (same_space) { 1155 // Need to copy so that the new vector has the right dm 1156 PetscCall(VecCopy(coordsOld, coordsNew)); 1157 } else { 1158 Mat In; 1159 1160 PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &In, NULL)); 1161 PetscCall(MatMult(In, coordsOld, coordsNew)); 1162 PetscCall(MatDestroy(&In)); 1163 } 1164 PetscCall(DMSetCoordinates(dm, coordsNew)); 1165 PetscCall(VecDestroy(&coordsNew)); 1166 } 1167 } 1168 /* Set new coordinate structures */ 1169 PetscCall(DMSetCoordinateField(dm, NULL)); 1170 PetscCall(DMSetCoordinateDM(dm, cdmNew)); 1171 PetscCall(DMDestroy(&cdmNew)); 1172 PetscFunctionReturn(PETSC_SUCCESS); 1173 } 1174 1175 /*@ 1176 DMLocatePoints - Locate the points in `v` in the mesh and return a `PetscSF` of the containing cells 1177 1178 Collective 1179 1180 Input Parameters: 1181 + dm - The `DM` 1182 - ltype - The type of point location, e.g. `DM_POINTLOCATION_NONE` or `DM_POINTLOCATION_NEAREST` 1183 1184 Input/Output Parameters: 1185 + v - The `Vec` of points, on output contains the nearest mesh points to the given points if `DM_POINTLOCATION_NEAREST` is used 1186 - cellSF - Points to either `NULL`, or a `PetscSF` with guesses for which cells contain each point; 1187 on output, the `PetscSF` containing the MPI ranks and local indices of the containing points 1188 1189 Level: developer 1190 1191 Notes: 1192 To do a search of the local cells of the mesh, `v` should have `PETSC_COMM_SELF` as its communicator. 1193 To do a search of all the cells in the distributed mesh, `v` should have the same MPI communicator as `dm`. 1194 1195 Points will only be located in owned cells, not overlap cells arising from `DMPlexDistribute()` or other overlapping distributions. 1196 1197 If *cellSF is `NULL` on input, a `PetscSF` will be created. 1198 If *cellSF is not `NULL` on input, it should point to an existing `PetscSF`, whose graph will be used as initial guesses. 1199 1200 An array that maps each point to its containing cell can be obtained with 1201 .vb 1202 const PetscSFNode *cells; 1203 PetscInt nFound; 1204 const PetscInt *found; 1205 1206 PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells); 1207 .ve 1208 1209 Where cells[i].rank is the MPI rank of the process owning the cell containing point found[i] (or i if found == NULL), and cells[i].index is 1210 the index of the cell in its MPI process' local numbering. This rank is in the communicator for `v`, so if `v` is on `PETSC_COMM_SELF` then the rank will always be 0. 1211 1212 .seealso: `DM`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMPointLocationType` 1213 @*/ 1214 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF) 1215 { 1216 PetscFunctionBegin; 1217 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1218 PetscValidHeaderSpecific(v, VEC_CLASSID, 2); 1219 PetscAssertPointer(cellSF, 4); 1220 if (*cellSF) { 1221 PetscMPIInt result; 1222 1223 PetscValidHeaderSpecific(*cellSF, PETSCSF_CLASSID, 4); 1224 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v), PetscObjectComm((PetscObject)*cellSF), &result)); 1225 PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "cellSF must have a communicator congruent to v's"); 1226 } else { 1227 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v), cellSF)); 1228 } 1229 PetscCall(PetscLogEventBegin(DM_LocatePoints, dm, 0, 0, 0)); 1230 PetscUseTypeMethod(dm, locatepoints, v, ltype, *cellSF); 1231 PetscCall(PetscLogEventEnd(DM_LocatePoints, dm, 0, 0, 0)); 1232 PetscFunctionReturn(PETSC_SUCCESS); 1233 } 1234