Loading...
Searching...
No Matches
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-------------------------------------------------------------------------------
11License
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
31namespace Foam
32{
34}
35
36
37// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38
39void 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
55void Foam::shortEdgeFilter2D::updateEdgeRegionMap
56(
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 labelUList& startPtRegions =
84 boundaryPtRegions[surfPtToBoundaryPt[meshPoints[e.first()]]];
85
86 const labelUList& 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
129Foam::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
175 meshTools::writeOBJ
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 labelUList& startVertexRegions =
367 boundaryPointRegions[meshPoints[startVertex]];
368 const labelUList& 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
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// ************************************************************************* //
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::point toPoint3D(const point2D &) const
Definition CV2DI.H:135
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
Map from edge (expressed as its endpoints) to value. Hashing (and ==) on an edge is symmetric.
Definition edgeHashes.H:59
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition ListI.H:171
void clear()
Clear the list, i.e. set size to zero.
Definition ListI.H:133
A surface geometry mesh with zone information, not to be confused with the similarly named surfaceMes...
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition Ostream.H:59
const edgeList & edges() const
Return list of edges, address into LOCAL point list.
const labelList & meshPoints() const
Return labelList of mesh points in patch.
bool isInternalEdge(const label edgei) const
Is internal edge?
T & first()
Access first element of the list, position [0].
Definition UList.H:957
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition dictionary.H:133
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
This class filters short edges generated by the CV2D mesher.
const MeshedSurface< face > & fMesh() const
void writeInfo(Ostream &os)
A surface mesh consisting of general polygon faces that has IO capabilities and a registry for storin...
Definition surfMesh.H:67
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
const pointField & points
#define WarningInFunction
Report a warning using Foam::Warning.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition BitOps.H:73
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
Namespace for OpenFOAM.
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
vector2DField point2DField
point2DField is a vector2DField.
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
List< face > faceList
List of faces.
Definition faceListFwd.H:41
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
UList< label > labelUList
A UList of labels.
Definition UList.H:75
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
label newPointi
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];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } 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};constexpr 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< DynamicList< face > > pFaces[nBCs]
labelList f(nPoints)
dictionary dict
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235