All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
shortEdgeFilter2D.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2013-2019 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 \*---------------------------------------------------------------------------*/
25 
26 #include "shortEdgeFilter2D.H"
27 
28 namespace Foam
29 {
30  defineTypeNameAndDebug(shortEdgeFilter2D, 0);
31 }
32 
33 
34 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
35 
36 void Foam::shortEdgeFilter2D::addRegion
37 (
38  const label regionI,
39  DynamicList<label>& bPointRegions
40 ) const
41 {
42  if (bPointRegions.empty())
43  {
44  bPointRegions.append(regionI);
45  }
46  else if (findIndex(bPointRegions, regionI) == -1)
47  {
48  bPointRegions.append(regionI);
49  }
50 }
51 
52 
53 void Foam::shortEdgeFilter2D::assignBoundaryPointRegions
54 (
55  List<DynamicList<label>>& boundaryPointRegions
56 ) const
57 {
58  forAllConstIter(EdgeMap<label>, mapEdgesRegion_, iter)
59  {
60  const edge& e = iter.key();
61  const label& regionI = iter();
62 
63  const label startI = e.start();
64  const label endI = e.end();
65 
66  addRegion(regionI, boundaryPointRegions[startI]);
67  addRegion(regionI, boundaryPointRegions[endI]);
68  }
69 }
70 
71 
72 void Foam::shortEdgeFilter2D::updateEdgeRegionMap
73 (
74  const MeshedSurface<face>& surfMesh,
75  const List<DynamicList<label>>& boundaryPtRegions,
76  const labelList& surfPtToBoundaryPt,
77  EdgeMap<label>& mapEdgesRegion,
78  labelList& patchSizes
79 ) const
80 {
81  EdgeMap<label> newMapEdgesRegion(mapEdgesRegion.size());
82 
83  const edgeList& edges = surfMesh.edges();
84  const labelList& meshPoints = surfMesh.meshPoints();
85 
86  patchSizes.setSize(patchNames_.size(), 0);
87  patchSizes = 0;
88 
89  forAll(edges, edgeI)
90  {
91  if (surfMesh.isInternalEdge(edgeI))
92  {
93  continue;
94  }
95 
96  const edge& e = edges[edgeI];
97 
98  const label startI = meshPoints[e[0]];
99  const label endI = meshPoints[e[1]];
100 
101  label region = -1;
102 
103  const DynamicList<label> startPtRegions =
104  boundaryPtRegions[surfPtToBoundaryPt[startI]];
105  const DynamicList<label> endPtRegions =
106  boundaryPtRegions[surfPtToBoundaryPt[endI]];
107 
108  if (startPtRegions.size() > 1 && endPtRegions.size() > 1)
109  {
110  region = startPtRegions[0];
111 
113  << "Both points in edge are in different regions."
114  << " Assigning edge to region " << region
115  << endl;
116  }
117  else if (startPtRegions.size() > 1 || endPtRegions.size() > 1)
118  {
119  region =
120  (
121  startPtRegions.size() > 1
122  ? endPtRegions[0]
123  : startPtRegions[0]
124  );
125  }
126  else if
127  (
128  startPtRegions[0] == endPtRegions[0]
129  && startPtRegions[0] != -1
130  )
131  {
132  region = startPtRegions[0];
133  }
134 
135  if (region != -1)
136  {
137  newMapEdgesRegion.insert(e, region);
138  patchSizes[region]++;
139  }
140  }
141 
142  mapEdgesRegion.transfer(newMapEdgesRegion);
143 }
144 
145 
146 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
147 
149 (
150  const Foam::CV2D& cv2Dmesh,
151  const dictionary& dict
152 )
153 :
154  shortEdgeFilterFactor_(dict.lookup<scalar>("shortEdgeFilterFactor")),
155  edgeAttachedToBoundaryFactor_
156  (
157  dict.lookupOrDefault<scalar>("edgeAttachedToBoundaryFactor", 2.0)
158  ),
159  patchNames_(wordList()),
160  patchSizes_(labelList()),
161  mapEdgesRegion_(),
162  indirectPatchEdge_()
163 {
164  point2DField points2D;
165  faceList faces;
166 
167  cv2Dmesh.calcDual
168  (
169  points2D,
170  faces,
171  patchNames_,
172  patchSizes_,
173  mapEdgesRegion_,
174  indirectPatchEdge_
175  );
176 
177  pointField points(points2D.size());
178  forAll(points, ip)
179  {
180  points[ip] = cv2Dmesh.toPoint3D(points2D[ip]);
181  }
182 
183  if (debug)
184  {
185  OFstream str("indirectPatchEdges.obj");
186  label count = 0;
187 
188  Info<< "Writing indirectPatchEdges to " << str.name() << endl;
189 
190  forAllConstIter(EdgeMap<label>, indirectPatchEdge_, iter)
191  {
192  const edge& e = iter.key();
193 
195  (
196  str,
197  points[e.start()],
198  points[e.end()],
199  count
200  );
201  }
202  }
203 
204  points2D.clear();
205 
206  ms_ = MeshedSurface<face>(move(points), move(faces));
207 
208  Info<< "Meshed surface stats before edge filtering :" << endl;
209  ms_.writeStats(Info);
210 
211  if (debug)
212  {
213  writeInfo(Info);
214 
215  ms_.write("MeshedSurface_preFilter.obj");
216  }
217 }
218 
219 
220 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
221 
223 {}
224 
225 
226 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
227 
228 void
230 {
231  // These are global indices.
232  const pointField& points = ms_.points();
233  const edgeList& edges = ms_.edges();
234  const faceList& faces = ms_.faces();
235  const labelList& meshPoints = ms_.meshPoints();
236  const labelList& boundaryPoints = ms_.boundaryPoints();
237 
238  label maxChain = 0;
239  label nPointsToRemove = 0;
240 
241  labelList pointsToRemove(ms_.points().size(), -1);
242 
243  // List of number of vertices in a face.
244  labelList newFaceVertexCount(faces.size(), -1);
245  forAll(faces, facei)
246  {
247  newFaceVertexCount[facei] = faces[facei].size();
248  }
249 
250  // Check if the point is a boundary point. Flag if it is so that
251  // it will not be deleted.
252  List<DynamicList<label>> boundaryPointRegions
253  (
254  points.size(),
255  DynamicList<label>()
256  );
257  assignBoundaryPointRegions(boundaryPointRegions);
258 
259  // Check if an edge has a boundary point. It it does the edge length
260  // will be doubled when working out its length.
261  Info<< " Marking edges attached to boundaries." << endl;
262  boolList edgeAttachedToBoundary(edges.size(), false);
263  forAll(edges, edgeI)
264  {
265  const edge& e = edges[edgeI];
266  const label startVertex = e.start();
267  const label endVertex = e.end();
268 
269  forAll(boundaryPoints, bPoint)
270  {
271  if
272  (
273  boundaryPoints[bPoint] == startVertex
274  || boundaryPoints[bPoint] == endVertex
275  )
276  {
277  edgeAttachedToBoundary[edgeI] = true;
278  }
279  }
280  }
281 
282  forAll(edges, edgeI)
283  {
284  const edge& e = edges[edgeI];
285 
286  // get the vertices of that edge.
287  const label startVertex = e.start();
288  const label endVertex = e.end();
289 
290  scalar edgeLength =
291  mag
292  (
293  points[meshPoints[startVertex]]
294  - points[meshPoints[endVertex]]
295  );
296 
297  if (edgeAttachedToBoundary[edgeI])
298  {
299  edgeLength *= edgeAttachedToBoundaryFactor_;
300  }
301 
302  scalar shortEdgeFilterValue = 0.0;
303 
304  const labelList& psEdges = ms_.pointEdges()[startVertex];
305  const labelList& peEdges = ms_.pointEdges()[endVertex];
306 
307  forAll(psEdges, psEdgeI)
308  {
309  const edge& psE = edges[psEdges[psEdgeI]];
310  if (edgeI != psEdges[psEdgeI])
311  {
312  shortEdgeFilterValue +=
313  mag
314  (
315  points[meshPoints[psE.start()]]
316  - points[meshPoints[psE.end()]]
317  );
318  }
319  }
320 
321  forAll(peEdges, peEdgeI)
322  {
323  const edge& peE = edges[peEdges[peEdgeI]];
324  if (edgeI != peEdges[peEdgeI])
325  {
326  shortEdgeFilterValue +=
327  mag
328  (
329  points[meshPoints[peE.start()]]
330  - points[meshPoints[peE.end()]]
331  );
332  }
333  }
334 
335  shortEdgeFilterValue *=
336  shortEdgeFilterFactor_
337  /(psEdges.size() + peEdges.size() - 2);
338 
339  edge lookupInPatchEdge
340  (
341  meshPoints[startVertex],
342  meshPoints[endVertex]
343  );
344 
345  if
346  (
347  edgeLength < shortEdgeFilterValue
348  || indirectPatchEdge_.found(lookupInPatchEdge)
349  )
350  {
351  bool flagDegenerateFace = false;
352  const labelList& pFaces = ms_.pointFaces()[startVertex];
353 
354  forAll(pFaces, pFacei)
355  {
356  const face& f = ms_.localFaces()[pFaces[pFacei]];
357  forAll(f, fp)
358  {
359  // If the edge is part of this face...
360  if (f[fp] == endVertex)
361  {
362  // If deleting vertex would create a triangle, don't!
363  if (newFaceVertexCount[pFaces[pFacei]] < 4)
364  {
365  flagDegenerateFace = true;
366  }
367  else
368  {
369  newFaceVertexCount[pFaces[pFacei]]--;
370  }
371  }
372  // If the edge is not part of this face...
373  else
374  {
375  // Deleting vertex of a triangle...
376  if (newFaceVertexCount[pFaces[pFacei]] < 3)
377  {
378  flagDegenerateFace = true;
379  }
380  }
381  }
382  }
383 
384  // This if statement determines whether a point should be deleted.
385  if
386  (
387  pointsToRemove[meshPoints[startVertex]] == -1
388  && pointsToRemove[meshPoints[endVertex]] == -1
389  && !flagDegenerateFace
390  )
391  {
392  const DynamicList<label>& startVertexRegions =
393  boundaryPointRegions[meshPoints[startVertex]];
394  const DynamicList<label>& endVertexRegions =
395  boundaryPointRegions[meshPoints[endVertex]];
396 
397  if (startVertexRegions.size() && endVertexRegions.size())
398  {
399  if (startVertexRegions.size() > 1)
400  {
401  pointsToRemove[meshPoints[endVertex]] =
402  meshPoints[startVertex];
403  }
404  else
405  {
406  pointsToRemove[meshPoints[startVertex]] =
407  meshPoints[endVertex];
408  }
409  }
410  else if (startVertexRegions.size())
411  {
412  pointsToRemove[meshPoints[endVertex]] =
413  meshPoints[startVertex];
414  }
415  else
416  {
417  pointsToRemove[meshPoints[startVertex]] =
418  meshPoints[endVertex];
419  }
420 
421  ++nPointsToRemove;
422  }
423  }
424  }
425 
426  label totalNewPoints = points.size() - nPointsToRemove;
427 
428  pointField newPoints(totalNewPoints, Zero);
429  labelList newPointNumbers(points.size(), -1);
430  label numberRemoved = 0;
431 
432  // Maintain addressing from new to old point field
433  labelList newPtToOldPt(totalNewPoints, -1);
434 
435  forAll(points, pointi)
436  {
437  // If the point is NOT going to be removed.
438  if (pointsToRemove[pointi] == -1)
439  {
440  newPoints[pointi - numberRemoved] = points[pointi];
441  newPointNumbers[pointi] = pointi - numberRemoved;
442  newPtToOldPt[pointi - numberRemoved] = pointi;
443  }
444  else
445  {
446  numberRemoved++;
447  }
448  }
449 
450  // Need a new faceList
451  faceList newFaces(faces.size());
452  label newFacei = 0;
453 
454  labelList newFace;
455  label newFaceSize = 0;
456 
457  // Now need to iterate over the faces and remove points. Global index.
458  forAll(faces, facei)
459  {
460  const face& f = faces[facei];
461 
462  newFace.clear();
463  newFace.setSize(f.size());
464  newFaceSize = 0;
465 
466  forAll(f, fp)
467  {
468  label pointi = f[fp];
469  // If not removing the point, then add it to the new face.
470  if (pointsToRemove[pointi] == -1)
471  {
472  newFace[newFaceSize++] = newPointNumbers[pointi];
473  }
474  else
475  {
476  label newPointi = pointsToRemove[pointi];
477  // Replace deleted point with point that it is being
478  // collapsed to.
479  if
480  (
481  f.nextLabel(fp) != newPointi
482  && f.prevLabel(fp) != newPointi
483  )
484  {
485  label pChain = newPointi;
486  label totalChain = 0;
487  for (label nChain = 0; nChain <= totalChain; ++nChain)
488  {
489  if (newPointNumbers[pChain] != -1)
490  {
491  newFace[newFaceSize++] = newPointNumbers[pChain];
492  newPointNumbers[pointi] = newPointNumbers[pChain];
493  maxChain = max(totalChain, maxChain);
494  }
495  else
496  {
498  << "Point " << pChain
499  << " marked for deletion as well as point "
500  << pointi << nl
501  << " Incrementing maxChain by 1 from "
502  << totalChain << " to " << totalChain + 1
503  << endl;
504  totalChain++;
505  }
506  pChain = pointsToRemove[pChain];
507  }
508  }
509  else
510  {
511  if (newPointNumbers[newPointi] != -1)
512  {
513  newPointNumbers[pointi] = newPointNumbers[newPointi];
514  }
515  }
516  }
517  }
518 
519  newFace.setSize(newFaceSize);
520 
521  if (newFace.size() > 2)
522  {
523  newFaces[newFacei++] = face(newFace);
524  }
525  else
526  {
528  << "Only " << newFace.size() << " in face " << facei
529  << exit(FatalError);
530  }
531  }
532 
533  newFaces.setSize(newFacei);
534 
535  MeshedSurface<face> fMesh
536  (
537  move(newPoints),
538  move(newFaces),
539  List<surfZone>()
540  );
541 
542  updateEdgeRegionMap
543  (
544  fMesh,
545  boundaryPointRegions,
546  newPtToOldPt,
547  mapEdgesRegion_,
548  patchSizes_
549  );
550 
551  forAll(newPointNumbers, pointi)
552  {
553  if (newPointNumbers[pointi] == -1)
554  {
556  << pointi << " will be deleted and " << newPointNumbers[pointi]
557  << ", so it will not be replaced. "
558  << "This will cause edges to be deleted." << endl;
559  }
560  }
561 
562  ms_.transfer(fMesh);
563 
564  if (debug)
565  {
566  Info<< " Maximum number of chained collapses = " << maxChain << endl;
567 
568  writeInfo(Info);
569  }
570 }
571 
572 
573 void Foam::shortEdgeFilter2D::writeInfo(Ostream& os)
574 {
575  os << "Short Edge Filtering Information:" << nl
576  << " shortEdgeFilterFactor: " << shortEdgeFilterFactor_ << nl
577  << " edgeAttachedToBoundaryFactor: " << edgeAttachedToBoundaryFactor_
578  << endl;
579 
580  forAll(patchNames_, patchi)
581  {
582  os << " Patch " << patchNames_[patchi]
583  << ", size " << patchSizes_[patchi] << endl;
584  }
585 
586  os << " There are " << mapEdgesRegion_.size()
587  << " boundary edges." << endl;
588 
589  os << " Mesh Info:" << nl
590  << " Points: " << ms_.nPoints() << nl
591  << " Faces: " << ms_.size() << nl
592  << " Edges: " << ms_.nEdges() << nl
593  << " Internal: " << ms_.nInternalEdges() << nl
594  << " External: " << ms_.nEdges() - ms_.nInternalEdges()
595  << endl;
596 }
597 
598 
599 // ************************************************************************* //
~shortEdgeFilter2D()
Destructor.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
List< face > faceList
Definition: faceListFwd.H:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
point toPoint3D(const point2D &) const
Definition: CV2DI.H:141
label count(const ListType &l, typename ListType::const_reference x)
Count the number of occurrences of a value in a list.
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
shortEdgeFilter2D(const CV2D &cv2Dmesh, const dictionary &dict)
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
stressControl lookup("compactNormalStress") >> compactNormalStress
const pointField & points
List< edge > edgeList
Definition: edgeList.H:38
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:97
void calcDual(point2DField &dualPoints, faceList &dualFaces, wordList &patchNames, labelList &patchSizes, EdgeMap< label > &mapEdgesRegion, EdgeMap< label > &indirectPatchEdge) const
Calculates dual points (circumcentres of tets) and faces.
static const char nl
Definition: Ostream.H:260
defineTypeNameAndDebug(combustionModel, 0)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
vector2DField point2DField
point2DField is a vector2DField.
List< word > wordList
A List of words.
Definition: fileName.H:54
void setSize(const label)
Reset size of List.
Definition: List.C:281
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
label newPointi
Definition: readKivaGrid.H:501
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
Conformal-Voronoi 2D automatic mesher with grid or read initial points and point position relaxation ...
Definition: CV2D.H:144
void writeInfo(Ostream &os)
Namespace for OpenFOAM.