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