xref: /petsc/src/dm/impls/plex/plexreorder.c (revision 50be1cf59a4e72359a5dcf554efd10fd6d5d86f4)
1 #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petsc/private/matorderimpl.h> /*I      "petscmat.h"      I*/
3 
4 static PetscErrorCode DMPlexCreateOrderingClosure_Static(DM dm, PetscInt numPoints, const PetscInt pperm[], PetscInt **clperm, PetscInt **invclperm)
5 {
6   PetscInt      *perm, *iperm;
7   PetscInt       depth, d, pStart, pEnd, fStart, fMax, fEnd, p;
8 
9   PetscFunctionBegin;
10   PetscCall(DMPlexGetDepth(dm, &depth));
11   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
12   PetscCall(PetscMalloc1(pEnd-pStart,&perm));
13   PetscCall(PetscMalloc1(pEnd-pStart,&iperm));
14   for (p = pStart; p < pEnd; ++p) iperm[p] = -1;
15   for (d = depth; d > 0; --d) {
16     PetscCall(DMPlexGetDepthStratum(dm, d,   &pStart, &pEnd));
17     PetscCall(DMPlexGetDepthStratum(dm, d-1, &fStart, &fEnd));
18     fMax = fStart;
19     for (p = pStart; p < pEnd; ++p) {
20       const PetscInt *cone;
21       PetscInt        point, coneSize, c;
22 
23       if (d == depth) {
24         perm[p]         = pperm[p];
25         iperm[pperm[p]] = p;
26       }
27       point = perm[p];
28       PetscCall(DMPlexGetConeSize(dm, point, &coneSize));
29       PetscCall(DMPlexGetCone(dm, point, &cone));
30       for (c = 0; c < coneSize; ++c) {
31         const PetscInt oldc = cone[c];
32         const PetscInt newc = iperm[oldc];
33 
34         if (newc < 0) {
35           perm[fMax]  = oldc;
36           iperm[oldc] = fMax++;
37         }
38       }
39     }
40     PetscCheck(fMax == fEnd,PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of depth %" PetscInt_FMT " faces %" PetscInt_FMT " does not match permuted number %" PetscInt_FMT, d, fEnd-fStart, fMax-fStart);
41   }
42   *clperm    = perm;
43   *invclperm = iperm;
44   PetscFunctionReturn(0);
45 }
46 
47 /*@
48   DMPlexGetOrdering - Calculate a reordering of the mesh
49 
50   Collective on dm
51 
52   Input Parameters:
53 + dm - The DMPlex object
54 . otype - type of reordering, one of the following:
55 $     MATORDERINGNATURAL - Natural
56 $     MATORDERINGND - Nested Dissection
57 $     MATORDERING1WD - One-way Dissection
58 $     MATORDERINGRCM - Reverse Cuthill-McKee
59 $     MATORDERINGQMD - Quotient Minimum Degree
60 - label - [Optional] Label used to segregate ordering into sets, or NULL
61 
62   Output Parameter:
63 . perm - The point permutation as an IS, perm[old point number] = new point number
64 
65   Note: The label is used to group sets of points together by label value. This makes it easy to reorder a mesh which
66   has different types of cells, and then loop over each set of reordered cells for assembly.
67 
68   Level: intermediate
69 
70 .seealso: `DMPlexPermute()`, `MatGetOrdering()`
71 @*/
72 PetscErrorCode DMPlexGetOrdering(DM dm, MatOrderingType otype, DMLabel label, IS *perm)
73 {
74   PetscInt       numCells = 0;
75   PetscInt      *start = NULL, *adjacency = NULL, *cperm, *clperm = NULL, *invclperm = NULL, *mask, *xls, pStart, pEnd, c, i;
76 
77   PetscFunctionBegin;
78   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
79   PetscValidPointer(perm, 4);
80   PetscCall(DMPlexCreateNeighborCSR(dm, 0, &numCells, &start, &adjacency));
81   PetscCall(PetscMalloc3(numCells,&cperm,numCells,&mask,numCells*2,&xls));
82   if (numCells) {
83     /* Shift for Fortran numbering */
84     for (i = 0; i < start[numCells]; ++i) ++adjacency[i];
85     for (i = 0; i <= numCells; ++i)       ++start[i];
86     PetscCall(SPARSEPACKgenrcm(&numCells, start, adjacency, cperm, mask, xls));
87   }
88   PetscCall(PetscFree(start));
89   PetscCall(PetscFree(adjacency));
90   /* Shift for Fortran numbering */
91   for (c = 0; c < numCells; ++c) --cperm[c];
92   /* Segregate */
93   if (label) {
94     IS              valueIS;
95     const PetscInt *valuesTmp;
96     PetscInt       *values;
97     PetscInt        numValues, numPoints = 0;
98     PetscInt       *sperm, *vsize, *voff, v;
99 
100     // Can't directly sort the valueIS, since it is a view into the DMLabel
101     PetscCall(DMLabelGetValueIS(label, &valueIS));
102     PetscCall(ISGetLocalSize(valueIS, &numValues));
103     PetscCall(ISGetIndices(valueIS, &valuesTmp));
104     PetscCall(PetscCalloc4(numCells, &sperm, numValues, &values, numValues, &vsize, numValues+1,&voff));
105     PetscCall(PetscArraycpy(values, valuesTmp, numValues));
106     PetscCall(PetscSortInt(numValues, values));
107     PetscCall(ISRestoreIndices(valueIS, &valuesTmp));
108     PetscCall(ISDestroy(&valueIS));
109     for (v = 0; v < numValues; ++v) {
110       PetscCall(DMLabelGetStratumSize(label, values[v], &vsize[v]));
111       if (v < numValues-1) voff[v+2] += vsize[v] + voff[v+1];
112       numPoints += vsize[v];
113     }
114     PetscCheck(numPoints == numCells, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Label only covers %" PetscInt_FMT " cells != %" PetscInt_FMT " total cells", numPoints, numCells);
115     for (c = 0; c < numCells; ++c) {
116       const PetscInt oldc = cperm[c];
117       PetscInt       val, vloc;
118 
119       PetscCall(DMLabelGetValue(label, oldc, &val));
120       PetscCheck(val != -1,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Cell %" PetscInt_FMT " not present in label", oldc);
121       PetscCall(PetscFindInt(val, numValues, values, &vloc));
122       PetscCheck(vloc >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Value %" PetscInt_FMT " not present label", val);
123       sperm[voff[vloc+1]++] = oldc;
124     }
125     for (v = 0; v < numValues; ++v) {
126       PetscCheck(voff[v+1] - voff[v] == vsize[v],PETSC_COMM_SELF, PETSC_ERR_PLIB, "Number of %" PetscInt_FMT " values found is %" PetscInt_FMT " != %" PetscInt_FMT, values[v], voff[v+1] - voff[v], vsize[v]);
127     }
128     PetscCall(PetscArraycpy(cperm, sperm, numCells));
129     PetscCall(PetscFree4(sperm, values, vsize, voff));
130   }
131   /* Construct closure */
132   PetscCall(DMPlexCreateOrderingClosure_Static(dm, numCells, cperm, &clperm, &invclperm));
133   PetscCall(PetscFree3(cperm,mask,xls));
134   PetscCall(PetscFree(clperm));
135   /* Invert permutation */
136   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
137   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd-pStart, invclperm, PETSC_OWN_POINTER, perm));
138   PetscFunctionReturn(0);
139 }
140 
141 /*@
142   DMPlexGetOrdering1D - Reorder the vertices so that the mesh is in a line
143 
144   Collective on dm
145 
146   Input Parameter:
147 . dm - The DMPlex object
148 
149   Output Parameter:
150 . perm - The point permutation as an IS, perm[old point number] = new point number
151 
152   Level: intermediate
153 
154 .seealso: `DMPlexGetOrdering()`, `DMPlexPermute()`, `MatGetOrdering()`
155 @*/
156 PetscErrorCode DMPlexGetOrdering1D(DM dm, IS *perm)
157 {
158   PetscInt       *points;
159   const PetscInt *support, *cone;
160   PetscInt        dim, pStart, pEnd, cStart, cEnd, c, vStart, vEnd, v, suppSize, lastCell = 0;
161 
162   PetscFunctionBegin;
163   PetscCall(DMGetDimension(dm, &dim));
164   PetscCheck(dim == 1, PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Input mesh must be one dimensional, not %" PetscInt_FMT, dim);
165   PetscCall(DMPlexGetChart(dm, &pStart, &pEnd));
166   PetscCall(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd));
167   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
168   PetscCall(PetscMalloc1(pEnd-pStart, &points));
169   for (c = cStart; c < cEnd; ++c) points[c] = c;
170   for (v = vStart; v < vEnd; ++v) points[v] = v;
171   for (v = vStart; v < vEnd; ++v) {
172     PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
173     PetscCall(DMPlexGetSupport(dm, v, &support));
174     if (suppSize == 1) {lastCell = support[0]; break;}
175   }
176   if (v < vEnd) {
177     PetscInt pos = cEnd;
178 
179     points[v] = pos++;
180     while (lastCell >= cStart) {
181       PetscCall(DMPlexGetCone(dm, lastCell, &cone));
182       if (cone[0] == v) v = cone[1];
183       else              v = cone[0];
184       PetscCall(DMPlexGetSupport(dm, v, &support));
185       PetscCall(DMPlexGetSupportSize(dm, v, &suppSize));
186       if (suppSize == 1) {lastCell = -1;}
187       else {
188         if (support[0] == lastCell) lastCell = support[1];
189         else                        lastCell = support[0];
190       }
191       points[v] = pos++;
192     }
193     PetscCheck(pos == pEnd, PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Last vertex was %" PetscInt_FMT ", not %" PetscInt_FMT, pos, pEnd);
194   }
195   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject) dm), pEnd-pStart, points, PETSC_OWN_POINTER, perm));
196   PetscFunctionReturn(0);
197 }
198 
199 static PetscErrorCode DMPlexRemapCoordinates_Private(IS perm, PetscSection cs, Vec coordinates, PetscSection *csNew, Vec *coordinatesNew)
200 {
201   PetscScalar    *coords, *coordsNew;
202   const PetscInt *pperm;
203   PetscInt        pStart, pEnd, p;
204   const char     *name;
205 
206   PetscFunctionBegin;
207   PetscCall(PetscSectionPermute(cs, perm, csNew));
208   PetscCall(VecDuplicate(coordinates, coordinatesNew));
209   PetscCall(PetscObjectGetName((PetscObject) coordinates, &name));
210   PetscCall(PetscObjectSetName((PetscObject) *coordinatesNew, name));
211   PetscCall(VecGetArray(coordinates, &coords));
212   PetscCall(VecGetArray(*coordinatesNew, &coordsNew));
213   PetscCall(PetscSectionGetChart(*csNew, &pStart, &pEnd));
214   PetscCall(ISGetIndices(perm, &pperm));
215   for (p = pStart; p < pEnd; ++p) {
216     PetscInt dof, off, offNew, d;
217 
218     PetscCall(PetscSectionGetDof(*csNew, p, &dof));
219     PetscCall(PetscSectionGetOffset(cs, p, &off));
220     PetscCall(PetscSectionGetOffset(*csNew, pperm[p], &offNew));
221     for (d = 0; d < dof; ++d) coordsNew[offNew+d] = coords[off+d];
222   }
223   PetscCall(ISRestoreIndices(perm, &pperm));
224   PetscCall(VecRestoreArray(coordinates, &coords));
225   PetscCall(VecRestoreArray(*coordinatesNew, &coordsNew));
226   PetscFunctionReturn(0);
227 }
228 
229 /*@
230   DMPlexPermute - Reorder the mesh according to the input permutation
231 
232   Collective on dm
233 
234   Input Parameters:
235 + dm - The DMPlex object
236 - perm - The point permutation, perm[old point number] = new point number
237 
238   Output Parameter:
239 . pdm - The permuted DM
240 
241   Level: intermediate
242 
243 .seealso: `MatPermute()`
244 @*/
245 PetscErrorCode DMPlexPermute(DM dm, IS perm, DM *pdm)
246 {
247   DM_Plex       *plex = (DM_Plex *) dm->data, *plexNew;
248   PetscInt       dim, cdim;
249   const char    *name;
250 
251   PetscFunctionBegin;
252   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
253   PetscValidHeaderSpecific(perm, IS_CLASSID, 2);
254   PetscValidPointer(pdm, 3);
255   PetscCall(DMCreate(PetscObjectComm((PetscObject) dm), pdm));
256   PetscCall(DMSetType(*pdm, DMPLEX));
257   PetscCall(PetscObjectGetName((PetscObject) dm, &name));
258   PetscCall(PetscObjectSetName((PetscObject) *pdm, name));
259   PetscCall(DMGetDimension(dm, &dim));
260   PetscCall(DMSetDimension(*pdm, dim));
261   PetscCall(DMGetCoordinateDim(dm, &cdim));
262   PetscCall(DMSetCoordinateDim(*pdm, cdim));
263   PetscCall(DMCopyDisc(dm, *pdm));
264   if (dm->localSection) {
265     PetscSection section, sectionNew;
266 
267     PetscCall(DMGetLocalSection(dm, &section));
268     PetscCall(PetscSectionPermute(section, perm, &sectionNew));
269     PetscCall(DMSetLocalSection(*pdm, sectionNew));
270     PetscCall(PetscSectionDestroy(&sectionNew));
271   }
272   plexNew = (DM_Plex *) (*pdm)->data;
273   /* Ignore ltogmap, ltogmapb */
274   /* Ignore sf, sectionSF */
275   /* Ignore globalVertexNumbers, globalCellNumbers */
276   /* Reorder labels */
277   {
278     PetscInt numLabels, l;
279     DMLabel  label, labelNew;
280 
281     PetscCall(DMGetNumLabels(dm, &numLabels));
282     for (l = 0; l < numLabels; ++l) {
283       PetscCall(DMGetLabelByNum(dm, l, &label));
284       PetscCall(DMLabelPermute(label, perm, &labelNew));
285       PetscCall(DMAddLabel(*pdm, labelNew));
286       PetscCall(DMLabelDestroy(&labelNew));
287     }
288     PetscCall(DMGetLabel(*pdm, "depth", &(*pdm)->depthLabel));
289     if (plex->subpointMap) PetscCall(DMLabelPermute(plex->subpointMap, perm, &plexNew->subpointMap));
290   }
291   /* Reorder topology */
292   {
293     const PetscInt *pperm;
294     PetscInt        n, pStart, pEnd, p;
295 
296     PetscCall(PetscSectionDestroy(&plexNew->coneSection));
297     PetscCall(PetscSectionPermute(plex->coneSection, perm, &plexNew->coneSection));
298     PetscCall(PetscSectionGetStorageSize(plexNew->coneSection, &n));
299     PetscCall(PetscMalloc1(n, &plexNew->cones));
300     PetscCall(PetscMalloc1(n, &plexNew->coneOrientations));
301     PetscCall(ISGetIndices(perm, &pperm));
302     PetscCall(PetscSectionGetChart(plex->coneSection, &pStart, &pEnd));
303     for (p = pStart; p < pEnd; ++p) {
304       PetscInt dof, off, offNew, d;
305 
306       PetscCall(PetscSectionGetDof(plexNew->coneSection, pperm[p], &dof));
307       PetscCall(PetscSectionGetOffset(plex->coneSection, p, &off));
308       PetscCall(PetscSectionGetOffset(plexNew->coneSection, pperm[p], &offNew));
309       for (d = 0; d < dof; ++d) {
310         plexNew->cones[offNew+d]            = pperm[plex->cones[off+d]];
311         plexNew->coneOrientations[offNew+d] = plex->coneOrientations[off+d];
312       }
313     }
314     PetscCall(PetscSectionDestroy(&plexNew->supportSection));
315     PetscCall(PetscSectionPermute(plex->supportSection, perm, &plexNew->supportSection));
316     PetscCall(PetscSectionGetStorageSize(plexNew->supportSection, &n));
317     PetscCall(PetscMalloc1(n, &plexNew->supports));
318     PetscCall(PetscSectionGetChart(plex->supportSection, &pStart, &pEnd));
319     for (p = pStart; p < pEnd; ++p) {
320       PetscInt dof, off, offNew, d;
321 
322       PetscCall(PetscSectionGetDof(plexNew->supportSection, pperm[p], &dof));
323       PetscCall(PetscSectionGetOffset(plex->supportSection, p, &off));
324       PetscCall(PetscSectionGetOffset(plexNew->supportSection, pperm[p], &offNew));
325       for (d = 0; d < dof; ++d) {
326         plexNew->supports[offNew+d] = pperm[plex->supports[off+d]];
327       }
328     }
329     PetscCall(ISRestoreIndices(perm, &pperm));
330   }
331   /* Remap coordinates */
332   {
333     DM           cdm, cdmNew;
334     PetscSection cs, csNew;
335     Vec          coordinates, coordinatesNew;
336 
337     PetscCall(DMGetCoordinateSection(dm, &cs));
338     PetscCall(DMGetCoordinatesLocal(dm, &coordinates));
339     PetscCall(DMPlexRemapCoordinates_Private(perm, cs, coordinates, &csNew, &coordinatesNew));
340     PetscCall(DMSetCoordinateSection(*pdm, PETSC_DETERMINE, csNew));
341     PetscCall(DMSetCoordinatesLocal(*pdm, coordinatesNew));
342     PetscCall(PetscSectionDestroy(&csNew));
343     PetscCall(VecDestroy(&coordinatesNew));
344 
345     PetscCall(DMGetCellCoordinateDM(dm, &cdm));
346     if (cdm) {
347       PetscCall(DMGetCoordinateDM(*pdm, &cdm));
348       PetscCall(DMClone(cdm, &cdmNew));
349       PetscCall(DMSetCellCoordinateDM(*pdm, cdmNew));
350       PetscCall(DMDestroy(&cdmNew));
351       PetscCall(DMGetCellCoordinateSection(dm, &cs));
352       PetscCall(DMGetCellCoordinatesLocal(dm, &coordinates));
353       PetscCall(DMPlexRemapCoordinates_Private(perm, cs, coordinates, &csNew, &coordinatesNew));
354       PetscCall(DMSetCellCoordinateSection(*pdm, PETSC_DETERMINE, csNew));
355       PetscCall(DMSetCellCoordinatesLocal(*pdm, coordinatesNew));
356       PetscCall(PetscSectionDestroy(&csNew));
357       PetscCall(VecDestroy(&coordinatesNew));
358     }
359   }
360   PetscCall(DMPlexCopy_Internal(dm, PETSC_TRUE, PETSC_TRUE, *pdm));
361   (*pdm)->setupcalled = PETSC_TRUE;
362   PetscFunctionReturn(0);
363 }
364 
365 PetscErrorCode DMPlexReorderSetDefault_Plex(DM dm, DMPlexReorderDefaultFlag reorder)
366 {
367   DM_Plex *mesh = (DM_Plex *) dm->data;
368 
369   PetscFunctionBegin;
370   mesh->reorderDefault = reorder;
371   PetscFunctionReturn(0);
372 }
373 
374 /*@
375   DMPlexReorderSetDefault - Set flag indicating whether the DM should be reordered by default
376 
377   Logically collective
378 
379   Input Parameters:
380 + dm        - The DM
381 - reorder   - Flag for reordering
382 
383   Level: intermediate
384 
385 .seealso: `DMPlexReorderGetDefault()`
386 @*/
387 PetscErrorCode DMPlexReorderSetDefault(DM dm, DMPlexReorderDefaultFlag reorder)
388 {
389   PetscFunctionBegin;
390   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
391   PetscTryMethod(dm,"DMPlexReorderSetDefault_C",(DM,DMPlexReorderDefaultFlag),(dm,reorder));
392   PetscFunctionReturn(0);
393 }
394 
395 PetscErrorCode DMPlexReorderGetDefault_Plex(DM dm, DMPlexReorderDefaultFlag *reorder)
396 {
397   DM_Plex *mesh = (DM_Plex *) dm->data;
398 
399   PetscFunctionBegin;
400   *reorder = mesh->reorderDefault;
401   PetscFunctionReturn(0);
402 }
403 
404 /*@
405   DMPlexReorderGetDefault - Get flag indicating whether the DM should be reordered by default
406 
407   Not collective
408 
409   Input Parameter:
410 . dm      - The DM
411 
412   Output Parameter:
413 . reorder - Flag for reordering
414 
415   Level: intermediate
416 
417 .seealso: `DMPlexReorderSetDefault()`
418 @*/
419 PetscErrorCode DMPlexReorderGetDefault(DM dm, DMPlexReorderDefaultFlag *reorder)
420 {
421   PetscFunctionBegin;
422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
423   PetscValidPointer(reorder, 2);
424   PetscUseMethod(dm,"DMPlexReorderGetDefault_C",(DM,DMPlexReorderDefaultFlag*),(dm,reorder));
425   PetscFunctionReturn(0);
426 }
427