shortEdgeFilter2D.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) 2013-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 \*---------------------------------------------------------------------------*/
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 
148 Foam::shortEdgeFilter2D::shortEdgeFilter2D
149 (
150  const Foam::CV2D& cv2Dmesh,
151  const dictionary& dict
152 )
153 :
154  cv2Dmesh_(cv2Dmesh),
155  shortEdgeFilterFactor_(readScalar(dict.lookup("shortEdgeFilterFactor"))),
156  edgeAttachedToBoundaryFactor_
157  (
158  dict.lookupOrDefault<scalar>("edgeAttachedToBoundaryFactor", 2.0)
159  ),
160  patchNames_(wordList()),
161  patchSizes_(labelList()),
162  mapEdgesRegion_(),
163  indirectPatchEdge_()
164 {
165  point2DField points2D;
166  faceList faces;
167 
168  cv2Dmesh.calcDual
169  (
170  points2D,
171  faces,
172  patchNames_,
173  patchSizes_,
174  mapEdgesRegion_,
175  indirectPatchEdge_
176  );
177 
178  pointField points(points2D.size());
179  forAll(points, ip)
180  {
181  points[ip] = cv2Dmesh.toPoint3D(points2D[ip]);
182  }
183 
184  if (debug)
185  {
186  OFstream str("indirectPatchEdges.obj");
187  label count = 0;
188 
189  Info<< "Writing indirectPatchEdges to " << str.name() << endl;
190 
191  forAllConstIter(EdgeMap<label>, indirectPatchEdge_, iter)
192  {
193  const edge& e = iter.key();
194 
196  (
197  str,
198  points[e.start()],
199  points[e.end()],
200  count
201  );
202  }
203  }
204 
205  points2D.clear();
206 
207  ms_ = MeshedSurface<face>(xferMove(points), xferMove(faces));
208 
209  Info<< "Meshed surface stats before edge filtering :" << endl;
210  ms_.writeStats(Info);
211 
212  if (debug)
213  {
214  writeInfo(Info);
215 
216  ms_.write("MeshedSurface_preFilter.obj");
217  }
218 }
219 
220 
221 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
222 
224 {}
225 
226 
227 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
228 
229 void
231 {
232  // These are global indices.
233  const pointField& points = ms_.points();
234  const edgeList& edges = ms_.edges();
235  const faceList& faces = ms_.faces();
236  const labelList& meshPoints = ms_.meshPoints();
237  const labelList& boundaryPoints = ms_.boundaryPoints();
238 
239  label maxChain = 0;
240  label nPointsToRemove = 0;
241 
242  labelList pointsToRemove(ms_.points().size(), -1);
243 
244  // List of number of vertices in a face.
245  labelList newFaceVertexCount(faces.size(), -1);
246  forAll(faces, facei)
247  {
248  newFaceVertexCount[facei] = faces[facei].size();
249  }
250 
251  // Check if the point is a boundary point. Flag if it is so that
252  // it will not be deleted.
253  List<DynamicList<label>> boundaryPointRegions
254  (
255  points.size(),
256  DynamicList<label>()
257  );
258  assignBoundaryPointRegions(boundaryPointRegions);
259 
260  // Check if an edge has a boundary point. It it does the edge length
261  // will be doubled when working out its length.
262  Info<< " Marking edges attached to boundaries." << endl;
263  boolList edgeAttachedToBoundary(edges.size(), false);
264  forAll(edges, edgeI)
265  {
266  const edge& e = edges[edgeI];
267  const label startVertex = e.start();
268  const label endVertex = e.end();
269 
270  forAll(boundaryPoints, bPoint)
271  {
272  if
273  (
274  boundaryPoints[bPoint] == startVertex
275  || boundaryPoints[bPoint] == endVertex
276  )
277  {
278  edgeAttachedToBoundary[edgeI] = true;
279  }
280  }
281  }
282 
283  forAll(edges, edgeI)
284  {
285  const edge& e = edges[edgeI];
286 
287  // get the vertices of that edge.
288  const label startVertex = e.start();
289  const label endVertex = e.end();
290 
291  scalar edgeLength =
292  mag
293  (
294  points[meshPoints[startVertex]]
295  - points[meshPoints[endVertex]]
296  );
297 
298  if (edgeAttachedToBoundary[edgeI])
299  {
300  edgeLength *= edgeAttachedToBoundaryFactor_;
301  }
302 
303  scalar shortEdgeFilterValue = 0.0;
304 
305  const labelList& psEdges = ms_.pointEdges()[startVertex];
306  const labelList& peEdges = ms_.pointEdges()[endVertex];
307 
308  forAll(psEdges, psEdgeI)
309  {
310  const edge& psE = edges[psEdges[psEdgeI]];
311  if (edgeI != psEdges[psEdgeI])
312  {
313  shortEdgeFilterValue +=
314  mag
315  (
316  points[meshPoints[psE.start()]]
317  - points[meshPoints[psE.end()]]
318  );
319  }
320  }
321 
322  forAll(peEdges, peEdgeI)
323  {
324  const edge& peE = edges[peEdges[peEdgeI]];
325  if (edgeI != peEdges[peEdgeI])
326  {
327  shortEdgeFilterValue +=
328  mag
329  (
330  points[meshPoints[peE.start()]]
331  - points[meshPoints[peE.end()]]
332  );
333  }
334  }
335 
336  shortEdgeFilterValue *=
337  shortEdgeFilterFactor_
338  /(psEdges.size() + peEdges.size() - 2);
339 
340  edge lookupInPatchEdge
341  (
342  meshPoints[startVertex],
343  meshPoints[endVertex]
344  );
345 
346  if
347  (
348  edgeLength < shortEdgeFilterValue
349  || indirectPatchEdge_.found(lookupInPatchEdge)
350  )
351  {
352  bool flagDegenerateFace = false;
353  const labelList& pFaces = ms_.pointFaces()[startVertex];
354 
355  forAll(pFaces, pFacei)
356  {
357  const face& f = ms_.localFaces()[pFaces[pFacei]];
358  forAll(f, fp)
359  {
360  // If the edge is part of this face...
361  if (f[fp] == endVertex)
362  {
363  // If deleting vertex would create a triangle, don't!
364  if (newFaceVertexCount[pFaces[pFacei]] < 4)
365  {
366  flagDegenerateFace = true;
367  }
368  else
369  {
370  newFaceVertexCount[pFaces[pFacei]]--;
371  }
372  }
373  // If the edge is not part of this face...
374  else
375  {
376  // Deleting vertex of a triangle...
377  if (newFaceVertexCount[pFaces[pFacei]] < 3)
378  {
379  flagDegenerateFace = true;
380  }
381  }
382  }
383  }
384 
385  // This if statement determines whether a point should be deleted.
386  if
387  (
388  pointsToRemove[meshPoints[startVertex]] == -1
389  && pointsToRemove[meshPoints[endVertex]] == -1
390  && !flagDegenerateFace
391  )
392  {
393  const DynamicList<label>& startVertexRegions =
394  boundaryPointRegions[meshPoints[startVertex]];
395  const DynamicList<label>& endVertexRegions =
396  boundaryPointRegions[meshPoints[endVertex]];
397 
398  if (startVertexRegions.size() && endVertexRegions.size())
399  {
400  if (startVertexRegions.size() > 1)
401  {
402  pointsToRemove[meshPoints[endVertex]] =
403  meshPoints[startVertex];
404  }
405  else
406  {
407  pointsToRemove[meshPoints[startVertex]] =
408  meshPoints[endVertex];
409  }
410  }
411  else if (startVertexRegions.size())
412  {
413  pointsToRemove[meshPoints[endVertex]] =
414  meshPoints[startVertex];
415  }
416  else
417  {
418  pointsToRemove[meshPoints[startVertex]] =
419  meshPoints[endVertex];
420  }
421 
422  ++nPointsToRemove;
423  }
424  }
425  }
426 
427  label totalNewPoints = points.size() - nPointsToRemove;
428 
429  pointField newPoints(totalNewPoints, Zero);
430  labelList newPointNumbers(points.size(), -1);
431  label numberRemoved = 0;
432 
433  // Maintain addressing from new to old point field
434  labelList newPtToOldPt(totalNewPoints, -1);
435 
436  forAll(points, pointi)
437  {
438  // If the point is NOT going to be removed.
439  if (pointsToRemove[pointi] == -1)
440  {
441  newPoints[pointi - numberRemoved] = points[pointi];
442  newPointNumbers[pointi] = pointi - numberRemoved;
443  newPtToOldPt[pointi - numberRemoved] = pointi;
444  }
445  else
446  {
447  numberRemoved++;
448  }
449  }
450 
451  // Need a new faceList
452  faceList newFaces(faces.size());
453  label newFacei = 0;
454 
455  labelList newFace;
456  label newFaceSize = 0;
457 
458  // Now need to iterate over the faces and remove points. Global index.
459  forAll(faces, facei)
460  {
461  const face& f = faces[facei];
462 
463  newFace.clear();
464  newFace.setSize(f.size());
465  newFaceSize = 0;
466 
467  forAll(f, fp)
468  {
469  label pointi = f[fp];
470  // If not removing the point, then add it to the new face.
471  if (pointsToRemove[pointi] == -1)
472  {
473  newFace[newFaceSize++] = newPointNumbers[pointi];
474  }
475  else
476  {
477  label newPointi = pointsToRemove[pointi];
478  // Replace deleted point with point that it is being
479  // collapsed to.
480  if
481  (
482  f.nextLabel(fp) != newPointi
483  && f.prevLabel(fp) != newPointi
484  )
485  {
486  label pChain = newPointi;
487  label totalChain = 0;
488  for (label nChain = 0; nChain <= totalChain; ++nChain)
489  {
490  if (newPointNumbers[pChain] != -1)
491  {
492  newFace[newFaceSize++] = newPointNumbers[pChain];
493  newPointNumbers[pointi] = newPointNumbers[pChain];
494  maxChain = max(totalChain, maxChain);
495  }
496  else
497  {
499  << "Point " << pChain
500  << " marked for deletion as well as point "
501  << pointi << nl
502  << " Incrementing maxChain by 1 from "
503  << totalChain << " to " << totalChain + 1
504  << endl;
505  totalChain++;
506  }
507  pChain = pointsToRemove[pChain];
508  }
509  }
510  else
511  {
512  if (newPointNumbers[newPointi] != -1)
513  {
514  newPointNumbers[pointi] = newPointNumbers[newPointi];
515  }
516  }
517  }
518  }
519 
520  newFace.setSize(newFaceSize);
521 
522  if (newFace.size() > 2)
523  {
524  newFaces[newFacei++] = face(newFace);
525  }
526  else
527  {
529  << "Only " << newFace.size() << " in face " << facei
530  << exit(FatalError);
531  }
532  }
533 
534  newFaces.setSize(newFacei);
535 
536  MeshedSurface<face> fMesh
537  (
538  xferMove(newPoints),
539  xferMove(newFaces),
540  xferCopy(List<surfZone>())
541  );
542 
543  updateEdgeRegionMap
544  (
545  fMesh,
546  boundaryPointRegions,
547  newPtToOldPt,
548  mapEdgesRegion_,
549  patchSizes_
550  );
551 
552  forAll(newPointNumbers, pointi)
553  {
554  if (newPointNumbers[pointi] == -1)
555  {
557  << pointi << " will be deleted and " << newPointNumbers[pointi]
558  << ", so it will not be replaced. "
559  << "This will cause edges to be deleted." << endl;
560  }
561  }
562 
563  ms_.transfer(fMesh);
564 
565  if (debug)
566  {
567  Info<< " Maximum number of chained collapses = " << maxChain << endl;
568 
569  writeInfo(Info);
570  }
571 }
572 
573 
574 void Foam::shortEdgeFilter2D::writeInfo(Ostream& os)
575 {
576  os << "Short Edge Filtering Information:" << nl
577  << " shortEdgeFilterFactor: " << shortEdgeFilterFactor_ << nl
578  << " edgeAttachedToBoundaryFactor: " << edgeAttachedToBoundaryFactor_
579  << endl;
580 
581  forAll(patchNames_, patchi)
582  {
583  os << " Patch " << patchNames_[patchi]
584  << ", size " << patchSizes_[patchi] << endl;
585  }
586 
587  os << " There are " << mapEdgesRegion_.size()
588  << " boundary edges." << endl;
589 
590  os << " Mesh Info:" << nl
591  << " Points: " << ms_.nPoints() << nl
592  << " Faces: " << ms_.size() << nl
593  << " Edges: " << ms_.nEdges() << nl
594  << " Internal: " << ms_.nInternalEdges() << nl
595  << " External: " << ms_.nEdges() - ms_.nInternalEdges()
596  << endl;
597 }
598 
599 
600 // ************************************************************************* //
~shortEdgeFilter2D()
Destructor.
#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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
List< face > faceList
Definition: faceListFwd.H:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
point toPoint3D(const point2D &) const
Definition: CV2DI.H:141
Xfer< T > xferCopy(const T &)
Construct by copying the contents of the arg.
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
List< bool > boolList
Bool container classes.
Definition: boolList.H:50
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
stressControl lookup("compactNormalStress") >> compactNormalStress
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.
const pointField & points
List< edge > edgeList
Definition: edgeList.H:38
Xfer< T > xferMove(T &)
Construct by transferring the contents of the arg.
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:91
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if succesful.
Definition: doubleScalar.H:63
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
static const char nl
Definition: Ostream.H:262
defineTypeNameAndDebug(combustionModel, 0)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurence 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:295
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:146
void writeInfo(Ostream &os)
Namespace for OpenFOAM.