selectCells.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-2025 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  selectCells
26 
27 Description
28  Select cells in relation to surface.
29 
30  Divides cells into three sets:
31  - cutCells : cells cut by surface or close to surface.
32  - outside : cells not in cutCells and reachable from set of
33  user-defined points (outsidePoints)
34  - inside : same but not reachable.
35 
36  Finally the wanted sets are combined into a cellSet 'selected'. Apart
37  from straightforward adding the contents there are a few extra rules to
38  make sure that the surface of the 'outside' of the mesh is singly
39  connected.
40 
41 \*---------------------------------------------------------------------------*/
42 
43 #include "argList.H"
44 #include "Time.H"
45 #include "polyMesh.H"
46 #include "IOdictionary.H"
47 #include "twoDPointCorrector.H"
48 #include "OFstream.H"
49 #include "meshTools.H"
50 
51 #include "triSurface.H"
52 #include "triSurfaceSearch.H"
53 #include "meshSearch.H"
54 #include "cellClassification.H"
55 #include "cellSet.H"
56 #include "cellInfo.H"
57 #include "FaceCellWave.H"
58 #include "edgeStats.H"
59 #include "treeDataTriSurface.H"
60 #include "indexedOctree.H"
61 #include "globalMeshData.H"
62 
63 using namespace Foam;
64 
65 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
66 
67 // cellType for cells included/not included in mesh.
68 static const label MESH = cellClassification::INSIDE;
69 static const label NONMESH = cellClassification::OUTSIDE;
70 
71 
72 void writeSet(const cellSet& cells, const string& msg)
73 {
74  Info<< "Writing " << msg << " (" << cells.size() << ") to cellSet "
75  << cells.instance()/cells.local()/cells.name()
76  << endl << endl;
77  cells.write();
78 }
79 
80 
81 void getType(const labelList& elems, const label type, labelHashSet& set)
82 {
83  forAll(elems, i)
84  {
85  if (elems[i] == type)
86  {
87  set.insert(i);
88  }
89  }
90 }
91 
92 
93 void cutBySurface
94 (
95  const polyMesh& mesh,
96  const triSurfaceSearch& querySurf,
97 
98  const pointField& outsidePts,
99  const bool selectCut,
100  const bool selectInside,
101  const bool selectOutside,
102  const scalar nearDist,
103 
104  cellClassification& cellType
105 )
106 {
107  // Cut with surface and classify as inside/outside/cut
108  cellType = cellClassification(mesh, querySurf, outsidePts);
109 
110  // Get inside/outside/cutCells cellSets.
111  cellSet inside(mesh, "inside", mesh.nCells()/10);
112  getType(cellType, cellClassification::INSIDE, inside);
113  writeSet(inside, "inside cells");
114 
115  cellSet outside(mesh, "outside", mesh.nCells()/10);
116  getType(cellType, cellClassification::OUTSIDE, outside);
117  writeSet(outside, "outside cells");
118 
119  cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
120  getType(cellType, cellClassification::CUT, cutCells);
121  writeSet(cutCells, "cells cut by surface");
122 
123 
124  // Change cellType to reflect selected part of mesh. Use
125  // MESH to denote selected part, NONMESH for all
126  // other cells.
127  // Is a bit of a hack but allows us to reuse all the functionality
128  // in cellClassification.
129 
130  forAll(cellType, celli)
131  {
132  label cType = cellType[celli];
133 
134  if (cType == cellClassification::CUT)
135  {
136  if (selectCut)
137  {
138  cellType[celli] = MESH;
139  }
140  else
141  {
142  cellType[celli] = NONMESH;
143  }
144  }
145  else if (cType == cellClassification::INSIDE)
146  {
147  if (selectInside)
148  {
149  cellType[celli] = MESH;
150  }
151  else
152  {
153  cellType[celli] = NONMESH;
154  }
155  }
156  else if (cType == cellClassification::OUTSIDE)
157  {
158  if (selectOutside)
159  {
160  cellType[celli] = MESH;
161  }
162  else
163  {
164  cellType[celli] = NONMESH;
165  }
166  }
167  else
168  {
170  << "Multiple mesh regions in original mesh" << endl
171  << "Please use splitMeshRegions to separate these"
172  << exit(FatalError);
173  }
174  }
175 
176 
177  if (nearDist > 0)
178  {
179  Info<< "Removing cells with points closer than " << nearDist
180  << " to the surface ..." << nl << endl;
181 
182  const pointField& pts = mesh.points();
183  const indexedOctree<treeDataTriSurface>& tree = querySurf.tree();
184 
185  label nRemoved = 0;
186 
187  forAll(pts, pointi)
188  {
189  const point& pt = pts[pointi];
190 
191  pointIndexHit hitInfo = tree.findNearest(pt, sqr(nearDist));
192 
193  if (hitInfo.hit())
194  {
195  const labelList& pCells = mesh.pointCells()[pointi];
196 
197  forAll(pCells, i)
198  {
199  if (cellType[pCells[i]] != NONMESH)
200  {
201  cellType[pCells[i]] = NONMESH;
202  nRemoved++;
203  }
204  }
205  }
206  }
207 
208 // tmp<pointField> tnearest = querySurf.calcNearest(pts);
209 // const pointField& nearest = tnearest();
210 //
211 // label nRemoved = 0;
212 //
213 // forAll(nearest, pointi)
214 // {
215 // if (mag(nearest[pointi] - pts[pointi]) < nearDist)
216 // {
217 // const labelList& pCells = mesh.pointCells()[pointi];
218 //
219 // forAll(pCells, i)
220 // {
221 // if (cellType[pCells[i]] != NONMESH)
222 // {
223 // cellType[pCells[i]] = NONMESH;
224 // nRemoved++;
225 // }
226 // }
227 // }
228 // }
229 
230  Info<< "Removed " << nRemoved << " cells since too close to surface"
231  << nl << endl;
232  }
233 }
234 
235 
236 
237 // We're meshing the outside. Subset the currently selected mesh cells with the
238 // ones reachable from the outsidepoints.
239 label selectOutsideCells
240 (
241  const polyMesh& mesh,
242  const pointField& outsidePts,
243  cellClassification& cellType
244 )
245 {
246  //
247  // Check all outsidePts and for all of them inside a mesh cell
248  // collect the faces to start walking from
249  //
250 
251  // Outside faces
252  labelHashSet outsideFacesMap(outsidePts.size() * 6 * 2);
253  DynamicList<label> outsideFaces(outsideFacesMap.size());
254  // CellInfo on outside faces
255  DynamicList<cellInfo> outsideFacesInfo(outsideFacesMap.size());
256 
257  // cellInfo for mesh cell
258  const cellInfo meshInfo(MESH);
259 
260  forAll(outsidePts, outsidePtI)
261  {
262  // Find cell containing point. Linear search.
263  label celli = meshSearch::findCellNoTree(mesh, outsidePts[outsidePtI]);
264 
265  if (celli != -1 && cellType[celli] == MESH)
266  {
267  Info<< "Marking cell " << celli << " containing outside point "
268  << outsidePts[outsidePtI] << " with type " << cellType[celli]
269  << " ..." << endl;
270 
271  //
272  // Mark this cell and its faces to start walking from
273  //
274 
275  // Mark faces of celli
276  const labelList& cFaces = mesh.cells()[celli];
277  forAll(cFaces, i)
278  {
279  label facei = cFaces[i];
280 
281  if (outsideFacesMap.insert(facei))
282  {
283  outsideFaces.append(facei);
284  outsideFacesInfo.append(meshInfo);
285  }
286  }
287  }
288  }
289 
290  // Floodfill starting from outsideFaces (of type meshInfo)
291  List<cellInfo> faceInfoList(mesh.nFaces()), cellInfoList(mesh.nCells());
292  FaceCellWave<cellInfo> regionCalc
293  (
294  mesh,
295  outsideFaces.shrink(),
296  outsideFacesInfo.shrink(),
297  faceInfoList,
298  cellInfoList,
299  mesh.globalData().nTotalCells() + 1 // max iterations
300  );
301 
302  // Now cellInfoList should hold info on cells that are reachable from
303  // changedFaces. Use these to subset cellType
304  label nChanged = 0;
305  forAll(cellInfoList, celli)
306  {
307  if (cellType[celli] == MESH)
308  {
309  // Original cell was selected for meshing. Check if cell was
310  // reached from outsidePoints
311  if (cellInfoList[celli].type() != MESH)
312  {
313  cellType[celli] = NONMESH;
314  nChanged++;
315  }
316  }
317  }
318 
319  return nChanged;
320 }
321 
322 
323 
324 int main(int argc, char *argv[])
325 {
327 
328  #include "setRootCase.H"
329  #include "createTime.H"
330  #include "createPolyMesh.H"
331 
332  // Mesh edge statistics calculator
333  edgeStats edgeCalc(mesh);
334 
335 
336  IOdictionary refineDict
337  (
338  IOobject
339  (
340  "selectCellsDict",
341  runTime.system(),
342  mesh,
345  )
346  );
347 
348  fileName surfName(refineDict.lookup("surface"));
349  pointField outsidePts(refineDict.lookup("outsidePoints"));
350  bool useSurface(readBool(refineDict.lookup("useSurface")));
351  bool selectCut(readBool(refineDict.lookup("selectCut")));
352  bool selectInside(readBool(refineDict.lookup("selectInside")));
353  bool selectOutside(readBool(refineDict.lookup("selectOutside")));
354  scalar nearDist(refineDict.lookup<scalar>("nearDistance"));
355 
356 
357  if (useSurface)
358  {
359  Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
360  << " cells cut by surface : " << selectCut << nl
361  << " cells inside of surface : " << selectInside << nl
362  << " cells outside of surface : " << selectOutside << nl
363  << " cells with points further than : " << nearDist << nl
364  << endl;
365  }
366  else
367  {
368  Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
369  << " cells reachable from outsidePoints:" << selectOutside << nl
370  << endl;
371  }
372 
373  // Print edge stats on original mesh.
374  (void)edgeCalc.minLen(Info);
375 
376  // Check all 'outside' points
377  forAll(outsidePts, outsideI)
378  {
379  const point& outsidePoint = outsidePts[outsideI];
380 
381  label celli = meshSearch::findCellNoTree(mesh, outsidePoint);
382 
383  if (returnReduce(celli, maxOp<label>()) == -1)
384  {
386  << "outsidePoint " << outsidePoint
387  << " is not inside any cell"
388  << exit(FatalError);
389  }
390  }
391 
392  // Cell status (compared to surface if provided): inside/outside/cut.
393  // Start off from everything selected and cut later.
394  cellClassification cellType
395  (
396  mesh,
397  labelList
398  (
399  mesh.nCells(),
401  )
402  );
403 
404 
405  // Surface
406  autoPtr<triSurface> surf(nullptr);
407  // Search engine on surface.
408  autoPtr<triSurfaceSearch> querySurf(nullptr);
409 
410  if (useSurface)
411  {
412  surf.reset(new triSurface(surfName));
413 
414  // Dump some stats
415  surf().writeStats(Info);
416 
417  // Search engine on surface.
418  querySurf.reset(new triSurfaceSearch(surf));
419 
420  // Set cellType[celli] according to relation to surface
421  cutBySurface
422  (
423  mesh,
424  querySurf,
425 
426  outsidePts,
427  selectCut,
428  selectInside,
429  selectOutside,
430  nearDist,
431 
432  cellType
433  );
434  }
435 
436 
437  // Now 'trim' all the corners from the mesh so meshing/surface extraction
438  // becomes easier.
439 
440  label nHanging, nRegionEdges, nRegionPoints, nOutside;
441 
442  do
443  {
444  Info<< "Removing cells which after subsetting would have all points"
445  << " on outside ..." << nl << endl;
446 
447  nHanging = cellType.fillHangingCells
448  (
449  MESH, // meshType
450  NONMESH, // fill type
451  mesh.nCells()
452  );
453 
454 
455  Info<< "Removing edges connecting cells unconnected by faces ..."
456  << nl << endl;
457 
458  nRegionEdges = cellType.fillRegionEdges
459  (
460  MESH, // meshType
461  NONMESH, // fill type
462  mesh.nCells()
463  );
464 
465 
466  Info<< "Removing points connecting cells unconnected by faces ..."
467  << nl << endl;
468 
469  nRegionPoints = cellType.fillRegionPoints
470  (
471  MESH, // meshType
472  NONMESH, // fill type
473  mesh.nCells()
474  );
475 
476  nOutside = 0;
477  if (selectOutside)
478  {
479  // Since we're selecting the cells reachable from outsidePoints
480  // and the set might have changed, redo the outsideCells
481  // calculation
482  nOutside = selectOutsideCells(mesh, outsidePts, cellType);
483  }
484  } while
485  (
486  nHanging != 0
487  || nRegionEdges != 0
488  || nRegionPoints != 0
489  || nOutside != 0
490  );
491 
492  cellSet selectedCells(mesh, "selected", mesh.nCells()/10);
493  getType(cellType, MESH, selectedCells);
494 
495  writeSet(selectedCells, "cells selected for meshing");
496 
497 
498  Info<< "End\n" << endl;
499 
500  return 0;
501 }
502 
503 
504 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
Wave propagation of information through grid. Every iteration information goes through one layer of c...
Definition: FaceCellWave.H:79
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
void shrink()
Shrink the allocated table to approx. twice number of elements.
Definition: HashTable.C:574
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:57
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
@ MUST_READ_IF_MODIFIED
Definition: IOobject.H:119
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
This class describes the interaction of (usually) a face and a point. It carries the info of a succes...
Definition: PointIndexHit.H:54
bool hit() const
Is there a hit.
static void noParallel()
Remove the parallel options.
Definition: argList.C:168
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: autoPtr.H:51
'Cuts' a mesh with a surface.
label fillRegionPoints(const label meshType, const label fillType, const label maxIter)
Find regionPoints and fill all neighbours. Iterate until nothing.
label fillHangingCells(const label meshType, const label fillType, const label maxIter)
Find hanging cells (cells with all points on outside) and set their.
label fillRegionEdges(const label meshType, const label fillType, const label maxIter)
Find regionEdges and fill one neighbour. Iterate until nothing.
Holds information regarding type of cell. Used in inside/outside determination in cellClassification.
Definition: cellInfo.H:67
A collection of cell labels.
Definition: cellSet.H:51
Helper class to calculate minimum edge length on mesh.
Definition: edgeStats.H:55
A class for handling file names.
Definition: fileName.H:82
label nTotalCells() const
Return total number of cells in decomposed mesh.
Non-pointer based hierarchical recursive searching.
Definition: indexedOctree.H:72
static label findCellNoTree(const polyMesh &mesh, const point &p, const pointInCellShapes=pointInCellShapes::tets)
Find the cell containing the given point. Do a.
Definition: meshSearch.C:183
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1471
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
const labelListList & pointCells() const
label nCells() const
const cellList & cells() const
label nFaces() const
Helper class to search on triSurface.
const indexedOctree< treeDataTriSurface > & tree() const
Demand driven construction of the octree.
Triangulated surface description with patch information.
Definition: triSurface.H:68
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
int main(int argc, char *argv[])
Definition: financialFoam.C:44
const cellShapeList & cells
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
bool readBool(Istream &)
Definition: boolIO.C:63
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:288
messageStream Info
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
error FatalError
static const char nl
Definition: Ostream.H:297
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488