xref: /petsc/src/dm/impls/plex/plexnatural.c (revision daad07d386296cdcbb87925ef5f1432ee4a24ec4)
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   Vec          tmpVec;
105   PetscSF      sf, sfEmbed, sfField;
106   PetscSection gSection, sectionDist, gLocSection;
107   PetscInt    *spoints, *remoteOffsets;
108   PetscInt     ssize, pStart, pEnd, p, globalSize;
109   PetscBool    destroyFlag = PETSC_FALSE, debug = PETSC_FALSE;
110 
111   PetscFunctionBegin;
112   PetscCall(PetscObjectGetComm((PetscObject) dm, &comm));
113   if (!sfMigration) {
114     /* If sfMigration is missing, sfNatural cannot be computed and is set to NULL */
115     *sfNatural = NULL;
116     PetscFunctionReturn(0);
117   } else if (!section) {
118     /* If the sequential section is not provided (NULL), it is reconstructed from the parallel section */
119     PetscSF sfMigrationInv;
120     PetscSection localSection;
121 
122     PetscCall(DMGetLocalSection(dm, &localSection));
123     PetscCall(PetscSFCreateInverseSF(sfMigration, &sfMigrationInv));
124     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section));
125     PetscCall(PetscSFDistributeSection(sfMigrationInv, localSection, NULL, section));
126     PetscCall(PetscSFDestroy(&sfMigrationInv));
127     destroyFlag = PETSC_TRUE;
128   }
129   if (debug) PetscCall(PetscSFView(sfMigration, NULL));
130   /* Create a new section from distributing the original section */
131   PetscCall(PetscSectionCreate(comm, &sectionDist));
132   PetscCall(PetscSFDistributeSection(sfMigration, section, &remoteOffsets, sectionDist));
133   PetscCall(PetscObjectSetName((PetscObject) sectionDist, "Migrated Section"));
134   if (debug) PetscCall(PetscSectionView(sectionDist, NULL));
135   PetscCall(DMSetLocalSection(dm, sectionDist));
136   /* If a sequential section is provided but no dof is affected, sfNatural cannot be computed and is set to NULL */
137   PetscCall(DMCreateGlobalVector(dm, &tmpVec));
138   PetscCall(VecGetSize(tmpVec, &globalSize));
139   PetscCall(DMRestoreGlobalVector(dm, &tmpVec));
140   if (globalSize) {
141     const PetscInt *leaves;
142     PetscInt       *sortleaves, *indices;
143     PetscInt        Nl;
144 
145     /* Get a pruned version of migration SF */
146     PetscCall(DMGetGlobalSection(dm, &gSection));
147     if (debug) PetscCall(PetscSectionView(gSection, NULL));
148     PetscCall(PetscSFGetGraph(sfMigration, NULL, &Nl, &leaves, NULL));
149     PetscCall(PetscSectionGetChart(gSection, &pStart, &pEnd));
150     for (p = pStart, ssize = 0; p < pEnd; ++p) {
151       PetscInt dof, off;
152 
153       PetscCall(PetscSectionGetDof(gSection, p, &dof));
154       PetscCall(PetscSectionGetOffset(gSection, p, &off));
155       if ((dof > 0) && (off >= 0)) ++ssize;
156     }
157     PetscCall(PetscMalloc3(ssize, &spoints, Nl, &sortleaves, Nl, &indices));
158     for (p = 0; p < Nl; ++p) {sortleaves[p] = leaves ? leaves[p] : p; indices[p] = p;}
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_FALSE, 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