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