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