surfaceSubset.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) 2011-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 Application
25  surfaceSubset
26 
27 Description
28  A surface analysis tool which sub-sets the triSurface
29  to choose only a part of interest. Based on subsetMesh.
30 
31 \*---------------------------------------------------------------------------*/
32 
33 #include "triSurface.H"
34 #include "triSurfaceSearch.H"
35 #include "argList.H"
36 #include "OFstream.H"
37 #include "IFstream.H"
38 #include "Switch.H"
39 #include "IOdictionary.H"
40 #include "boundBox.H"
41 #include "indexedOctree.H"
42 #include "treeDataTriSurface.H"
43 #include "Random.H"
44 #include "volumeType.H"
45 #include "plane.H"
46 
47 using namespace Foam;
48 
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 
51 int main(int argc, char *argv[])
52 {
53  #include "removeCaseOptions.H"
54 
55  argList::validArgs.append("surface file");
56  argList::validArgs.append("output surface file");
57  argList::validArgs.append("surfaceSubsetDict");
58  argList args(argc, argv);
59 
60  Info<< "Reading dictionary " << args[3] << " ..." << endl;
61  IFstream dictFile(args[3]);
62  dictionary meshSubsetDict(dictFile);
63 
64  Info<< "Reading surface " << args[1] << " ..." << endl;
65  triSurface surf1(args[1]);
66 
67  const fileName outFileName = args[2];
68 
69 
70  Info<< "Original:" << endl;
71  surf1.writeStats(Info);
72  Info<< endl;
73 
74 
75  labelList markedPoints
76  (
77  meshSubsetDict.lookup("localPoints")
78  );
79 
80  labelList markedEdges
81  (
82  meshSubsetDict.lookup("edges")
83  );
84 
85  labelList markedFaces
86  (
87  meshSubsetDict.lookup("faces")
88  );
89 
90  pointField markedZone
91  (
92  meshSubsetDict.lookup("zone")
93  );
94 
95  if (markedZone.size() && markedZone.size() != 2)
96  {
98  << "zone specification should be two points, min and max of "
99  << "the boundingbox" << endl
100  << "zone:" << markedZone
101  << exit(FatalError);
102  }
103 
104  Switch addFaceNeighbours
105  (
106  meshSubsetDict.lookup("addFaceNeighbours")
107  );
108 
109  const bool invertSelection =
110  meshSubsetDict.lookupOrDefault("invertSelection", false);
111 
112  // Mark the cells for the subset
113 
114  // Faces to subset
115  boolList facesToSubset(surf1.size(), false);
116 
117 
118  //
119  // pick up faces connected to "localPoints"
120  //
121 
122  if (markedPoints.size())
123  {
124  Info<< "Found " << markedPoints.size() << " marked point(s)." << endl;
125 
126  // pick up cells sharing the point
127 
128  forAll(markedPoints, pointi)
129  {
130  if
131  (
132  markedPoints[pointi] < 0
133  || markedPoints[pointi] >= surf1.nPoints()
134  )
135  {
137  << "localPoint label " << markedPoints[pointi]
138  << "out of range."
139  << " The mesh has got "
140  << surf1.nPoints() << " localPoints."
141  << exit(FatalError);
142  }
143 
144  const labelList& curFaces =
145  surf1.pointFaces()[markedPoints[pointi]];
146 
147  forAll(curFaces, i)
148  {
149  facesToSubset[curFaces[i]] = true;
150  }
151  }
152  }
153 
154 
155 
156  //
157  // pick up faces connected to "edges"
158  //
159 
160  if (markedEdges.size())
161  {
162  Info<< "Found " << markedEdges.size() << " marked edge(s)." << endl;
163 
164  // pick up cells sharing the edge
165 
166  forAll(markedEdges, edgeI)
167  {
168  if
169  (
170  markedEdges[edgeI] < 0
171  || markedEdges[edgeI] >= surf1.nEdges()
172  )
173  {
175  << "edge label " << markedEdges[edgeI]
176  << "out of range."
177  << " The mesh has got "
178  << surf1.nEdges() << " edges."
179  << exit(FatalError);
180  }
181 
182  const labelList& curFaces = surf1.edgeFaces()[markedEdges[edgeI]];
183 
184  forAll(curFaces, i)
185  {
186  facesToSubset[curFaces[i]] = true;
187  }
188  }
189  }
190 
191 
192  //
193  // pick up faces with centre inside "zone"
194  //
195 
196  if (markedZone.size() == 2)
197  {
198  const point& min = markedZone[0];
199  const point& max = markedZone[1];
200 
201  Info<< "Using zone min:" << min << " max:" << max << endl;
202 
203  forAll(surf1, facei)
204  {
205  const point centre = surf1[facei].centre(surf1.points());
206 
207  if
208  (
209  (centre.x() >= min.x())
210  && (centre.y() >= min.y())
211  && (centre.z() >= min.z())
212  && (centre.x() <= max.x())
213  && (centre.y() <= max.y())
214  && (centre.z() <= max.z())
215  )
216  {
217  facesToSubset[facei] = true;
218  }
219  }
220  }
221 
222 
223  //
224  // pick up faces on certain side of surface
225  //
226 
227  if (meshSubsetDict.found("surface"))
228  {
229  const dictionary& surfDict = meshSubsetDict.subDict("surface");
230 
231  fileName surfName(surfDict.lookup("name"));
232 
233  Switch outside(surfDict.lookup("outside"));
234 
235  if (outside)
236  {
237  Info<< "Selecting all triangles with centre outside surface "
238  << surfName << endl;
239  }
240  else
241  {
242  Info<< "Selecting all triangles with centre inside surface "
243  << surfName << endl;
244  }
245 
246  // Read surface to select on
247  triSurface selectSurf(surfName);
248 
249  triSurfaceSearch searchSelectSurf
250  (
251  selectSurf,
253  8
254  );
255 
256  const indexedOctree<treeDataTriSurface>& selectTree =
257  searchSelectSurf.tree();
258 
259  // Check if face (centre) is in outside or inside.
260  forAll(facesToSubset, facei)
261  {
262  if (!facesToSubset[facei])
263  {
264  const point fc(surf1[facei].centre(surf1.points()));
265 
266  volumeType t = selectTree.getVolumeType(fc);
267 
268  if
269  (
270  outside
271  ? (t == volumeType::outside)
272  : (t == volumeType::inside)
273  )
274  {
275  facesToSubset[facei] = true;
276  }
277  }
278  }
279  }
280 
281 
282  if (meshSubsetDict.found("plane"))
283  {
284  const dictionary& planeDict = meshSubsetDict.subDict("plane");
285 
286  const plane pl(planeDict);
287  const scalar distance(planeDict.lookup<scalar>("distance"));
288  const scalar cosAngle(planeDict.lookup<scalar>("cosAngle"));
289 
290  // Select all triangles that are close to the plane and
291  // whose normal aligns with the plane as well.
292 
293  forAll(surf1.faceCentres(), facei)
294  {
295  const point& fc = surf1.faceCentres()[facei];
296  const point& nf = surf1.faceNormals()[facei];
297 
298  if (pl.distance(fc) < distance && mag(pl.normal() & nf) > cosAngle)
299  {
300  facesToSubset[facei] = true;
301  }
302  }
303  }
304 
305 
306 
307  //
308  // pick up specified "faces"
309  //
310 
311  // Number of additional faces picked up because of addFaceNeighbours
312  label nFaceNeighbours = 0;
313 
314  if (markedFaces.size())
315  {
316  Info<< "Found " << markedFaces.size() << " marked face(s)." << endl;
317 
318  // Check and mark faces to pick up
319  forAll(markedFaces, facei)
320  {
321  if
322  (
323  markedFaces[facei] < 0
324  || markedFaces[facei] >= surf1.size()
325  )
326  {
328  << "Face label " << markedFaces[facei] << "out of range."
329  << " The mesh has got "
330  << surf1.size() << " faces."
331  << exit(FatalError);
332  }
333 
334  // Mark the face
335  facesToSubset[markedFaces[facei]] = true;
336 
337  // mark its neighbours if requested
338  if (addFaceNeighbours)
339  {
340  const labelList& curFaces =
341  surf1.faceFaces()[markedFaces[facei]];
342 
343  forAll(curFaces, i)
344  {
345  label facei = curFaces[i];
346 
347  if (!facesToSubset[facei])
348  {
349  facesToSubset[facei] = true;
350  nFaceNeighbours++;
351  }
352  }
353  }
354  }
355  }
356 
357  if (addFaceNeighbours)
358  {
359  Info<< "Added " << nFaceNeighbours
360  << " faces because of addFaceNeighbours" << endl;
361  }
362 
363 
364  if (invertSelection)
365  {
366  Info<< "Inverting selection." << endl;
367 
368  forAll(facesToSubset, i)
369  {
370  facesToSubset[i] = facesToSubset[i] ? false : true;
371  }
372  }
373 
374 
375  // Create subsetted surface
376  labelList pointMap;
378  triSurface surf2
379  (
380  surf1.subsetMesh(facesToSubset, pointMap, faceMap)
381  );
382 
383  Info<< "Subset:" << endl;
384  surf2.writeStats(Info);
385  Info<< endl;
386 
387  Info<< "Writing surface to " << outFileName << endl;
388 
389  surf2.write(outFileName);
390 
391  return 0;
392 }
393 
394 
395 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Input from file stream.
Definition: IFstream.H:85
virtual Ostream & write(const char)=0
Write character.
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
const Cmpt & z() const
Definition: VectorI.H:87
const Cmpt & y() const
Definition: VectorI.H:81
const Cmpt & x() const
Definition: VectorI.H:75
const Vector< Cmpt > & centre(const Foam::List< Vector< Cmpt >> &) const
Return *this (used for point which is a typedef to Vector<scalar>.
Definition: VectorI.H:116
Extract command arguments and options from the supplied argc and argv parameters.
Definition: argList.H:103
static SLList< string > validArgs
A list of valid (mandatory) arguments.
Definition: argList.H:153
A list of keyword definitions, which are a keyword followed by any number of values (e....
Definition: dictionary.H:160
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:860
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:998
A class for handling file names.
Definition: fileName.H:82
Non-pointer based hierarchical recursive searching.
Definition: indexedOctree.H:72
Geometric class that creates a 2D plane and can return the intersection point between a line and the ...
Definition: plane.H:61
Helper class to search on triSurface.
Triangulated surface description with patch information.
Definition: triSurface.H:69
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
int main(int argc, char *argv[])
Definition: financialFoam.C:44
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
messageStream Info
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensioned< scalar > mag(const dimensioned< Type > &)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
error FatalError
Foam::argList args(argc, argv)