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 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). 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 .seealso: `DM`, `DMDA`, `DMSetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()` 419 @*/ 420 PetscErrorCode DMGetCoordinates(DM dm, Vec *c) 421 { 422 PetscFunctionBegin; 423 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 424 PetscAssertPointer(c, 2); 425 if (!dm->coordinates[0].x && dm->coordinates[0].xl) { 426 DM cdm = NULL; 427 428 PetscCall(DMGetCoordinateDM(dm, &cdm)); 429 PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[0].x)); 430 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].x, "coordinates")); 431 PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x)); 432 PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[0].xl, INSERT_VALUES, dm->coordinates[0].x)); 433 } 434 *c = dm->coordinates[0].x; 435 PetscFunctionReturn(PETSC_SUCCESS); 436 } 437 438 /*@ 439 DMSetCoordinates - Sets into the `DM` a global vector that holds the coordinates 440 441 Collective 442 443 Input Parameters: 444 + dm - the `DM` 445 - c - coordinate vector 446 447 Level: intermediate 448 449 Notes: 450 The coordinates do not include those for ghost points, which are in the local vector. 451 452 The vector `c` can be destroyed after the call 453 454 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetCoordinateDM()`, `DMDASetUniformCoordinates()` 455 @*/ 456 PetscErrorCode DMSetCoordinates(DM dm, Vec c) 457 { 458 PetscFunctionBegin; 459 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 460 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 461 PetscCall(PetscObjectReference((PetscObject)c)); 462 PetscCall(VecDestroy(&dm->coordinates[0].x)); 463 dm->coordinates[0].x = c; 464 PetscCall(VecDestroy(&dm->coordinates[0].xl)); 465 PetscCall(DMCoarsenHookAdd(dm, DMRestrictHook_Coordinates, NULL, NULL)); 466 PetscCall(DMSubDomainHookAdd(dm, DMSubDomainHook_Coordinates, NULL, NULL)); 467 PetscFunctionReturn(PETSC_SUCCESS); 468 } 469 470 /*@ 471 DMGetCellCoordinates - Gets a global vector with the cellwise coordinates associated with the `DM`. 472 473 Collective 474 475 Input Parameter: 476 . dm - the `DM` 477 478 Output Parameter: 479 . c - global coordinate vector 480 481 Level: intermediate 482 483 Notes: 484 This is a borrowed reference, so the user should NOT destroy this vector. When the `DM` is 485 destroyed `c` will no longer be valid. 486 487 Each process has only the locally-owned portion of the global coordinates (does NOT have the ghost coordinates). 488 489 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()` 490 @*/ 491 PetscErrorCode DMGetCellCoordinates(DM dm, Vec *c) 492 { 493 PetscFunctionBegin; 494 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 495 PetscAssertPointer(c, 2); 496 if (!dm->coordinates[1].x && dm->coordinates[1].xl) { 497 DM cdm = NULL; 498 499 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 500 PetscCall(DMCreateGlobalVector(cdm, &dm->coordinates[1].x)); 501 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].x, "DG coordinates")); 502 PetscCall(DMLocalToGlobalBegin(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x)); 503 PetscCall(DMLocalToGlobalEnd(cdm, dm->coordinates[1].xl, INSERT_VALUES, dm->coordinates[1].x)); 504 } 505 *c = dm->coordinates[1].x; 506 PetscFunctionReturn(PETSC_SUCCESS); 507 } 508 509 /*@ 510 DMSetCellCoordinates - Sets into the `DM` a global vector that holds the cellwise coordinates 511 512 Collective 513 514 Input Parameters: 515 + dm - the `DM` 516 - c - cellwise coordinate vector 517 518 Level: intermediate 519 520 Notes: 521 The coordinates do not include those for ghost points, which are in the local vector. 522 523 The vector `c` should be destroyed by the caller. 524 525 .seealso: `DM`, `DMGetCoordinates()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMGetCellCoordinatesLocal()`, `DMGetCellCoordinateDM()` 526 @*/ 527 PetscErrorCode DMSetCellCoordinates(DM dm, Vec c) 528 { 529 PetscFunctionBegin; 530 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 531 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 532 PetscCall(PetscObjectReference((PetscObject)c)); 533 PetscCall(VecDestroy(&dm->coordinates[1].x)); 534 dm->coordinates[1].x = c; 535 PetscCall(VecDestroy(&dm->coordinates[1].xl)); 536 PetscFunctionReturn(PETSC_SUCCESS); 537 } 538 539 /*@ 540 DMGetCoordinatesLocalSetUp - Prepares a local vector of coordinates, so that `DMGetCoordinatesLocalNoncollective()` can be used as non-collective afterwards. 541 542 Collective 543 544 Input Parameter: 545 . dm - the `DM` 546 547 Level: advanced 548 549 .seealso: `DM`, `DMSetCoordinates()`, `DMGetCoordinatesLocalNoncollective()` 550 @*/ 551 PetscErrorCode DMGetCoordinatesLocalSetUp(DM dm) 552 { 553 PetscFunctionBegin; 554 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 555 if (!dm->coordinates[0].xl && dm->coordinates[0].x) { 556 DM cdm = NULL; 557 PetscInt bs; 558 559 PetscCall(DMGetCoordinateDM(dm, &cdm)); 560 PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[0].xl)); 561 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].xl, "Local Coordinates")); 562 // If the size of the vector is 0, it will not get the right block size 563 PetscCall(VecGetBlockSize(dm->coordinates[0].x, &bs)); 564 PetscCall(VecSetBlockSize(dm->coordinates[0].xl, bs)); 565 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[0].xl, "coordinates")); 566 PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl)); 567 PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[0].x, INSERT_VALUES, dm->coordinates[0].xl)); 568 } 569 PetscFunctionReturn(PETSC_SUCCESS); 570 } 571 572 /*@ 573 DMGetCoordinatesLocal - Gets a local vector with the coordinates associated with the `DM`. 574 575 Collective the first time it is called 576 577 Input Parameter: 578 . dm - the `DM` 579 580 Output Parameter: 581 . c - coordinate vector 582 583 Level: intermediate 584 585 Notes: 586 This is a borrowed reference, so the user should NOT destroy `c` 587 588 Each process has the local and ghost coordinates 589 590 For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 591 and (x_0,y_0,z_0,x_1,y_1,z_1...) 592 593 .seealso: `DM`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()`, `DMGetCoordinatesLocalNoncollective()` 594 @*/ 595 PetscErrorCode DMGetCoordinatesLocal(DM dm, Vec *c) 596 { 597 PetscFunctionBegin; 598 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 599 PetscAssertPointer(c, 2); 600 PetscCall(DMGetCoordinatesLocalSetUp(dm)); 601 *c = dm->coordinates[0].xl; 602 PetscFunctionReturn(PETSC_SUCCESS); 603 } 604 605 /*@ 606 DMGetCoordinatesLocalNoncollective - Non-collective version of `DMGetCoordinatesLocal()`. Fails if global coordinates have been set and `DMGetCoordinatesLocalSetUp()` not called. 607 608 Not Collective 609 610 Input Parameter: 611 . dm - the `DM` 612 613 Output Parameter: 614 . c - coordinate vector 615 616 Level: advanced 617 618 Note: 619 A previous call to `DMGetCoordinatesLocal()` or `DMGetCoordinatesLocalSetUp()` ensures that a call to this function will not error. 620 621 .seealso: `DM`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinatesLocal()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()` 622 @*/ 623 PetscErrorCode DMGetCoordinatesLocalNoncollective(DM dm, Vec *c) 624 { 625 PetscFunctionBegin; 626 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 627 PetscAssertPointer(c, 2); 628 PetscCheck(dm->coordinates[0].xl || !dm->coordinates[0].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called"); 629 *c = dm->coordinates[0].xl; 630 PetscFunctionReturn(PETSC_SUCCESS); 631 } 632 633 /*@ 634 DMGetCoordinatesLocalTuple - Gets a local vector with the coordinates of specified points and the section describing its layout. 635 636 Not Collective 637 638 Input Parameters: 639 + dm - the `DM` 640 - p - the `IS` of points whose coordinates will be returned 641 642 Output Parameters: 643 + pCoordSection - the `PetscSection` describing the layout of pCoord, i.e. each point corresponds to one point in `p`, and DOFs correspond to coordinates 644 - pCoord - the `Vec` with coordinates of points in `p` 645 646 Level: advanced 647 648 Notes: 649 `DMGetCoordinatesLocalSetUp()` must be called first. This function employs `DMGetCoordinatesLocalNoncollective()` so it is not collective. 650 651 This creates a new vector, so the user SHOULD destroy this vector 652 653 Each process has the local and ghost coordinates 654 655 For `DMDA`, in two and three dimensions coordinates are interlaced (x_0,y_0,x_1,y_1,...) 656 and (x_0,y_0,z_0,x_1,y_1,z_1...) 657 658 .seealso: `DM`, `DMDA`, `DMSetCoordinatesLocal()`, `DMGetCoordinatesLocal()`, `DMGetCoordinatesLocalNoncollective()`, `DMGetCoordinatesLocalSetUp()`, `DMGetCoordinates()`, `DMSetCoordinates()`, `DMGetCoordinateDM()` 659 @*/ 660 PetscErrorCode DMGetCoordinatesLocalTuple(DM dm, IS p, PetscSection *pCoordSection, Vec *pCoord) 661 { 662 DM cdm; 663 PetscSection cs, newcs; 664 Vec coords; 665 const PetscScalar *arr; 666 PetscScalar *newarr = NULL; 667 PetscInt n; 668 669 PetscFunctionBegin; 670 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 671 PetscValidHeaderSpecific(p, IS_CLASSID, 2); 672 if (pCoordSection) PetscAssertPointer(pCoordSection, 3); 673 if (pCoord) PetscAssertPointer(pCoord, 4); 674 PetscCall(DMGetCoordinateDM(dm, &cdm)); 675 PetscCall(DMGetLocalSection(cdm, &cs)); 676 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 677 PetscCheck(coords, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCoordinatesLocalSetUp() has not been called or coordinates not set"); 678 PetscCheck(cdm && cs, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM not supported"); 679 PetscCall(VecGetArrayRead(coords, &arr)); 680 PetscCall(PetscSectionExtractDofsFromArray(cs, MPIU_SCALAR, arr, p, &newcs, pCoord ? ((void **)&newarr) : NULL)); 681 PetscCall(VecRestoreArrayRead(coords, &arr)); 682 if (pCoord) { 683 PetscCall(PetscSectionGetStorageSize(newcs, &n)); 684 /* set array in two steps to mimic PETSC_OWN_POINTER */ 685 PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)p), 1, n, NULL, pCoord)); 686 PetscCall(VecReplaceArray(*pCoord, newarr)); 687 } else { 688 PetscCall(PetscFree(newarr)); 689 } 690 if (pCoordSection) { 691 *pCoordSection = newcs; 692 } else PetscCall(PetscSectionDestroy(&newcs)); 693 PetscFunctionReturn(PETSC_SUCCESS); 694 } 695 696 /*@ 697 DMSetCoordinatesLocal - Sets into the `DM` a local vector, including ghost points, that holds the coordinates 698 699 Not Collective 700 701 Input Parameters: 702 + dm - the `DM` 703 - c - coordinate vector 704 705 Level: intermediate 706 707 Notes: 708 The coordinates of ghost points can be set using `DMSetCoordinates()` 709 followed by `DMGetCoordinatesLocal()`. This is intended to enable the 710 setting of ghost coordinates outside of the domain. 711 712 The vector `c` should be destroyed by the caller. 713 714 .seealso: `DM`, `DMGetCoordinatesLocal()`, `DMSetCoordinates()`, `DMGetCoordinates()`, `DMGetCoordinateDM()` 715 @*/ 716 PetscErrorCode DMSetCoordinatesLocal(DM dm, Vec c) 717 { 718 PetscFunctionBegin; 719 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 720 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 721 PetscCall(PetscObjectReference((PetscObject)c)); 722 PetscCall(VecDestroy(&dm->coordinates[0].xl)); 723 dm->coordinates[0].xl = c; 724 PetscCall(VecDestroy(&dm->coordinates[0].x)); 725 PetscFunctionReturn(PETSC_SUCCESS); 726 } 727 728 /*@ 729 DMGetCellCoordinatesLocalSetUp - Prepares a local vector of cellwise coordinates, so that `DMGetCellCoordinatesLocalNoncollective()` can be used as non-collective afterwards. 730 731 Collective 732 733 Input Parameter: 734 . dm - the `DM` 735 736 Level: advanced 737 738 .seealso: `DM`, `DMGetCellCoordinatesLocalNoncollective()` 739 @*/ 740 PetscErrorCode DMGetCellCoordinatesLocalSetUp(DM dm) 741 { 742 PetscFunctionBegin; 743 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 744 if (!dm->coordinates[1].xl && dm->coordinates[1].x) { 745 DM cdm = NULL; 746 747 PetscCall(DMGetCellCoordinateDM(dm, &cdm)); 748 PetscCall(DMCreateLocalVector(cdm, &dm->coordinates[1].xl)); 749 PetscCall(PetscObjectSetName((PetscObject)dm->coordinates[1].xl, "DG coordinates")); 750 PetscCall(DMGlobalToLocalBegin(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl)); 751 PetscCall(DMGlobalToLocalEnd(cdm, dm->coordinates[1].x, INSERT_VALUES, dm->coordinates[1].xl)); 752 } 753 PetscFunctionReturn(PETSC_SUCCESS); 754 } 755 756 /*@ 757 DMGetCellCoordinatesLocal - Gets a local vector with the cellwise coordinates associated with the `DM`. 758 759 Collective 760 761 Input Parameter: 762 . dm - the `DM` 763 764 Output Parameter: 765 . c - coordinate vector 766 767 Level: intermediate 768 769 Notes: 770 This is a borrowed reference, so the user should NOT destroy this vector 771 772 Each process has the local and ghost coordinates 773 774 .seealso: `DM`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()`, `DMGetCellCoordinatesLocalNoncollective()` 775 @*/ 776 PetscErrorCode DMGetCellCoordinatesLocal(DM dm, Vec *c) 777 { 778 PetscFunctionBegin; 779 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 780 PetscAssertPointer(c, 2); 781 PetscCall(DMGetCellCoordinatesLocalSetUp(dm)); 782 *c = dm->coordinates[1].xl; 783 PetscFunctionReturn(PETSC_SUCCESS); 784 } 785 786 /*@ 787 DMGetCellCoordinatesLocalNoncollective - Non-collective version of `DMGetCellCoordinatesLocal()`. Fails if global cellwise coordinates have been set and `DMGetCellCoordinatesLocalSetUp()` not called. 788 789 Not Collective 790 791 Input Parameter: 792 . dm - the `DM` 793 794 Output Parameter: 795 . c - cellwise coordinate vector 796 797 Level: advanced 798 799 .seealso: `DM`, `DMGetCellCoordinatesLocalSetUp()`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinatesLocal()`, `DMGetCellCoordinates()`, `DMSetCellCoordinates()`, `DMGetCellCoordinateDM()` 800 @*/ 801 PetscErrorCode DMGetCellCoordinatesLocalNoncollective(DM dm, Vec *c) 802 { 803 PetscFunctionBegin; 804 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 805 PetscAssertPointer(c, 2); 806 PetscCheck(dm->coordinates[1].xl || !dm->coordinates[1].x, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DMGetCellCoordinatesLocalSetUp() has not been called"); 807 *c = dm->coordinates[1].xl; 808 PetscFunctionReturn(PETSC_SUCCESS); 809 } 810 811 /*@ 812 DMSetCellCoordinatesLocal - Sets into the `DM` a local vector including ghost points that holds the cellwise coordinates 813 814 Not Collective 815 816 Input Parameters: 817 + dm - the `DM` 818 - c - cellwise coordinate vector 819 820 Level: intermediate 821 822 Notes: 823 The coordinates of ghost points can be set using `DMSetCoordinates()` 824 followed by `DMGetCoordinatesLocal()`. This is intended to enable the 825 setting of ghost coordinates outside of the domain. 826 827 The vector `c` should be destroyed by the caller. 828 829 .seealso: `DM`, `DMGetCellCoordinatesLocal()`, `DMSetCellCoordinates()`, `DMGetCellCoordinates()`, `DMGetCellCoordinateDM()` 830 @*/ 831 PetscErrorCode DMSetCellCoordinatesLocal(DM dm, Vec c) 832 { 833 PetscFunctionBegin; 834 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 835 if (c) PetscValidHeaderSpecific(c, VEC_CLASSID, 2); 836 PetscCall(PetscObjectReference((PetscObject)c)); 837 PetscCall(VecDestroy(&dm->coordinates[1].xl)); 838 dm->coordinates[1].xl = c; 839 PetscCall(VecDestroy(&dm->coordinates[1].x)); 840 PetscFunctionReturn(PETSC_SUCCESS); 841 } 842 843 PetscErrorCode DMGetCoordinateField(DM dm, DMField *field) 844 { 845 PetscFunctionBegin; 846 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 847 PetscAssertPointer(field, 2); 848 if (!dm->coordinates[0].field) PetscTryTypeMethod(dm, createcoordinatefield, &dm->coordinates[0].field); 849 *field = dm->coordinates[0].field; 850 PetscFunctionReturn(PETSC_SUCCESS); 851 } 852 853 PetscErrorCode DMSetCoordinateField(DM dm, DMField field) 854 { 855 PetscFunctionBegin; 856 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 857 if (field) PetscValidHeaderSpecific(field, DMFIELD_CLASSID, 2); 858 PetscCall(PetscObjectReference((PetscObject)field)); 859 PetscCall(DMFieldDestroy(&dm->coordinates[0].field)); 860 dm->coordinates[0].field = field; 861 PetscFunctionReturn(PETSC_SUCCESS); 862 } 863 864 PetscErrorCode DMGetLocalBoundingBox_Coordinates(DM dm, PetscReal lmin[], PetscReal lmax[], PetscInt cs[], PetscInt ce[]) 865 { 866 Vec coords = NULL; 867 PetscReal min[3] = {PETSC_MAX_REAL, PETSC_MAX_REAL, PETSC_MAX_REAL}; 868 PetscReal max[3] = {PETSC_MIN_REAL, PETSC_MIN_REAL, PETSC_MIN_REAL}; 869 PetscInt cdim, i, j; 870 PetscMPIInt size; 871 872 PetscFunctionBegin; 873 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 874 PetscCall(DMGetCoordinateDim(dm, &cdim)); 875 if (size == 1) { 876 const PetscReal *L, *Lstart; 877 878 PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L)); 879 if (L) { 880 for (PetscInt d = 0; d < cdim; ++d) 881 if (L[d] > 0.0) { 882 min[d] = Lstart[d]; 883 max[d] = Lstart[d] + L[d]; 884 } 885 } 886 } 887 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 888 if (coords) { 889 const PetscScalar *local_coords; 890 PetscInt N, Ni; 891 892 for (j = cdim; j < 3; ++j) { 893 min[j] = 0; 894 max[j] = 0; 895 } 896 PetscCall(VecGetArrayRead(coords, &local_coords)); 897 PetscCall(VecGetLocalSize(coords, &N)); 898 Ni = N / cdim; 899 for (i = 0; i < Ni; ++i) { 900 for (j = 0; j < cdim; ++j) { 901 min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j])); 902 max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j])); 903 } 904 } 905 PetscCall(VecRestoreArrayRead(coords, &local_coords)); 906 PetscCall(DMGetCellCoordinatesLocal(dm, &coords)); 907 if (coords) { 908 PetscCall(VecGetArrayRead(coords, &local_coords)); 909 PetscCall(VecGetLocalSize(coords, &N)); 910 Ni = N / cdim; 911 for (i = 0; i < Ni; ++i) { 912 for (j = 0; j < cdim; ++j) { 913 min[j] = PetscMin(min[j], PetscRealPart(local_coords[i * cdim + j])); 914 max[j] = PetscMax(max[j], PetscRealPart(local_coords[i * cdim + j])); 915 } 916 } 917 PetscCall(VecRestoreArrayRead(coords, &local_coords)); 918 } 919 if (lmin) PetscCall(PetscArraycpy(lmin, min, cdim)); 920 if (lmax) PetscCall(PetscArraycpy(lmax, max, cdim)); 921 } 922 PetscFunctionReturn(PETSC_SUCCESS); 923 } 924 925 /*@ 926 DMGetLocalBoundingBox - Returns the bounding box for the piece of the `DM` on this process. 927 928 Not Collective 929 930 Input Parameter: 931 . dm - the `DM` 932 933 Output Parameters: 934 + lmin - local minimum coordinates (length coord dim, optional) 935 - lmax - local maximum coordinates (length coord dim, optional) 936 937 Level: beginner 938 939 Note: 940 If the `DM` is a `DMDA` and has no coordinates, the index bounds are returned instead. 941 942 .seealso: `DM`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMGetBoundingBox()` 943 @*/ 944 PetscErrorCode DMGetLocalBoundingBox(DM dm, PetscReal lmin[], PetscReal lmax[]) 945 { 946 PetscFunctionBegin; 947 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 948 PetscUseTypeMethod(dm, getlocalboundingbox, lmin, lmax, NULL, NULL); 949 PetscFunctionReturn(PETSC_SUCCESS); 950 } 951 952 /*@ 953 DMGetBoundingBox - Returns the global bounding box for the `DM`. 954 955 Collective 956 957 Input Parameter: 958 . dm - the `DM` 959 960 Output Parameters: 961 + gmin - global minimum coordinates (length coord dim, optional) 962 - gmax - global maximum coordinates (length coord dim, optional) 963 964 Level: beginner 965 966 .seealso: `DM`, `DMGetLocalBoundingBox()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()` 967 @*/ 968 PetscErrorCode DMGetBoundingBox(DM dm, PetscReal gmin[], PetscReal gmax[]) 969 { 970 PetscReal lmin[3], lmax[3]; 971 const PetscReal *L, *Lstart; 972 PetscInt cdim; 973 974 PetscFunctionBegin; 975 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 976 PetscCall(DMGetCoordinateDim(dm, &cdim)); 977 PetscCall(DMGetLocalBoundingBox(dm, lmin, lmax)); 978 if (gmin) PetscCallMPI(MPIU_Allreduce(lmin, gmin, cdim, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)dm))); 979 if (gmax) PetscCallMPI(MPIU_Allreduce(lmax, gmax, cdim, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)dm))); 980 PetscCall(DMGetPeriodicity(dm, NULL, &Lstart, &L)); 981 if (L) { 982 for (PetscInt d = 0; d < cdim; ++d) 983 if (L[d] > 0.0) { 984 gmin[d] = Lstart[d]; 985 gmax[d] = Lstart[d] + L[d]; 986 } 987 } 988 PetscFunctionReturn(PETSC_SUCCESS); 989 } 990 991 static PetscErrorCode DMCreateAffineCoordinates_Internal(DM dm) 992 { 993 DM cdm; 994 PetscFE feLinear; 995 DMPolytopeType ct; 996 PetscInt dim, dE, height, cStart, cEnd, gct; 997 998 PetscFunctionBegin; 999 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1000 PetscCall(DMGetDimension(dm, &dim)); 1001 PetscCall(DMGetCoordinateDim(dm, &dE)); 1002 PetscCall(DMPlexGetVTKCellHeight(dm, &height)); 1003 PetscCall(DMPlexGetHeightStratum(dm, height, &cStart, &cEnd)); 1004 if (cEnd > cStart) PetscCall(DMPlexGetCellType(dm, cStart, &ct)); 1005 else ct = DM_POLYTOPE_UNKNOWN; 1006 gct = (PetscInt)ct; 1007 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &gct, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm))); 1008 ct = (DMPolytopeType)gct; 1009 // Work around current bug in PetscDualSpaceSetUp_Lagrange() 1010 // Can be seen in plex_tutorials-ex10_1 1011 if (ct != DM_POLYTOPE_SEG_PRISM_TENSOR && ct != DM_POLYTOPE_TRI_PRISM_TENSOR && ct != DM_POLYTOPE_QUAD_PRISM_TENSOR) { 1012 PetscCall(PetscFECreateLagrangeByCell(PETSC_COMM_SELF, dim, dE, ct, 1, -1, &feLinear)); 1013 PetscCall(DMSetField(cdm, 0, NULL, (PetscObject)feLinear)); 1014 PetscCall(PetscFEDestroy(&feLinear)); 1015 PetscCall(DMCreateDS(cdm)); 1016 } 1017 PetscFunctionReturn(PETSC_SUCCESS); 1018 } 1019 1020 PetscErrorCode DMGetCoordinateDegree_Internal(DM dm, PetscInt *degree) 1021 { 1022 DM cdm; 1023 PetscFE fe; 1024 PetscSpace sp; 1025 PetscClassId id; 1026 1027 PetscFunctionBegin; 1028 *degree = 1; 1029 PetscCall(DMGetCoordinateDM(dm, &cdm)); 1030 PetscCall(DMGetField(cdm, 0, NULL, (PetscObject *)&fe)); 1031 PetscCall(PetscObjectGetClassId((PetscObject)fe, &id)); 1032 if (id != PETSCFE_CLASSID) PetscFunctionReturn(PETSC_SUCCESS); 1033 PetscCall(PetscFEGetBasisSpace(fe, &sp)); 1034 PetscCall(PetscSpaceGetDegree(sp, degree, NULL)); 1035 PetscFunctionReturn(PETSC_SUCCESS); 1036 } 1037 1038 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[]) 1039 { 1040 for (PetscInt i = 0; i < dim; i++) xnew[i] = x[i]; 1041 } 1042 1043 /*@ 1044 DMSetCoordinateDisc - Set a coordinate space 1045 1046 Input Parameters: 1047 + dm - The `DM` object 1048 . disc - The new coordinate discretization or `NULL` to ensure a coordinate discretization exists 1049 - project - Project coordinates to new discretization 1050 1051 Level: intermediate 1052 1053 Notes: 1054 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. 1055 1056 This function takes the current mesh coordinates, which are discretized using some `PetscFE` space, and projects this function into a new `PetscFE` space. 1057 The coordinate projection is done on the continuous coordinates, but the discontinuous coordinates are not updated. 1058 1059 Developer Note: 1060 With more effort, we could directly project the discontinuous coordinates also. 1061 1062 .seealso: `DM`, `PetscFE`, `DMGetCoordinateField()` 1063 @*/ 1064 PetscErrorCode DMSetCoordinateDisc(DM dm, PetscFE disc, PetscBool project) 1065 { 1066 DM cdmOld, cdmNew; 1067 PetscFE discOld; 1068 PetscClassId classid; 1069 PetscBool same_space = PETSC_TRUE; 1070 const char *prefix; 1071 1072 PetscFunctionBegin; 1073 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1074 if (disc) PetscValidHeaderSpecific(disc, PETSCFE_CLASSID, 2); 1075 1076 PetscCall(DMGetCoordinateDM(dm, &cdmOld)); 1077 /* Check current discretization is compatible */ 1078 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld)); 1079 PetscCall(PetscObjectGetClassId((PetscObject)discOld, &classid)); 1080 if (classid != PETSCFE_CLASSID) { 1081 if (classid == PETSC_CONTAINER_CLASSID) { 1082 PetscCall(DMCreateAffineCoordinates_Internal(dm)); 1083 PetscCall(DMGetField(cdmOld, 0, NULL, (PetscObject *)&discOld)); 1084 } else { 1085 const char *discname; 1086 1087 PetscCall(PetscObjectGetType((PetscObject)discOld, &discname)); 1088 SETERRQ(PetscObjectComm((PetscObject)discOld), PETSC_ERR_SUP, "Discretization type %s not supported", discname); 1089 } 1090 } 1091 // Linear space has been created by now 1092 if (!disc) PetscFunctionReturn(PETSC_SUCCESS); 1093 // Check if the new space is the same as the old modulo quadrature 1094 { 1095 PetscDualSpace dsOld, ds; 1096 PetscCall(PetscFEGetDualSpace(discOld, &dsOld)); 1097 PetscCall(PetscFEGetDualSpace(disc, &ds)); 1098 PetscCall(PetscDualSpaceEqual(dsOld, ds, &same_space)); 1099 } 1100 // Make a fresh clone of the coordinate DM 1101 PetscCall(DMClone(cdmOld, &cdmNew)); 1102 cdmNew->cloneOpts = PETSC_TRUE; 1103 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)cdmOld, &prefix)); 1104 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)cdmNew, prefix)); 1105 PetscCall(DMSetField(cdmNew, 0, NULL, (PetscObject)disc)); 1106 PetscCall(DMCreateDS(cdmNew)); 1107 { 1108 PetscDS ds, nds; 1109 1110 PetscCall(DMGetDS(cdmOld, &ds)); 1111 PetscCall(DMGetDS(cdmNew, &nds)); 1112 PetscCall(PetscDSCopyConstants(ds, nds)); 1113 } 1114 if (cdmOld->periodic.setup) { 1115 PetscSF dummy; 1116 // Force IsoperiodicPointSF to be built, required for periodic coordinate setup 1117 PetscCall(DMGetIsoperiodicPointSF_Internal(dm, &dummy)); 1118 cdmNew->periodic.setup = cdmOld->periodic.setup; 1119 PetscCall(cdmNew->periodic.setup(cdmNew)); 1120 } 1121 if (dm->setfromoptionscalled) PetscCall(DMSetFromOptions(cdmNew)); 1122 if (project) { 1123 Vec coordsOld, coordsNew; 1124 PetscInt num_face_sfs = 0; 1125 1126 PetscCall(DMPlexGetIsoperiodicFaceSF(dm, &num_face_sfs, NULL)); 1127 if (num_face_sfs) { // Isoperiodicity requires projecting the local coordinates 1128 PetscCall(DMGetCoordinatesLocal(dm, &coordsOld)); 1129 PetscCall(DMCreateLocalVector(cdmNew, &coordsNew)); 1130 PetscCall(PetscObjectSetName((PetscObject)coordsNew, "coordinates")); 1131 if (same_space) { 1132 // Need to copy so that the new vector has the right dm 1133 PetscCall(VecCopy(coordsOld, coordsNew)); 1134 } else { 1135 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}; 1136 1137 // We can't call DMProjectField directly because it depends on KSP for DMGlobalToLocalSolve(), but we can use the core strategy 1138 PetscCall(DMSetCoordinateDM(cdmNew, cdmOld)); 1139 // See DMPlexRemapGeometry() for a similar pattern handling the coordinate field 1140 DMField cf; 1141 PetscCall(DMGetCoordinateField(dm, &cf)); 1142 cdmNew->coordinates[0].field = cf; 1143 PetscCall(DMProjectFieldLocal(cdmNew, 0.0, NULL, funcs, INSERT_VALUES, coordsNew)); 1144 cdmNew->coordinates[0].field = NULL; 1145 PetscCall(DMSetCoordinateDM(cdmNew, NULL)); 1146 } 1147 PetscCall(DMSetCoordinatesLocal(dm, coordsNew)); 1148 PetscCall(VecDestroy(&coordsNew)); 1149 } else { 1150 PetscCall(DMGetCoordinates(dm, &coordsOld)); 1151 PetscCall(DMCreateGlobalVector(cdmNew, &coordsNew)); 1152 if (same_space) { 1153 // Need to copy so that the new vector has the right dm 1154 PetscCall(VecCopy(coordsOld, coordsNew)); 1155 } else { 1156 Mat In; 1157 1158 PetscCall(DMCreateInterpolation(cdmOld, cdmNew, &In, NULL)); 1159 PetscCall(MatMult(In, coordsOld, coordsNew)); 1160 PetscCall(MatDestroy(&In)); 1161 } 1162 PetscCall(DMSetCoordinates(dm, coordsNew)); 1163 PetscCall(VecDestroy(&coordsNew)); 1164 } 1165 } 1166 /* Set new coordinate structures */ 1167 PetscCall(DMSetCoordinateField(dm, NULL)); 1168 PetscCall(DMSetCoordinateDM(dm, cdmNew)); 1169 PetscCall(DMDestroy(&cdmNew)); 1170 PetscFunctionReturn(PETSC_SUCCESS); 1171 } 1172 1173 /*@ 1174 DMLocatePoints - Locate the points in `v` in the mesh and return a `PetscSF` of the containing cells 1175 1176 Collective 1177 1178 Input Parameters: 1179 + dm - The `DM` 1180 - ltype - The type of point location, e.g. `DM_POINTLOCATION_NONE` or `DM_POINTLOCATION_NEAREST` 1181 1182 Input/Output Parameters: 1183 + v - The `Vec` of points, on output contains the nearest mesh points to the given points if `DM_POINTLOCATION_NEAREST` is used 1184 - cellSF - Points to either `NULL`, or a `PetscSF` with guesses for which cells contain each point; 1185 on output, the `PetscSF` containing the MPI ranks and local indices of the containing points 1186 1187 Level: developer 1188 1189 Notes: 1190 To do a search of the local cells of the mesh, `v` should have `PETSC_COMM_SELF` as its communicator. 1191 To do a search of all the cells in the distributed mesh, `v` should have the same MPI communicator as `dm`. 1192 1193 Points will only be located in owned cells, not overlap cells arising from `DMPlexDistribute()` or other overlapping distributions. 1194 1195 If *cellSF is `NULL` on input, a `PetscSF` will be created. 1196 If *cellSF is not `NULL` on input, it should point to an existing `PetscSF`, whose graph will be used as initial guesses. 1197 1198 An array that maps each point to its containing cell can be obtained with 1199 .vb 1200 const PetscSFNode *cells; 1201 PetscInt nFound; 1202 const PetscInt *found; 1203 1204 PetscSFGetGraph(cellSF,NULL,&nFound,&found,&cells); 1205 .ve 1206 1207 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 1208 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. 1209 1210 .seealso: `DM`, `DMSetCoordinates()`, `DMSetCoordinatesLocal()`, `DMGetCoordinates()`, `DMGetCoordinatesLocal()`, `DMPointLocationType` 1211 @*/ 1212 PetscErrorCode DMLocatePoints(DM dm, Vec v, DMPointLocationType ltype, PetscSF *cellSF) 1213 { 1214 PetscFunctionBegin; 1215 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1216 PetscValidHeaderSpecific(v, VEC_CLASSID, 2); 1217 PetscAssertPointer(cellSF, 4); 1218 if (*cellSF) { 1219 PetscMPIInt result; 1220 1221 PetscValidHeaderSpecific(*cellSF, PETSCSF_CLASSID, 4); 1222 PetscCallMPI(MPI_Comm_compare(PetscObjectComm((PetscObject)v), PetscObjectComm((PetscObject)*cellSF), &result)); 1223 PetscCheck(result == MPI_IDENT || result == MPI_CONGRUENT, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "cellSF must have a communicator congruent to v's"); 1224 } else { 1225 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)v), cellSF)); 1226 } 1227 PetscCall(PetscLogEventBegin(DM_LocatePoints, dm, 0, 0, 0)); 1228 PetscUseTypeMethod(dm, locatepoints, v, ltype, *cellSF); 1229 PetscCall(PetscLogEventEnd(DM_LocatePoints, dm, 0, 0, 0)); 1230 PetscFunctionReturn(PETSC_SUCCESS); 1231 } 1232