mergeCoupleFacePoints.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 | Copyright (C) 2011-2016 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25  Merge duplicate points created by arbitrary face coupling and remove unused
26  points.
27 
28 \*---------------------------------------------------------------------------*/
29 
30 #include "starMesh.H"
31 #include "demandDrivenData.H"
32 
33 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
34 
35 void Foam::starMesh::mergeCoupleFacePoints()
36 {
37  // mark all used points by looping through all faces in two goes.
38  // First, go into every cell and find min edge length. Use a
39  // fraction of that as a merge tolerance. Loop through all the
40  // points of the cell and query a merge against every other point
41  // of the same cell based on the current tolerance. If two points
42  // merge, find out if any of them already belongs to a "merge set"
43  // (group of points that merge together. If so, add the current
44  // points into the merge set and make sure that the merge label
45  // for the whole set is the lowest of all encountered vertices.
46  // This is stored in a mergeSetID list, under the index of the
47  // merge set. Once all cells (and thus points) are visited, go
48  // through the renumbering list and for each merging point use the
49  // label of the merge set as the new point label.
50  // This is VERY fancy. Use care if/when changing.
51 
52  Info<< endl << "Creating merge sets" << endl;
53 
54  // Create a renumbering list for points
55  // In the first instance the renumbering list is used as a
56  // mergeSetID storage
57  labelList renumberPoints(points_.size(), -1);
58 
59  // create storage of mergeSetIDs
60  label mergeIncrement = points_.size()/10;
61  labelList mergeSetID(mergeIncrement, -1);
62 
63  label nMergeSets = 0;
64 
65  forAll(cellFaces_, celli)
66  {
67  const faceList& curFaces = cellFaces_[celli];
68 
69  // create a list of all points for the cell with duplicates
70  // and find the shortest edge length
71 
72  label nPointsInCell = 0;
73 
74  scalar pointMergeTol = GREAT;
75 
76  forAll(curFaces, facei)
77  {
78  nPointsInCell += curFaces[facei].size();
79 
80  edgeList curEdges = curFaces[facei].edges();
81 
82  forAll(curEdges, edgeI)
83  {
84  scalar length = curEdges[edgeI].mag(points_);
85 
86  if (length < pointMergeTol)
87  {
88  pointMergeTol = length;
89  }
90  }
91  }
92 
93  // set merge tolerance as a fraction of the shortest edge
94  pointMergeTol /= 100.0;
95 
96  // create a list of points
97  labelList cellPoints(nPointsInCell);
98  label nAddedPoints = 0;
99 
100  forAll(curFaces, facei)
101  {
102  const face& f = curFaces[facei];
103 
104  forAll(f, fI)
105  {
106  cellPoints[nAddedPoints] = f[fI];
107  nAddedPoints++;
108  }
109  }
110 
111  // loop n-squared through the local points and merge them up
112  for (label firstPI = 0; firstPI < cellPoints.size() - 1; firstPI++)
113  {
114  for
115  (
116  label otherPI = firstPI;
117  otherPI < cellPoints.size();
118  otherPI++
119  )
120  {
121  if (cellPoints[firstPI] != cellPoints[otherPI])
122  {
123  label a = cellPoints[firstPI];
124  label b = cellPoints[otherPI];
125 
126  if (edge (a, b).mag(points_) < pointMergeTol)
127  {
128  // found a pair of points to merge
129  #ifdef DEBUG_MERGE
130  Info<< "Merging points " << a << " and " << b << endl;
131  #endif
132 
133  // are the two points in a merge group?
134  label mergeSetA = -1;
135  label mergeSetB = -1;
136 
137  if (renumberPoints[a] > -1)
138  {
139  mergeSetA = renumberPoints[a];
140  }
141 
142  if (renumberPoints[b] > -1)
143  {
144  mergeSetB = renumberPoints[b];
145  }
146 
147  if (mergeSetA == -1 && mergeSetB == -1)
148  {
149  // add new merge group
150  #ifdef DEBUG_MERGE
151  Info<< "adding new merge group " << nMergeSets
152  << endl;
153  #endif
154 
155  // mark points as belonging to a new merge set
156  renumberPoints[a] = nMergeSets;
157  renumberPoints[b] = nMergeSets;
158 
159  mergeSetID[nMergeSets] = min(a, b);
160  nMergeSets++;
161 
162  if (nMergeSets >= mergeSetID.size())
163  {
164  Info<< "Resizing mergeSetID" << endl;
165 
166  mergeSetID.setSize
167  (mergeSetID.size() + mergeIncrement);
168  }
169  }
170  else if (mergeSetA == -1 && mergeSetB != -1)
171  {
172  #ifdef DEBUG_MERGE
173  Info<< "adding point a into the merge set of b. "
174  << "a: " << a << endl;
175  #endif
176 
177  // add point a into the merge set of b
178  renumberPoints[a] = mergeSetB;
179 
180  // reset the min label of the mergeSet
181  mergeSetID[mergeSetB] =
182  min(a, mergeSetID[mergeSetB]);
183  }
184  else if (mergeSetA != -1 && mergeSetB == -1)
185  {
186  #ifdef DEBUG_MERGE
187  Info<< "adding point b into the merge set of a. "
188  << "b: " << b << endl;
189  #endif
190 
191  // add point b into the merge set of a
192  renumberPoints[b] = mergeSetA;
193 
194  // reset the min label of the mergeSet
195  mergeSetID[mergeSetA] =
196  min(b, mergeSetID[mergeSetA]);
197  }
198  else if (mergeSetA != mergeSetB)
199  {
200  // Points already belong to two different merge
201  // sets. Eliminate the higher merge set
202  label minMerge = min(mergeSetA, mergeSetB);
203  label maxMerge = max(mergeSetA, mergeSetB);
204 
205  #ifdef DEBUG_MERGE
206  Info<< "Points already belong to two "
207  << "different merge sets. "
208  << "Eliminate the higher merge set. Sets: "
209  << minMerge << " and " << maxMerge << endl;
210  #endif
211 
212  forAll(renumberPoints, elimI)
213  {
214  if (renumberPoints[elimI] == maxMerge)
215  {
216  renumberPoints[elimI] = minMerge;
217  }
218  }
219 
220  // set the lower label
221  mergeSetID[minMerge] =
222  min(mergeSetID[minMerge], mergeSetID[maxMerge]);
223  }
224  }
225  }
226  }
227  }
228  }
229 
230  mergeSetID.setSize(nMergeSets);
231 
232  Info<< "Finished creating merge sets. Number of merge sets: "
233  << nMergeSets << "." << endl;
234 
235  // Insert the primary point renumbering into the list
236  // Take care of possibly unused points in the list
237  forAll(renumberPoints, pointi)
238  {
239  if (renumberPoints[pointi] < 0)
240  {
241  // point not merged
242  renumberPoints[pointi] = pointi;
243  }
244  else
245  {
246  renumberPoints[pointi] = mergeSetID[renumberPoints[pointi]];
247  }
248  }
249 
250  // Now every point carries either its own label or the lowest of
251  // the labels of the points it is merged with. Now do PRELIMINARY
252  // renumbering of all faces. This will only be used to see which
253  // points are still used!
254 
255  forAll(cellFaces_, celli)
256  {
257  faceList& prelimFaces = cellFaces_[celli];
258 
259  forAll(prelimFaces, facei)
260  {
261  face oldFacePoints = prelimFaces[facei];
262 
263  face& prelimFacePoints = prelimFaces[facei];
264 
265  forAll(prelimFacePoints, pointi)
266  {
267  if (renumberPoints[oldFacePoints[pointi]] < 0)
268  {
270  << "Error in point renumbering. Old face: "
271  << oldFacePoints << endl
272  << "prelim face: " << prelimFacePoints
273  << abort(FatalError);
274  }
275 
276  prelimFacePoints[pointi] =
277  renumberPoints[oldFacePoints[pointi]];
278  }
279  }
280  }
281 
282  // First step complete. Reset the renumbering list, mark all used points,
283  // re-create the point list and renumber the whole lot
284  renumberPoints = 0;
285 
286  forAll(cellFaces_, celli)
287  {
288  const faceList& curFaces = cellFaces_[celli];
289 
290  forAll(curFaces, facei)
291  {
292  const face& curFacePoints = curFaces[facei];
293 
294  forAll(curFacePoints, pointi)
295  {
296  renumberPoints[curFacePoints[pointi]]++;
297  }
298  }
299  }
300 
301  forAll(cellShapes_, celli)
302  {
303  const labelList& curLabels = cellShapes_[celli];
304 
305  forAll(curLabels, pointi)
306  {
307  if (renumberPoints[curLabels[pointi]] == 0)
308  {
310  << "Error in point merging for cell "
311  << celli << ". STAR index: " << starCellID_[celli]
312  << ". " << endl
313  << "Point index: " << curLabels[pointi] << " STAR index "
314  << starPointID_[curLabels[pointi]] << endl
315  << "Please check the geometry for the cell." << endl;
316  }
317  }
318  }
319 
320  label nUsedPoints = 0;
321 
322  forAll(renumberPoints, pointi)
323  {
324  if (renumberPoints[pointi] > 0)
325  {
326  // This should be OK as the compressed points list will always
327  // have less points that the original lists. Even if there is
328  // no points removed, this will copy the list back onto itself
329  //
330  renumberPoints[pointi] = nUsedPoints;
331  points_[nUsedPoints] = points_[pointi];
332 
333  nUsedPoints++;
334  }
335  else
336  {
337  renumberPoints[pointi] = -1;
338  }
339  }
340 
341  Info<< "Total number of points: " << points_.size() << endl
342  << "Number of used points: " << nUsedPoints << endl;
343 
344  // reset number of points which need to be sorted
345  points_.setSize(nUsedPoints);
346 
347  Info<< "Renumbering all faces" << endl;
348 
349  forAll(cellFaces_, celli)
350  {
351  faceList& newFaces = cellFaces_[celli];
352 
353  forAll(newFaces, facei)
354  {
355  face oldFacePoints = newFaces[facei];
356 
357  face& newFacePoints = newFaces[facei];
358 
359  forAll(newFacePoints, pointi)
360  {
361  if (renumberPoints[oldFacePoints[pointi]] < 0)
362  {
364  << "Error in point renumbering for point "
365  << oldFacePoints[pointi]
366  << ". Renumbering index is -1." << endl
367  << "Old face: " << oldFacePoints << endl
368  << "New face: " << newFacePoints << abort(FatalError);
369  }
370 
371  newFacePoints[pointi] = renumberPoints[oldFacePoints[pointi]];
372  }
373  }
374  }
375 
376  Info<< "Renumbering all cell shapes" << endl;
377 
378  forAll(cellShapes_, celli)
379  {
380  labelList oldLabels = cellShapes_[celli];
381 
382  labelList& curLabels = cellShapes_[celli];
383 
384  forAll(curLabels, pointi)
385  {
386  if (renumberPoints[curLabels[pointi]] < 0)
387  {
389  << "Error in point renumbering for cell "
390  << celli << ". STAR index: " << starCellID_[celli]
391  << ". " << endl
392  << "Point index: " << curLabels[pointi] << " STAR index "
393  << starPointID_[curLabels[pointi]] << " returns invalid "
394  << "renumbering index: "
395  << renumberPoints[curLabels[pointi]] << "." << endl
396  << "Old cellShape: " << oldLabels << endl
397  << "New cell shape: " << curLabels << abort(FatalError);
398  }
399 
400  curLabels[pointi] = renumberPoints[oldLabels[pointi]];
401  }
402  }
403 
404  Info<< "Renumbering STAR point lookup" << endl;
405 
406  labelList oldStarPointID = starPointID_;
407 
408  starPointID_ = -1;
409 
410  forAll(starPointID_, pointi)
411  {
412  if (renumberPoints[pointi] > -1)
413  {
414  starPointID_[renumberPoints[pointi]] = oldStarPointID[pointi];
415  }
416  }
417 
418  // point-cell addressing has changed. Force it to be re-created
419  deleteDemandDrivenData(pointCellsPtr_);
420 }
421 
422 
423 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
List< face > faceList
Definition: faceListFwd.H:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
List< edge > edgeList
Definition: edgeList.H:38
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
List< label > labelList
A List of labels.
Definition: labelList.H:56
errorManip< error > abort(error &err)
Definition: errorManip.H:131
labelList f(nPoints)
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
void setSize(const label)
Reset size of List.
Definition: List.C:281
Template functions to aid in the implementation of demand driven data.
messageStream Info
void deleteDemandDrivenData(DataPtr &dataPtr)