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