bandCompression.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2022-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "bandCompression.H"
30 #include "bitSet.H"
31 #include "polyMesh.H"
32 #include "globalMeshData.H"
33 #include "CircularBuffer.H"
34 #include "CompactListList.H"
35 #include "DynamicList.H"
36 #include "IOstreams.H"
37 
38 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
39 
40 namespace
41 {
42 
43 // Process connections with the Cuthill-McKee algorithm.
44 // The connections are CompactListList<label> or a labelListList.
45 template<class ConnectionListListType>
46 Foam::labelList cuthill_mckee_algorithm
47 (
48  const ConnectionListListType& cellCellAddressing
49 )
50 {
51  using namespace Foam;
52 
53  const label nOldCells(cellCellAddressing.size());
54 
55  // Which cells are visited/unvisited
56  bitSet unvisited(nOldCells, true);
57 
58  // The new output order
59  labelList newOrder(nOldCells);
60 
61 
62  // Various work arrays
63  // ~~~~~~~~~~~~~~~~~~~
64 
65  // Neighbour cells
66  DynamicList<label> nbrCells;
67 
68  // Neighbour ordering
69  DynamicList<label> nbrOrder;
70 
71  // Corresponding weights for neighbour cells
72  DynamicList<label> weights;
73 
74  // FIFO buffer for renumbering.
75  CircularBuffer<label> queuedCells(1024);
76 
77  label cellInOrder = 0;
78 
79  while (true)
80  {
81  // For a disconnected region find the lowest connected cell.
82  label currCelli = -1;
83  label minCount = labelMax;
84 
85  for (const label celli : unvisited)
86  {
87  const label nbrCount = cellCellAddressing[celli].size();
88 
89  if (minCount > nbrCount)
90  {
91  minCount = nbrCount;
92  currCelli = celli;
93  }
94  }
95 
96  if (currCelli == -1)
97  {
98  break;
99  }
100 
101 
102  // Starting from currCelli - walk breadth-first
103 
104  queuedCells.push_back(currCelli);
105 
106  // Loop through queuedCells list. Add the first cell into the
107  // cell order if it has not already been visited and ask for its
108  // neighbours. If the neighbour in question has not been visited,
109  // add it to the end of the queuedCells list
110 
111  while (!queuedCells.empty())
112  {
113  // Process as FIFO
114  currCelli = queuedCells.front();
115  queuedCells.pop_front();
116 
117  if (unvisited.test(currCelli))
118  {
119  // First visit...
120  unvisited.unset(currCelli);
121 
122  // Add into cellOrder
123  newOrder[cellInOrder] = currCelli;
124  ++cellInOrder;
125 
126  // Add in increasing order of connectivity
127 
128  // 1. Count neighbours of unvisited neighbours
129  nbrCells.clear();
130  weights.clear();
131 
132  // Find if the neighbours have been visited
133  const auto& neighbours = cellCellAddressing[currCelli];
134 
135  for (const label nbr : neighbours)
136  {
137  const label nbrCount = cellCellAddressing[nbr].size();
138 
139  if (unvisited.test(nbr))
140  {
141  // Not visited (or removed), add to the list
142  nbrCells.push_back(nbr);
143  weights.push_back(nbrCount);
144  }
145  }
146 
147  // Resize DynamicList prior to sortedOrder
148  nbrOrder.resize_nocopy(weights.size());
149 
150  // 2. Ascending order
151  Foam::sortedOrder(weights, nbrOrder);
152 
153  // 3. Add to FIFO in sorted order
154  for (const label nbrIdx : nbrOrder)
155  {
156  queuedCells.push_back(nbrCells[nbrIdx]);
157  }
158  }
159  }
160  }
161 
162  // Debug:
163  // - the peak capacity of queuedCells approximates the
164  // maximum intermediate bandwidth
165  #if 0
166  Pout<< "bandCompression: peak-capacity=" << queuedCells.capacity() << nl;
167  #endif
168 
169  // Now we have new-to-old in newOrder.
170  return newOrder;
171 }
173 } // End anonymous namespace
174 
175 
176 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
177 
179 (
180  const labelUList& cellCells,
181  const labelUList& offsets
182 )
183 {
184  // Protect against zero-sized offset list
185  const label nOldCells = Foam::max(0, (offsets.size()-1));
186 
187  // Count number of neighbours
188  labelList numNbrs(nOldCells, Foam::zero{});
189  for (label celli = 0; celli < nOldCells; ++celli)
190  {
191  const label beg = offsets[celli];
192  const label end = offsets[celli+1];
193 
194  for (label idx = beg; idx < end; ++idx)
195  {
196  ++numNbrs[celli];
197  ++numNbrs[cellCells[idx]];
198  }
199  }
200 
201 
202  // Which cells are visited/unvisited
203  bitSet unvisited(nOldCells, true);
204 
205  // The new output order
206  labelList newOrder(nOldCells);
207 
208 
209  // Various work arrays
210  // ~~~~~~~~~~~~~~~~~~~
211 
212  // Neighbour cells
213  DynamicList<label> nbrCells;
214 
215  // Neighbour ordering
216  DynamicList<label> nbrOrder;
217 
218  // Corresponding weights for neighbour cells
219  DynamicList<label> weights;
220 
221  // FIFO buffer for renumbering.
222  CircularBuffer<label> queuedCells(1024);
223 
224 
225  label cellInOrder = 0;
226 
227  while (true)
228  {
229  // Find lowest connected cell that has not been visited yet
230  label currCelli = -1;
231  label minCount = labelMax;
232 
233  for (const label celli : unvisited)
234  {
235  const label nbrCount = numNbrs[celli];
236 
237  if (minCount > nbrCount)
238  {
239  minCount = nbrCount;
240  currCelli = celli;
241  }
242  }
243 
244  if (currCelli == -1)
245  {
246  break;
247  }
248 
249 
250  // Starting from currCellii - walk breadth-first
251 
252  queuedCells.push_back(currCelli);
253 
254  // loop through the nextCell list. Add the first cell into the
255  // cell order if it has not already been visited and ask for its
256  // neighbours. If the neighbour in question has not been visited,
257  // add it to the end of the nextCell list
258 
259  // Loop through queuedCells list. Add the first cell into the
260  // cell order if it has not already been visited and ask for its
261  // neighbours. If the neighbour in question has not been visited,
262  // add it to the end of the queuedCells list
263 
264  while (!queuedCells.empty())
265  {
266  // Process as FIFO
267  currCelli = queuedCells.front();
268  queuedCells.pop_front();
269 
270  if (unvisited.test(currCelli))
271  {
272  // First visit...
273  unvisited.unset(currCelli);
274 
275  // Add into cellOrder
276  newOrder[cellInOrder] = currCelli;
277  ++cellInOrder;
278 
279  // Add in increasing order of connectivity
280 
281  // 1. Count neighbours of unvisited neighbours
282  nbrCells.clear();
283  weights.clear();
284 
285  const label beg = offsets[currCelli];
286  const label end = offsets[currCelli+1];
287 
288  for (label idx = beg; idx < end; ++idx)
289  {
290  const label nbr = cellCells[idx];
291  const label nbrCount = numNbrs[nbr];
292 
293  if (unvisited.test(nbr))
294  {
295  // Not visited (or removed), add to the list
296  nbrCells.push_back(nbr);
297  weights.push_back(nbrCount);
298  }
299  }
300 
301  // Resize DynamicList prior to sortedOrder
302  nbrOrder.resize_nocopy(weights.size());
303 
304  // 2. Ascending order
305  Foam::sortedOrder(weights, nbrOrder);
306 
307  // 3. Add to FIFO in sorted order
308  for (const label nbrIdx : nbrOrder)
309  {
310  queuedCells.push_back(nbrCells[nbrIdx]);
311  }
312  }
313  }
314  }
315 
316  // Debug:
317  // - the peak capacity of queuedCells approximates the
318  // maximum intermediate bandwidth
319  #if 0
320  Pout<< "bandCompression: peak-capacity=" << queuedCells.capacity() << nl;
321  #endif
322 
323  // Now we have new-to-old in newOrder.
324  return newOrder;
325 }
326 
327 
328 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
329 
331 {
332  // Local mesh connectivity
333  CompactListList<label> cellCells;
334  globalMeshData::calcCellCells(mesh, cellCells);
335 
336  return cuthill_mckee_algorithm(cellCells);
337 }
338 
339 
341 (
342  const CompactListList<label>& cellCellAddressing
343 )
344 {
345  return cuthill_mckee_algorithm(cellCellAddressing);
346 }
347 
348 
350 (
351  const labelListList& cellCellAddressing
352 )
353 {
354  return cuthill_mckee_algorithm(cellCellAddressing);
355 }
356 
357 
358 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
The bandCompression function renumbers the addressing such that the band of the matrix is reduced...
dynamicFvMesh & mesh
A simple list of objects of type <T> that is intended to be used as a circular buffer (eg...
A packed storage of objects of type <T> using an offset table for access.
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:201
void clear() noexcept
Clear the addressed list, i.e. set the size to zero.
Definition: DynamicListI.H:405
void push_back(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:555
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
constexpr label labelMax
Definition: label.H:55
A class representing the concept of 0 (zero) that can be used to avoid manipulating objects known to ...
Definition: zero.H:57
void resize_nocopy(const label len)
Alter addressable list size, allocating new space if required without necessarily recovering old cont...
Definition: DynamicListI.H:375
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
labelList bandCompression(const polyMesh &mesh)
Renumber (mesh) addressing to reduce the band of the mesh connectivity, using the Cuthill-McKee algor...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.