1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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.
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
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/>.
24 \*---------------------------------------------------------------------------*/
26 #include "shellSurfaces.H"
27 #include "searchableSurface.H"
29 #include "triSurfaceMesh.H"
30 #include "refinementSurfaces.H"
31 #include "searchableSurfaces.H"
32 #include "orientedSurface.H"
33 #include "pointIndexHit.H"
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
43 NamedEnum<shellSurfaces::refineMode, 3>::
51 const NamedEnum<shellSurfaces::refineMode, 3> shellSurfaces::refineModeNames_;
53 } // End namespace Foam
57 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59 void Foam::shellSurfaces::setAndCheckLevels
62 const List<Tuple2<scalar, label> >& distLevels
65 if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
69 "shellSurfaces::shellSurfaces"
70 "(const searchableSurfaces&, const dictionary&)"
71 ) << "For refinement mode "
72 << refineModeNames_[modes_[shellI]]
73 << " specify only one distance+level."
74 << " (its distance gets discarded)"
77 // Extract information into separate distance and level
78 distances_[shellI].setSize(distLevels.size());
79 levels_[shellI].setSize(distLevels.size());
83 distances_[shellI][j] = distLevels[j].first();
84 levels_[shellI][j] = distLevels[j].second();
86 // Check in incremental order
91 (distances_[shellI][j] <= distances_[shellI][j-1])
92 || (levels_[shellI][j] > levels_[shellI][j-1])
97 "shellSurfaces::shellSurfaces"
98 "(const searchableSurfaces&, const dictionary&)"
99 ) << "For refinement mode "
100 << refineModeNames_[modes_[shellI]]
101 << " : Refinement should be specified in order"
102 << " of increasing distance"
103 << " (and decreasing refinement level)." << endl
104 << "Distance:" << distances_[shellI][j]
105 << " refinementLevel:" << levels_[shellI][j]
111 const searchableSurface& shell = allGeometry_[shells_[shellI]];
113 if (modes_[shellI] == DISTANCE)
115 Info<< "Refinement level according to distance to "
116 << shell.name() << endl;
117 forAll(levels_[shellI], j)
119 Info<< " level " << levels_[shellI][j]
120 << " for all cells within " << distances_[shellI][j]
121 << " meter." << endl;
126 if (!allGeometry_[shells_[shellI]].hasVolumeType())
130 "shellSurfaces::shellSurfaces"
131 "(const searchableSurfaces&"
132 ", const PtrList<dictionary>&)"
133 ) << "Shell " << shell.name()
134 << " does not support testing for "
135 << refineModeNames_[modes_[shellI]] << endl
136 << "Probably it is not closed."
140 if (modes_[shellI] == INSIDE)
142 Info<< "Refinement level " << levels_[shellI][0]
143 << " for all cells inside " << shell.name() << endl;
147 Info<< "Refinement level " << levels_[shellI][0]
148 << " for all cells outside " << shell.name() << endl;
154 // Specifically orient triSurfaces using a calculated point outside.
155 // Done since quite often triSurfaces not of consistent orientation which
156 // is (currently) necessary for sideness calculation
157 void Foam::shellSurfaces::orient()
159 // Determine outside point.
160 boundBox overallBb = boundBox::invertedBox;
162 bool hasSurface = false;
164 forAll(shells_, shellI)
166 const searchableSurface& s = allGeometry_[shells_[shellI]];
168 if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
170 const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
172 if (shell.triSurface::size())
174 const pointField& points = shell.points();
178 boundBox shellBb(points[0], points[0]);
179 // Assume surface is compact!
182 const point& pt = points[i];
183 shellBb.min() = min(shellBb.min(), pt);
184 shellBb.max() = max(shellBb.max(), pt);
187 overallBb.min() = min(overallBb.min(), shellBb.min());
188 overallBb.max() = max(overallBb.max(), shellBb.max());
195 const point outsidePt = overallBb.max() + overallBb.span();
197 //Info<< "Using point " << outsidePt << " to orient shells" << endl;
199 forAll(shells_, shellI)
201 const searchableSurface& s = allGeometry_[shells_[shellI]];
203 if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
205 triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
207 refCast<const triSurfaceMesh>(s)
210 // Flip surface so outsidePt is outside.
211 bool anyFlipped = orientedSurface::orient
220 // orientedSurface will have done a clearOut of the surface.
221 // we could do a clearout of the triSurfaceMeshes::trees()
222 // but these aren't affected by orientation
223 // (except for cached
224 // sideness which should not be set at this point.
227 Info<< "shellSurfaces : Flipped orientation of surface "
229 << " so point " << outsidePt << " is outside." << endl;
237 // Find maximum level of a shell.
238 void Foam::shellSurfaces::findHigherLevel
240 const pointField& pt,
245 const labelList& levels = levels_[shellI];
247 if (modes_[shellI] == DISTANCE)
251 const scalarField& distances = distances_[shellI];
253 // Collect all those points that have a current maxLevel less than
254 // (any of) the shell. Also collect the furthest distance allowable
255 // to any shell with a higher level.
257 pointField candidates(pt.size());
258 labelList candidateMap(pt.size());
259 scalarField candidateDistSqr(pt.size());
260 label candidateI = 0;
262 forAll(maxLevel, pointI)
264 forAllReverse(levels, levelI)
266 if (levels[levelI] > maxLevel[pointI])
268 candidates[candidateI] = pt[pointI];
269 candidateMap[candidateI] = pointI;
270 candidateDistSqr[candidateI] = sqr(distances[levelI]);
276 candidates.setSize(candidateI);
277 candidateMap.setSize(candidateI);
278 candidateDistSqr.setSize(candidateI);
280 // Do the expensive nearest test only for the candidate points.
281 List<pointIndexHit> nearInfo;
282 allGeometry_[shells_[shellI]].findNearest
290 forAll(nearInfo, candidateI)
292 if (nearInfo[candidateI].hit())
294 // Check which level it actually is in.
295 label minDistI = findLower
298 mag(nearInfo[candidateI].hitPoint()-candidates[candidateI])
301 label pointI = candidateMap[candidateI];
303 // pt is inbetween shell[minDistI] and shell[minDistI+1]
304 maxLevel[pointI] = levels[minDistI+1];
310 // Inside/outside mode
312 // Collect all those points that have a current maxLevel less than the
315 pointField candidates(pt.size());
316 labelList candidateMap(pt.size());
317 label candidateI = 0;
319 forAll(maxLevel, pointI)
321 if (levels[0] > maxLevel[pointI])
323 candidates[candidateI] = pt[pointI];
324 candidateMap[candidateI] = pointI;
328 candidates.setSize(candidateI);
329 candidateMap.setSize(candidateI);
331 // Do the expensive nearest test only for the candidate points.
332 List<searchableSurface::volumeType> volType;
333 allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
337 label pointI = candidateMap[i];
342 modes_[shellI] == INSIDE
343 && volType[i] == searchableSurface::INSIDE
346 modes_[shellI] == OUTSIDE
347 && volType[i] == searchableSurface::OUTSIDE
351 maxLevel[pointI] = levels[0];
358 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
360 Foam::shellSurfaces::shellSurfaces
362 const searchableSurfaces& allGeometry,
363 const PtrList<dictionary>& shellDicts
366 allGeometry_(allGeometry)
368 shells_.setSize(shellDicts.size());
369 modes_.setSize(shellDicts.size());
370 distances_.setSize(shellDicts.size());
371 levels_.setSize(shellDicts.size());
373 forAll(shellDicts, shellI)
375 const dictionary& dict = shellDicts[shellI];
376 const word name = dict.lookup("name");
377 const word type = dict.lookup("type");
379 shells_[shellI] = allGeometry_.findSurfaceID(name);
381 if (shells_[shellI] == -1)
385 "shellSurfaces::shellSurfaces"
386 "(const searchableSurfaces&, const PtrList<dictionary>&)"
387 ) << "No surface called " << name << endl
388 << "Valid surfaces are " << allGeometry_.names()
392 modes_[shellI] = refineModeNames_.read(dict.lookup("refineMode"));
394 // Read pairs of distance+level
395 setAndCheckLevels(shellI, dict.lookup("levels"));
398 // Orient shell surfaces before any searching is done. Note that this
399 // only needs to be done for inside or outside. Orienting surfaces
400 // constructs lots of addressing which we want to avoid.
405 Foam::shellSurfaces::shellSurfaces
407 const searchableSurfaces& allGeometry,
408 const dictionary& shellsDict
411 allGeometry_(allGeometry)
413 shells_.setSize(shellsDict.size());
414 modes_.setSize(shellsDict.size());
415 distances_.setSize(shellsDict.size());
416 levels_.setSize(shellsDict.size());
419 forAllConstIter(dictionary, shellsDict, iter)
421 shells_[shellI] = allGeometry_.findSurfaceID(iter().keyword());
423 if (shells_[shellI] == -1)
427 "shellSurfaces::shellSurfaces"
428 "(const searchableSurfaces&, const dictionary>&"
429 ) << "No surface called " << iter().keyword() << endl
430 << "Valid surfaces are " << allGeometry_.names()
433 const dictionary& dict = shellsDict.subDict(iter().keyword());
435 modes_[shellI] = refineModeNames_.read(dict.lookup("mode"));
437 // Read pairs of distance+level
438 setAndCheckLevels(shellI, dict.lookup("levels"));
443 // Orient shell surfaces before any searching is done. Note that this
444 // only needs to be done for inside or outside. Orienting surfaces
445 // constructs lots of addressing which we want to avoid.
450 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
452 // Highest shell level
453 Foam::label Foam::shellSurfaces::maxLevel() const
455 label overallMax = 0;
456 forAll(levels_, shellI)
458 overallMax = max(overallMax, max(levels_[shellI]));
464 void Foam::shellSurfaces::findHigherLevel
466 const pointField& pt,
467 const labelList& ptLevel,
471 // Maximum level of any shell. Start off with level of point.
474 forAll(shells_, shellI)
476 findHigherLevel(pt, shellI, maxLevel);
481 // ************************************************************************* //