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