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