shellSurfaces.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-2018 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 \*---------------------------------------------------------------------------*/
25 
26 #include "shellSurfaces.H"
27 #include "searchableSurface.H"
28 #include "boundBox.H"
29 #include "triSurfaceMesh.H"
30 #include "refinementSurfaces.H"
31 #include "searchableSurfaces.H"
32 #include "orientedSurface.H"
33 #include "pointIndexHit.H"
34 #include "volumeType.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 
39 namespace Foam
40 {
41 
42 template<>
43 const char*
44 NamedEnum<shellSurfaces::refineMode, 3>::
45 names[] =
46 {
47  "inside",
48  "outside",
49  "distance"
50 };
51 
52 const NamedEnum<shellSurfaces::refineMode, 3> shellSurfaces::refineModeNames_;
53 
54 } // End namespace Foam
55 
56 
57 
58 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59 
60 void Foam::shellSurfaces::setAndCheckLevels
61 (
62  const label shellI,
63  const List<Tuple2<scalar, label>>& distLevels
64 )
65 {
66  if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
67  {
69  << "For refinement mode "
70  << refineModeNames_[modes_[shellI]]
71  << " specify only one distance+level."
72  << " (its distance gets discarded)"
73  << exit(FatalError);
74  }
75  // Extract information into separate distance and level
76  distances_[shellI].setSize(distLevels.size());
77  levels_[shellI].setSize(distLevels.size());
78 
79  forAll(distLevels, j)
80  {
81  distances_[shellI][j] = distLevels[j].first();
82  levels_[shellI][j] = distLevels[j].second();
83 
84  // Check in incremental order
85  if (j > 0)
86  {
87  if
88  (
89  (distances_[shellI][j] <= distances_[shellI][j-1])
90  || (levels_[shellI][j] > levels_[shellI][j-1])
91  )
92  {
94  << "For refinement mode "
95  << refineModeNames_[modes_[shellI]]
96  << " : Refinement should be specified in order"
97  << " of increasing distance"
98  << " (and decreasing refinement level)." << endl
99  << "Distance:" << distances_[shellI][j]
100  << " refinementLevel:" << levels_[shellI][j]
101  << exit(FatalError);
102  }
103  }
104  }
105 
106  const searchableSurface& shell = allGeometry_[shells_[shellI]];
107 
108  if (modes_[shellI] == DISTANCE)
109  {
110  Info<< "Refinement level according to distance to "
111  << shell.name() << endl;
112  forAll(levels_[shellI], j)
113  {
114  Info<< " level " << levels_[shellI][j]
115  << " for all cells within " << distances_[shellI][j]
116  << " metre." << endl;
117  }
118  }
119  else
120  {
121  if (!allGeometry_[shells_[shellI]].hasVolumeType())
122  {
124  << "Shell " << shell.name()
125  << " does not support testing for "
126  << refineModeNames_[modes_[shellI]] << endl
127  << "Probably it is not closed."
128  << exit(FatalError);
129  }
130 
131  if (modes_[shellI] == INSIDE)
132  {
133  Info<< "Refinement level " << levels_[shellI][0]
134  << " for all cells inside " << shell.name() << endl;
135  }
136  else
137  {
138  Info<< "Refinement level " << levels_[shellI][0]
139  << " for all cells outside " << shell.name() << endl;
140  }
141  }
142 }
143 
144 
145 // Specifically orient triSurfaces using a calculated point outside.
146 // Done since quite often triSurfaces not of consistent orientation which
147 // is (currently) necessary for sideness calculation
148 void Foam::shellSurfaces::orient()
149 {
150  // Determine outside point.
151  boundBox overallBb = boundBox::invertedBox;
152 
153  bool hasSurface = false;
154 
155  forAll(shells_, shellI)
156  {
157  const searchableSurface& s = allGeometry_[shells_[shellI]];
158 
159  if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
160  {
161  const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
162 
163  if (shell.triSurface::size())
164  {
165  const pointField& points = shell.points();
166 
167  hasSurface = true;
168 
169  boundBox shellBb(points[0], points[0]);
170  // Assume surface is compact!
171  forAll(points, i)
172  {
173  const point& pt = points[i];
174  shellBb.min() = min(shellBb.min(), pt);
175  shellBb.max() = max(shellBb.max(), pt);
176  }
177 
178  overallBb.min() = min(overallBb.min(), shellBb.min());
179  overallBb.max() = max(overallBb.max(), shellBb.max());
180  }
181  }
182  }
183 
184  if (hasSurface)
185  {
186  const point outsidePt = overallBb.max() + overallBb.span();
187 
188  // Info<< "Using point " << outsidePt << " to orient shells" << endl;
189 
190  forAll(shells_, shellI)
191  {
192  const searchableSurface& s = allGeometry_[shells_[shellI]];
193 
194  if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
195  {
196  triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
197  (
198  refCast<const triSurfaceMesh>(s)
199  );
200 
201  // Flip surface so outsidePt is outside.
202  bool anyFlipped = orientedSurface::orient
203  (
204  shell,
205  outsidePt,
206  true
207  );
208 
209  if (anyFlipped)
210  {
211  // orientedSurface will have done a clearOut of the surface.
212  // we could do a clearout of the triSurfaceMeshes::trees()
213  // but these aren't affected by orientation
214  // (except for cached
215  // sideness which should not be set at this point.
216  // !!Should check!)
217 
218  Info<< "shellSurfaces : Flipped orientation of surface "
219  << s.name()
220  << " so point " << outsidePt << " is outside." << endl;
221  }
222  }
223  }
224  }
225 }
226 
227 
228 // Find maximum level of a shell.
229 void Foam::shellSurfaces::findHigherLevel
230 (
231  const pointField& pt,
232  const label shellI,
233  labelList& maxLevel
234 ) const
235 {
236  const labelList& levels = levels_[shellI];
237 
238  if (modes_[shellI] == DISTANCE)
239  {
240  // Distance mode.
241 
242  const scalarField& distances = distances_[shellI];
243 
244  // Collect all those points that have a current maxLevel less than
245  // (any of) the shell. Also collect the furthest distance allowable
246  // to any shell with a higher level.
247 
248  pointField candidates(pt.size());
249  labelList candidateMap(pt.size());
250  scalarField candidateDistSqr(pt.size());
251  label candidateI = 0;
252 
253  forAll(maxLevel, pointi)
254  {
255  forAllReverse(levels, levelI)
256  {
257  if (levels[levelI] > maxLevel[pointi])
258  {
259  candidates[candidateI] = pt[pointi];
260  candidateMap[candidateI] = pointi;
261  candidateDistSqr[candidateI] = sqr(distances[levelI]);
262  candidateI++;
263  break;
264  }
265  }
266  }
267  candidates.setSize(candidateI);
268  candidateMap.setSize(candidateI);
269  candidateDistSqr.setSize(candidateI);
270 
271  // Do the expensive nearest test only for the candidate points.
272  List<pointIndexHit> nearInfo;
273  allGeometry_[shells_[shellI]].findNearest
274  (
275  candidates,
276  candidateDistSqr,
277  nearInfo
278  );
279 
280  // Update maxLevel
281  forAll(nearInfo, candidateI)
282  {
283  if (nearInfo[candidateI].hit())
284  {
285  // Check which level it actually is in.
286  label minDistI = findLower
287  (
288  distances,
289  mag(nearInfo[candidateI].hitPoint()-candidates[candidateI])
290  );
291 
292  label pointi = candidateMap[candidateI];
293 
294  // pt is in between shell[minDistI] and shell[minDistI+1]
295  maxLevel[pointi] = levels[minDistI+1];
296  }
297  }
298  }
299  else
300  {
301  // Inside/outside mode
302 
303  // Collect all those points that have a current maxLevel less than the
304  // shell.
305 
306  pointField candidates(pt.size());
307  labelList candidateMap(pt.size());
308  label candidateI = 0;
309 
310  forAll(maxLevel, pointi)
311  {
312  if (levels[0] > maxLevel[pointi])
313  {
314  candidates[candidateI] = pt[pointi];
315  candidateMap[candidateI] = pointi;
316  candidateI++;
317  }
318  }
319  candidates.setSize(candidateI);
320  candidateMap.setSize(candidateI);
321 
322  // Do the expensive nearest test only for the candidate points.
323  List<volumeType> volType;
324  allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
325 
326  forAll(volType, i)
327  {
328  label pointi = candidateMap[i];
329 
330  if
331  (
332  (
333  modes_[shellI] == INSIDE
334  && volType[i] == volumeType::inside
335  )
336  || (
337  modes_[shellI] == OUTSIDE
338  && volType[i] == volumeType::outside
339  )
340  )
341  {
342  maxLevel[pointi] = levels[0];
343  }
344  }
345  }
346 }
347 
348 
349 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
350 
352 (
353  const searchableSurfaces& allGeometry,
354  const dictionary& shellsDict
355 )
356 :
357  allGeometry_(allGeometry)
358 {
359  // Wildcard specification : loop over all surfaces and try to find a match.
360 
361  // Count number of shells.
362  label shellI = 0;
363  forAll(allGeometry.names(), geomI)
364  {
365  const word& geomName = allGeometry_.names()[geomI];
366 
367  if (shellsDict.found(geomName))
368  {
369  shellI++;
370  }
371  }
372 
373 
374  // Size lists
375  shells_.setSize(shellI);
376  modes_.setSize(shellI);
377  distances_.setSize(shellI);
378  levels_.setSize(shellI);
379 
380  HashSet<word> unmatchedKeys(shellsDict.toc());
381  shellI = 0;
382 
383  forAll(allGeometry_.names(), geomI)
384  {
385  const word& geomName = allGeometry_.names()[geomI];
386 
387  const entry* ePtr = shellsDict.lookupEntryPtr(geomName, false, true);
388 
389  if (ePtr)
390  {
391  const dictionary& dict = ePtr->dict();
392  unmatchedKeys.erase(ePtr->keyword());
393 
394  shells_[shellI] = geomI;
395  modes_[shellI] = refineModeNames_.read(dict.lookup("mode"));
396 
397  // Read pairs of distance+level
398  setAndCheckLevels(shellI, dict.lookup("levels"));
399 
400  shellI++;
401  }
402  }
403 
404  if (unmatchedKeys.size() > 0)
405  {
407  (
408  shellsDict
409  ) << "Not all entries in refinementRegions dictionary were used."
410  << " The following entries were not used : "
411  << unmatchedKeys.sortedToc()
412  << endl;
413  }
414 
415  // Orient shell surfaces before any searching is done. Note that this
416  // only needs to be done for inside or outside. Orienting surfaces
417  // constructs lots of addressing which we want to avoid.
418  orient();
419 }
420 
421 
422 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
423 
424 // Highest shell level
426 {
427  label overallMax = 0;
428  forAll(levels_, shellI)
429  {
430  overallMax = max(overallMax, max(levels_[shellI]));
431  }
432  return overallMax;
433 }
434 
435 
436 void Foam::shellSurfaces::findHigherLevel
437 (
438  const pointField& pt,
439  const labelList& ptLevel,
440  labelList& maxLevel
441 ) const
442 {
443  // Maximum level of any shell. Start off with level of point.
444  maxLevel = ptLevel;
445 
446  forAll(shells_, shellI)
447  {
448  findHigherLevel(pt, shellI, maxLevel);
449  }
450 }
451 
452 
453 // ************************************************************************* //
shellSurfaces(const searchableSurfaces &allGeometry, const dictionary &shellsDict)
Construct from geometry and dictionary.
A HashTable with keys but without contents.
Definition: HashSet.H:59
dictionary dict
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:438
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
const word & name() const
Return name.
Definition: IOobject.H:295
const entry * lookupEntryPtr(const word &, bool recursive, bool patternMatch) const
Find and return an entry data stream pointer if present.
Definition: dictionary.C:477
const keyType & keyword() const
Return keyword.
Definition: entry.H:123
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
A 2-tuple for storing two objects of different types.
Definition: HashTable.H:65
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
virtual tmp< pointField > points() const
Get the points that define the surface.
dimensionedSymmTensor sqr(const dimensionedVector &dv)
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
static bool orient(triSurface &, const point &, const bool orientOutside)
Flip faces such that normals are consistent with point:
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:446
virtual const dictionary & dict() const =0
Return dictionary if this entry is a dictionary.
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:58
label maxLevel() const
Highest shell level.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:51
bool erase(T *p)
Remove the specified element from the list and delete it.
Definition: ILList.C:101
wordList toc() const
Return the table of contents.
Definition: dictionary.C:783
IOoject and searching on triSurface.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const pointField & points
A class for handling words, derived from string.
Definition: word.H:59
Container for searchableSurfaces.
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
void setSize(const label)
Reset size of List.
Definition: List.C:281
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:60
static const boundBox invertedBox
A very large inverted boundBox: min/max == +/- vGreat.
Definition: boundBox.H:82
const wordList & names() const
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:84
messageStream Info
label findLower(const ListType &, typename ListType::const_reference, const label stary, const BinaryOp &bop)
Find last element < given value in sorted list and return index,.
dimensioned< scalar > mag(const dimensioned< Type > &)
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:54
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:65
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:583