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