xref: /petsc/src/dm/impls/plex/plexnatural.c (revision 9371c9d470a9602b6d10a8bf50c9b2280a79e45a)
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), &section));
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, &sectionDist));
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(&sectionDist));
190   PetscCall(PetscFree(remoteOffsets));
191   if (destroyFlag) PetscCall(PetscSectionDestroy(&section));
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