1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 3 /*@ 4 DMPlexSetMigrationSF - Sets the `PetscSF` for migrating from a parent `DM` into this `DM` 5 6 Logically Collective on dm 7 8 Input Parameters: 9 + dm - The `DM` 10 - naturalSF - The `PetscSF` 11 12 Level: intermediate 13 14 Note: 15 It is necessary to call this in order to have `DMCreateSubDM()` or `DMCreateSuperDM()` build the Global-To-Natural map 16 17 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexCreateMigrationSF()`, `DMPlexGetMigrationSF()` 18 @*/ 19 PetscErrorCode DMPlexSetMigrationSF(DM dm, PetscSF migrationSF) 20 { 21 PetscFunctionBegin; 22 dm->sfMigration = migrationSF; 23 PetscCall(PetscObjectReference((PetscObject)migrationSF)); 24 PetscFunctionReturn(0); 25 } 26 27 /*@ 28 DMPlexGetMigrationSF - Gets the `PetscSF` for migrating from a parent `DM` into this `DM` 29 30 Note Collective 31 32 Input Parameter: 33 . dm - The `DM` 34 35 Output Parameter: 36 . migrationSF - The `PetscSF` 37 38 Level: intermediate 39 40 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexCreateMigrationSF()`, `DMPlexSetMigrationSF` 41 @*/ 42 PetscErrorCode DMPlexGetMigrationSF(DM dm, PetscSF *migrationSF) 43 { 44 PetscFunctionBegin; 45 *migrationSF = dm->sfMigration; 46 PetscFunctionReturn(0); 47 } 48 49 /*@ 50 DMPlexSetGlobalToNaturalSF - Sets the `PetscSF` for mapping Global `Vec` to the Natural `Vec` 51 52 Input Parameters: 53 + dm - The `DM` 54 - naturalSF - The `PetscSF` 55 56 Level: intermediate 57 58 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexGetGlobaltoNaturalSF()` 59 @*/ 60 PetscErrorCode DMPlexSetGlobalToNaturalSF(DM dm, PetscSF naturalSF) 61 { 62 PetscFunctionBegin; 63 dm->sfNatural = naturalSF; 64 PetscCall(PetscObjectReference((PetscObject)naturalSF)); 65 dm->useNatural = PETSC_TRUE; 66 PetscFunctionReturn(0); 67 } 68 69 /*@ 70 DMPlexGetGlobalToNaturalSF - Gets the `PetscSF` for mapping Global `Vec` to the Natural `Vec` 71 72 Input Parameter: 73 . dm - The `DM` 74 75 Output Parameter: 76 . naturalSF - The `PetscSF` 77 78 Level: intermediate 79 80 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexCreateGlobalToNaturalSF()`, `DMPlexSetGlobaltoNaturalSF` 81 @*/ 82 PetscErrorCode DMPlexGetGlobalToNaturalSF(DM dm, PetscSF *naturalSF) 83 { 84 PetscFunctionBegin; 85 *naturalSF = dm->sfNatural; 86 PetscFunctionReturn(0); 87 } 88 89 /*@ 90 DMPlexCreateGlobalToNaturalSF - Creates the `PetscSF` for mapping Global `Vec` to the Natural `Vec` 91 92 Input Parameters: 93 + dm - The redistributed `DM` 94 . section - The local `PetscSection` describing the `Vec` before the mesh was distributed, or NULL if not available 95 - sfMigration - The `PetscSF` used to distribute the mesh, or NULL if it cannot be computed 96 97 Output Parameter: 98 . sfNatural - `PetscSF` for mapping the `Vec` in PETSc ordering to the canonical ordering 99 100 Level: intermediate 101 102 Note: 103 This is not typically called by the user. 104 105 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `PetscSF`, `PetscSection`, `DMPlexDistribute()`, `DMPlexDistributeField()` 106 @*/ 107 PetscErrorCode DMPlexCreateGlobalToNaturalSF(DM dm, PetscSection section, PetscSF sfMigration, PetscSF *sfNatural) 108 { 109 MPI_Comm comm; 110 PetscSF sf, sfEmbed, sfField; 111 PetscSection gSection, sectionDist, gLocSection; 112 PetscInt *spoints, *remoteOffsets; 113 PetscInt ssize, pStart, pEnd, p, localSize, maxStorageSize; 114 PetscBool destroyFlag = PETSC_FALSE, debug = PETSC_FALSE; 115 116 PetscFunctionBegin; 117 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 118 if (!sfMigration) { 119 /* If sfMigration is missing, sfNatural cannot be computed and is set to NULL */ 120 *sfNatural = NULL; 121 PetscFunctionReturn(0); 122 } else if (!section) { 123 /* If the sequential section is not provided (NULL), it is reconstructed from the parallel section */ 124 PetscSF sfMigrationInv; 125 PetscSection localSection; 126 127 PetscCall(DMGetLocalSection(dm, &localSection)); 128 PetscCall(PetscSFCreateInverseSF(sfMigration, &sfMigrationInv)); 129 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ion)); 130 PetscCall(PetscSFDistributeSection(sfMigrationInv, localSection, NULL, section)); 131 PetscCall(PetscSFDestroy(&sfMigrationInv)); 132 destroyFlag = PETSC_TRUE; 133 } 134 if (debug) PetscCall(PetscSFView(sfMigration, NULL)); 135 /* Create a new section from distributing the original section */ 136 PetscCall(PetscSectionCreate(comm, §ionDist)); 137 PetscCall(PetscSFDistributeSection(sfMigration, section, &remoteOffsets, sectionDist)); 138 PetscCall(PetscObjectSetName((PetscObject)sectionDist, "Migrated Section")); 139 if (debug) PetscCall(PetscSectionView(sectionDist, NULL)); 140 PetscCall(DMSetLocalSection(dm, sectionDist)); 141 /* If a sequential section is provided but no dof is affected, sfNatural cannot be computed and is set to NULL */ 142 PetscCall(PetscSectionGetStorageSize(sectionDist, &localSize)); 143 PetscCallMPI(MPI_Allreduce(&localSize, &maxStorageSize, 1, MPI_INT, MPI_MAX, PetscObjectComm((PetscObject)dm))); 144 if (maxStorageSize) { 145 const PetscInt *leaves; 146 PetscInt *sortleaves, *indices; 147 PetscInt Nl; 148 149 /* Get a pruned version of migration SF */ 150 PetscCall(DMGetGlobalSection(dm, &gSection)); 151 if (debug) PetscCall(PetscSectionView(gSection, NULL)); 152 PetscCall(PetscSFGetGraph(sfMigration, NULL, &Nl, &leaves, NULL)); 153 PetscCall(PetscSectionGetChart(gSection, &pStart, &pEnd)); 154 for (p = pStart, ssize = 0; p < pEnd; ++p) { 155 PetscInt dof, off; 156 157 PetscCall(PetscSectionGetDof(gSection, p, &dof)); 158 PetscCall(PetscSectionGetOffset(gSection, p, &off)); 159 if ((dof > 0) && (off >= 0)) ++ssize; 160 } 161 PetscCall(PetscMalloc3(ssize, &spoints, Nl, &sortleaves, Nl, &indices)); 162 for (p = 0; p < Nl; ++p) { 163 sortleaves[p] = leaves ? leaves[p] : p; 164 indices[p] = p; 165 } 166 PetscCall(PetscSortIntWithArray(Nl, sortleaves, indices)); 167 for (p = pStart, ssize = 0; p < pEnd; ++p) { 168 PetscInt dof, off, loc; 169 170 PetscCall(PetscSectionGetDof(gSection, p, &dof)); 171 PetscCall(PetscSectionGetOffset(gSection, p, &off)); 172 if ((dof > 0) && (off >= 0)) { 173 PetscCall(PetscFindInt(p, Nl, sortleaves, &loc)); 174 PetscCheck(loc >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Point %" PetscInt_FMT " with nonzero dof is not a leaf of the migration SF", p); 175 spoints[ssize++] = indices[loc]; 176 } 177 } 178 PetscCall(PetscSFCreateEmbeddedLeafSF(sfMigration, ssize, spoints, &sfEmbed)); 179 PetscCall(PetscObjectSetName((PetscObject)sfEmbed, "Embedded SF")); 180 PetscCall(PetscFree3(spoints, sortleaves, indices)); 181 if (debug) PetscCall(PetscSFView(sfEmbed, NULL)); 182 /* Create the SF associated with this section 183 Roots are natural dofs, leaves are global dofs */ 184 PetscCall(DMGetPointSF(dm, &sf)); 185 PetscCall(PetscSectionCreateGlobalSection(sectionDist, sf, PETSC_TRUE, PETSC_TRUE, &gLocSection)); 186 PetscCall(PetscSFCreateSectionSF(sfEmbed, section, remoteOffsets, gLocSection, &sfField)); 187 PetscCall(PetscSFDestroy(&sfEmbed)); 188 PetscCall(PetscSectionDestroy(&gLocSection)); 189 PetscCall(PetscObjectSetName((PetscObject)sfField, "Natural-to-Global SF")); 190 if (debug) PetscCall(PetscSFView(sfField, NULL)); 191 /* Invert the field SF 192 Roots are global dofs, leaves are natural dofs */ 193 PetscCall(PetscSFCreateInverseSF(sfField, sfNatural)); 194 PetscCall(PetscObjectSetName((PetscObject)*sfNatural, "Global-to-Natural SF")); 195 PetscCall(PetscObjectViewFromOptions((PetscObject)*sfNatural, NULL, "-globaltonatural_sf_view")); 196 /* Clean up */ 197 PetscCall(PetscSFDestroy(&sfField)); 198 } else { 199 *sfNatural = NULL; 200 } 201 PetscCall(PetscSectionDestroy(§ionDist)); 202 PetscCall(PetscFree(remoteOffsets)); 203 if (destroyFlag) PetscCall(PetscSectionDestroy(§ion)); 204 PetscFunctionReturn(0); 205 } 206 207 /*@ 208 DMPlexGlobalToNaturalBegin - Rearranges a global `Vec` in the natural order. 209 210 Collective on dm 211 212 Input Parameters: 213 + dm - The distributed `DMPLEX` 214 - gv - The global `Vec` 215 216 Output Parameters: 217 . nv - `Vec` in the canonical ordering distributed over all processors associated with gv 218 219 Level: intermediate 220 221 Note: 222 The user must call `DMSetUseNatural`(dm, `PETSC_TRUE`) before `DMPlexDistribute()`. 223 224 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `Vec`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexNaturalToGlobalBegin()`, `DMPlexGlobalToNaturalEnd()` 225 @*/ 226 PetscErrorCode DMPlexGlobalToNaturalBegin(DM dm, Vec gv, Vec nv) 227 { 228 const PetscScalar *inarray; 229 PetscScalar *outarray; 230 PetscMPIInt size; 231 232 PetscFunctionBegin; 233 PetscCall(PetscLogEventBegin(DMPLEX_GlobalToNaturalBegin, dm, 0, 0, 0)); 234 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 235 if (dm->sfNatural) { 236 PetscCall(VecGetArray(nv, &outarray)); 237 PetscCall(VecGetArrayRead(gv, &inarray)); 238 PetscCall(PetscSFBcastBegin(dm->sfNatural, MPIU_SCALAR, (PetscScalar *)inarray, outarray, MPI_REPLACE)); 239 PetscCall(VecRestoreArrayRead(gv, &inarray)); 240 PetscCall(VecRestoreArray(nv, &outarray)); 241 } else if (size == 1) { 242 PetscCall(VecCopy(gv, nv)); 243 } else { 244 PetscCheck(!dm->useNatural, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "DM global to natural SF not present.\nIf DMPlexDistribute() was called and a section was defined, report to petsc-maint@mcs.anl.gov."); 245 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created.\nYou must call DMSetUseNatural() before DMPlexDistribute()."); 246 } 247 PetscCall(PetscLogEventEnd(DMPLEX_GlobalToNaturalBegin, dm, 0, 0, 0)); 248 PetscFunctionReturn(0); 249 } 250 251 /*@ 252 DMPlexGlobalToNaturalEnd - Rearranges a global `Vec` in the natural order. 253 254 Collective on dm 255 256 Input Parameters: 257 + dm - The distributed `DMPLEX` 258 - gv - The global `Vec` 259 260 Output Parameter: 261 . nv - The natural `Vec` 262 263 Level: intermediate 264 265 Note: 266 The user must call `DMSetUseNatural`(dm, `PETSC_TRUE`) before `DMPlexDistribute()`. 267 268 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `Vec`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexNaturalToGlobalBegin()`, `DMPlexGlobalToNaturalBegin()` 269 @*/ 270 PetscErrorCode DMPlexGlobalToNaturalEnd(DM dm, Vec gv, Vec nv) 271 { 272 const PetscScalar *inarray; 273 PetscScalar *outarray; 274 PetscMPIInt size; 275 276 PetscFunctionBegin; 277 PetscCall(PetscLogEventBegin(DMPLEX_GlobalToNaturalEnd, dm, 0, 0, 0)); 278 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 279 if (dm->sfNatural) { 280 PetscCall(VecGetArrayRead(gv, &inarray)); 281 PetscCall(VecGetArray(nv, &outarray)); 282 PetscCall(PetscSFBcastEnd(dm->sfNatural, MPIU_SCALAR, (PetscScalar *)inarray, outarray, MPI_REPLACE)); 283 PetscCall(VecRestoreArrayRead(gv, &inarray)); 284 PetscCall(VecRestoreArray(nv, &outarray)); 285 } else if (size == 1) { 286 } else { 287 PetscCheck(!dm->useNatural, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "DM global to natural SF not present.\nIf DMPlexDistribute() was called and a section was defined, report to petsc-maint@mcs.anl.gov."); 288 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created.\nYou must call DMSetUseNatural() before DMPlexDistribute()."); 289 } 290 PetscCall(PetscLogEventEnd(DMPLEX_GlobalToNaturalEnd, dm, 0, 0, 0)); 291 PetscFunctionReturn(0); 292 } 293 294 /*@ 295 DMPlexNaturalToGlobalBegin - Rearranges a `Vec` in the natural order to the Global order. 296 297 Collective on dm 298 299 Input Parameters: 300 + dm - The distributed `DMPLEX` 301 - nv - The natural `Vec` 302 303 Output Parameters: 304 . gv - The global `Vec` 305 306 Level: intermediate 307 308 Note: 309 The user must call `DMSetUseNatural`(dm, `PETSC_TRUE`) before `DMPlexDistribute()`. 310 311 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `Vec`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexNaturalToGlobalBegin()`, `DMPlexGlobalToNaturalEnd()` 312 @*/ 313 PetscErrorCode DMPlexNaturalToGlobalBegin(DM dm, Vec nv, Vec gv) 314 { 315 const PetscScalar *inarray; 316 PetscScalar *outarray; 317 PetscMPIInt size; 318 319 PetscFunctionBegin; 320 PetscCall(PetscLogEventBegin(DMPLEX_NaturalToGlobalBegin, dm, 0, 0, 0)); 321 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 322 if (dm->sfNatural) { 323 /* We only have access to the SF that goes from Global to Natural. 324 Instead of inverting dm->sfNatural, we can call PetscSFReduceBegin/End with MPI_Op MPI_SUM. 325 Here the SUM really does nothing since sfNatural is one to one, as long as gV is set to zero first. */ 326 PetscCall(VecZeroEntries(gv)); 327 PetscCall(VecGetArray(gv, &outarray)); 328 PetscCall(VecGetArrayRead(nv, &inarray)); 329 PetscCall(PetscSFReduceBegin(dm->sfNatural, MPIU_SCALAR, (PetscScalar *)inarray, outarray, MPI_SUM)); 330 PetscCall(VecRestoreArrayRead(nv, &inarray)); 331 PetscCall(VecRestoreArray(gv, &outarray)); 332 } else if (size == 1) { 333 PetscCall(VecCopy(nv, gv)); 334 } else { 335 PetscCheck(!dm->useNatural, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "DM global to natural SF not present.\nIf DMPlexDistribute() was called and a section was defined, report to petsc-maint@mcs.anl.gov."); 336 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created.\nYou must call DMSetUseNatural() before DMPlexDistribute()."); 337 } 338 PetscCall(PetscLogEventEnd(DMPLEX_NaturalToGlobalBegin, dm, 0, 0, 0)); 339 PetscFunctionReturn(0); 340 } 341 342 /*@ 343 DMPlexNaturalToGlobalEnd - Rearranges a `Vec` in the natural order to the Global order. 344 345 Collective on dm 346 347 Input Parameters: 348 + dm - The distributed `DMPLEX` 349 - nv - The natural `Vec` 350 351 Output Parameters: 352 . gv - The global `Vec` 353 354 Level: intermediate 355 356 Note: 357 The user must call `DMSetUseNatural`(dm, `PETSC_TRUE`) before `DMPlexDistribute()`. 358 359 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `Vec`, `DMPlexDistribute()`, `DMPlexDistributeField()`, `DMPlexNaturalToGlobalBegin()`, `DMPlexGlobalToNaturalBegin()` 360 @*/ 361 PetscErrorCode DMPlexNaturalToGlobalEnd(DM dm, Vec nv, Vec gv) 362 { 363 const PetscScalar *inarray; 364 PetscScalar *outarray; 365 PetscMPIInt size; 366 367 PetscFunctionBegin; 368 PetscCall(PetscLogEventBegin(DMPLEX_NaturalToGlobalEnd, dm, 0, 0, 0)); 369 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 370 if (dm->sfNatural) { 371 PetscCall(VecGetArrayRead(nv, &inarray)); 372 PetscCall(VecGetArray(gv, &outarray)); 373 PetscCall(PetscSFReduceEnd(dm->sfNatural, MPIU_SCALAR, (PetscScalar *)inarray, outarray, MPI_SUM)); 374 PetscCall(VecRestoreArrayRead(nv, &inarray)); 375 PetscCall(VecRestoreArray(gv, &outarray)); 376 } else if (size == 1) { 377 } else { 378 PetscCheck(!dm->useNatural, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "DM global to natural SF not present.\nIf DMPlexDistribute() was called and a section was defined, report to petsc-maint@mcs.anl.gov."); 379 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created.\nYou must call DMSetUseNatural() before DMPlexDistribute()."); 380 } 381 PetscCall(PetscLogEventEnd(DMPLEX_NaturalToGlobalEnd, dm, 0, 0, 0)); 382 PetscFunctionReturn(0); 383 } 384 385 /*@ 386 DMPlexCreateNaturalVector - Provide a `Vec` capable of holding the natural ordering and distribution. 387 388 Collective on dm 389 390 Input Parameter: 391 . dm - The distributed `DMPLEX` 392 393 Output Parameter: 394 . nv - The natural `Vec` 395 396 Level: intermediate 397 398 Note: 399 The user must call `DMSetUseNatural`(dm, `PETSC_TRUE`) before `DMPlexDistribute()`. 400 401 .seealso: [](chapter_unstructured), `DM`, `DMPLEX`, `Vec`, `DMPlexDistribute()`, `DMPlexNaturalToGlobalBegin()`, `DMPlexGlobalToNaturalBegin()` 402 @*/ 403 PetscErrorCode DMPlexCreateNaturalVector(DM dm, Vec *nv) 404 { 405 PetscMPIInt size; 406 407 PetscFunctionBegin; 408 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size)); 409 if (dm->sfNatural) { 410 PetscInt nleaves, bs; 411 Vec v; 412 PetscCall(DMGetLocalVector(dm, &v)); 413 PetscCall(VecGetBlockSize(v, &bs)); 414 PetscCall(DMRestoreLocalVector(dm, &v)); 415 416 PetscCall(PetscSFGetGraph(dm->sfNatural, NULL, &nleaves, NULL, NULL)); 417 PetscCall(VecCreate(PetscObjectComm((PetscObject)dm), nv)); 418 PetscCall(VecSetSizes(*nv, nleaves, PETSC_DETERMINE)); 419 PetscCall(VecSetBlockSize(*nv, bs)); 420 PetscCall(VecSetType(*nv, dm->vectype)); 421 PetscCall(VecSetDM(*nv, dm)); 422 } else if (size == 1) { 423 PetscCall(DMCreateLocalVector(dm, nv)); 424 } else { 425 PetscCheck(!dm->useNatural, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "DM global to natural SF not present.\nIf DMPlexDistribute() was called and a section was defined, report to petsc-maint@mcs.anl.gov."); 426 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "DM global to natural SF was not created.\nYou must call DMSetUseNatural() before DMPlexDistribute()."); 427 } 428 PetscFunctionReturn(0); 429 } 430