mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
- use keyType::option enum to consolidate searching options.
These enumeration names should be more intuitive to use
and improve code readability.
Eg, lookupEntry(key, keyType::REGEX);
vs lookupEntry(key, false, true);
or
Eg, lookupEntry(key, keyType::LITERAL_RECURSIVE);
vs lookupEntry(key, true, false);
- new findEntry(), findDict(), findScoped() methods with consolidated
search options for shorter naming and access names more closely
aligned with other components. Behave simliarly to the
methods lookupEntryPtr(), subDictPtr(), lookupScopedEntryPtr(),
respectively. Default search parameters consistent with lookupEntry().
Eg, const entry* e = dict.findEntry(key);
vs const entry* e = dict.lookupEntryPtr(key, false, true);
- added '*' and '->' dereference operators to dictionary searchers.
977 lines
27 KiB
C
977 lines
27 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
|
|
\\/ M anipulation | Copyright (C) 2015-2018 OpenCFD Ltd.
|
|
-------------------------------------------------------------------------------
|
|
License
|
|
This file is part of OpenFOAM.
|
|
|
|
OpenFOAM is free software: you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
\*---------------------------------------------------------------------------*/
|
|
|
|
#include "shellSurfaces.H"
|
|
#include "searchableSurface.H"
|
|
#include "boundBox.H"
|
|
#include "triSurfaceMesh.H"
|
|
#include "refinementSurfaces.H"
|
|
#include "searchableSurfaces.H"
|
|
#include "orientedSurface.H"
|
|
#include "pointIndexHit.H"
|
|
#include "volumeType.H"
|
|
|
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
|
|
|
const Foam::Enum
|
|
<
|
|
Foam::shellSurfaces::refineMode
|
|
>
|
|
Foam::shellSurfaces::refineModeNames_
|
|
{
|
|
{ refineMode::INSIDE, "inside" },
|
|
{ refineMode::OUTSIDE, "outside" },
|
|
{ refineMode::DISTANCE, "distance" },
|
|
};
|
|
|
|
|
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
|
|
void Foam::shellSurfaces::setAndCheckLevels
|
|
(
|
|
const label shellI,
|
|
const List<Tuple2<scalar, label>>& distLevels
|
|
)
|
|
{
|
|
const searchableSurface& shell = allGeometry_[shells_[shellI]];
|
|
|
|
if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "For refinement mode "
|
|
<< refineModeNames_[modes_[shellI]]
|
|
<< " specify only one distance+level."
|
|
<< " (its distance gets discarded)"
|
|
<< exit(FatalError);
|
|
}
|
|
// Extract information into separate distance and level
|
|
distances_[shellI].setSize(distLevels.size());
|
|
levels_[shellI].setSize(distLevels.size());
|
|
|
|
forAll(distLevels, j)
|
|
{
|
|
distances_[shellI][j] = distLevels[j].first();
|
|
levels_[shellI][j] = distLevels[j].second();
|
|
|
|
if (levels_[shellI][j] < -1)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Shell " << shell.name()
|
|
<< " has illegal refinement level "
|
|
<< levels_[shellI][j]
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
|
|
// Check in incremental order
|
|
if (j > 0)
|
|
{
|
|
if
|
|
(
|
|
(distances_[shellI][j] <= distances_[shellI][j-1])
|
|
|| (levels_[shellI][j] > levels_[shellI][j-1])
|
|
)
|
|
{
|
|
FatalErrorInFunction
|
|
<< "For refinement mode "
|
|
<< refineModeNames_[modes_[shellI]]
|
|
<< " : Refinement should be specified in order"
|
|
<< " of increasing distance"
|
|
<< " (and decreasing refinement level)." << endl
|
|
<< "Distance:" << distances_[shellI][j]
|
|
<< " refinementLevel:" << levels_[shellI][j]
|
|
<< exit(FatalError);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (modes_[shellI] == DISTANCE)
|
|
{
|
|
Info<< "Refinement level according to distance to "
|
|
<< shell.name() << endl;
|
|
forAll(levels_[shellI], j)
|
|
{
|
|
Info<< " level " << levels_[shellI][j]
|
|
<< " for all cells within " << distances_[shellI][j]
|
|
<< " metre." << endl;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!shell.hasVolumeType())
|
|
{
|
|
FatalErrorInFunction
|
|
<< "Shell " << shell.name()
|
|
<< " does not support testing for "
|
|
<< refineModeNames_[modes_[shellI]] << endl
|
|
<< "Probably it is not closed."
|
|
<< exit(FatalError);
|
|
}
|
|
|
|
if (modes_[shellI] == INSIDE)
|
|
{
|
|
Info<< "Refinement level " << levels_[shellI][0]
|
|
<< " for all cells inside " << shell.name() << endl;
|
|
}
|
|
else
|
|
{
|
|
Info<< "Refinement level " << levels_[shellI][0]
|
|
<< " for all cells outside " << shell.name() << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::checkGapLevels
|
|
(
|
|
const dictionary& shellDict,
|
|
const label shellI,
|
|
const List<FixedList<label, 3>>& levels
|
|
)
|
|
{
|
|
const searchableSurface& shell = allGeometry_[shells_[shellI]];
|
|
|
|
forAll(levels, regionI)
|
|
{
|
|
const FixedList<label, 3>& info = levels[regionI];
|
|
|
|
if (info[2] > 0)
|
|
{
|
|
if (modes_[shellI] == DISTANCE)
|
|
{
|
|
FatalIOErrorInFunction(shellDict)
|
|
<< "'gapLevel' specification cannot be used with mode "
|
|
<< refineModeNames_[DISTANCE]
|
|
<< " for shell " << shell.name()
|
|
<< exit(FatalIOError);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Hardcode for region 0
|
|
if (levels[0][0] > 0)
|
|
{
|
|
Info<< "Refinement level up to " << levels[0][2]
|
|
<< " for all cells in gaps for shell "
|
|
<< shell.name() << endl;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Specifically orient triSurfaces using a calculated point outside.
|
|
// Done since quite often triSurfaces not of consistent orientation which
|
|
// is (currently) necessary for sideness calculation
|
|
void Foam::shellSurfaces::orient()
|
|
{
|
|
// Determine outside point.
|
|
boundBox overallBb = boundBox::invertedBox;
|
|
|
|
bool hasSurface = false;
|
|
|
|
forAll(shells_, shellI)
|
|
{
|
|
const searchableSurface& s = allGeometry_[shells_[shellI]];
|
|
|
|
if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
|
|
{
|
|
const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
|
|
|
|
if (shell.triSurface::size())
|
|
{
|
|
hasSurface = true;
|
|
// Assume surface is compact!
|
|
overallBb.add(shell.points());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hasSurface)
|
|
{
|
|
const point outsidePt = overallBb.max() + overallBb.span();
|
|
|
|
//Info<< "Using point " << outsidePt << " to orient shells" << endl;
|
|
|
|
forAll(shells_, shellI)
|
|
{
|
|
const searchableSurface& s = allGeometry_[shells_[shellI]];
|
|
|
|
if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
|
|
{
|
|
triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
|
|
(
|
|
refCast<const triSurfaceMesh>(s)
|
|
);
|
|
|
|
// Flip surface so outsidePt is outside.
|
|
bool anyFlipped = orientedSurface::orient
|
|
(
|
|
shell,
|
|
outsidePt,
|
|
true
|
|
);
|
|
|
|
if (anyFlipped)
|
|
{
|
|
// orientedSurface will have done a clearOut of the surface.
|
|
// we could do a clearout of the triSurfaceMeshes::trees()
|
|
// but these aren't affected by orientation
|
|
// (except for cached
|
|
// sideness which should not be set at this point.
|
|
// !!Should check!)
|
|
|
|
Info<< "shellSurfaces : Flipped orientation of surface "
|
|
<< s.name()
|
|
<< " so point " << outsidePt << " is outside." << endl;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Find maximum level of a shell.
|
|
void Foam::shellSurfaces::findHigherLevel
|
|
(
|
|
const pointField& pt,
|
|
const label shellI,
|
|
labelList& maxLevel
|
|
) const
|
|
{
|
|
const labelList& levels = levels_[shellI];
|
|
|
|
if (modes_[shellI] == DISTANCE)
|
|
{
|
|
// Distance mode.
|
|
|
|
const scalarField& distances = distances_[shellI];
|
|
|
|
// Collect all those points that have a current maxLevel less than
|
|
// (any of) the shell. Also collect the furthest distance allowable
|
|
// to any shell with a higher level.
|
|
|
|
pointField candidates(pt.size());
|
|
labelList candidateMap(pt.size());
|
|
scalarField candidateDistSqr(pt.size());
|
|
label candidateI = 0;
|
|
|
|
forAll(maxLevel, pointi)
|
|
{
|
|
forAllReverse(levels, levelI)
|
|
{
|
|
if (levels[levelI] > maxLevel[pointi])
|
|
{
|
|
candidates[candidateI] = pt[pointi];
|
|
candidateMap[candidateI] = pointi;
|
|
candidateDistSqr[candidateI] = sqr(distances[levelI]);
|
|
candidateI++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
candidates.setSize(candidateI);
|
|
candidateMap.setSize(candidateI);
|
|
candidateDistSqr.setSize(candidateI);
|
|
|
|
// Do the expensive nearest test only for the candidate points.
|
|
List<pointIndexHit> nearInfo;
|
|
allGeometry_[shells_[shellI]].findNearest
|
|
(
|
|
candidates,
|
|
candidateDistSqr,
|
|
nearInfo
|
|
);
|
|
|
|
// Update maxLevel
|
|
forAll(nearInfo, i)
|
|
{
|
|
if (nearInfo[i].hit())
|
|
{
|
|
// Check which level it actually is in.
|
|
label minDistI = findLower
|
|
(
|
|
distances,
|
|
mag(nearInfo[i].hitPoint()-candidates[i])
|
|
);
|
|
|
|
label pointi = candidateMap[i];
|
|
|
|
// pt is inbetween shell[minDistI] and shell[minDistI+1]
|
|
maxLevel[pointi] = levels[minDistI+1];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Inside/outside mode
|
|
|
|
// Collect all those points that have a current maxLevel less than the
|
|
// shell.
|
|
|
|
pointField candidates(pt.size());
|
|
labelList candidateMap(pt.size());
|
|
label candidateI = 0;
|
|
|
|
forAll(maxLevel, pointi)
|
|
{
|
|
if (levels[0] > maxLevel[pointi])
|
|
{
|
|
candidates[candidateI] = pt[pointi];
|
|
candidateMap[candidateI] = pointi;
|
|
candidateI++;
|
|
}
|
|
}
|
|
candidates.setSize(candidateI);
|
|
candidateMap.setSize(candidateI);
|
|
|
|
// Do the expensive nearest test only for the candidate points.
|
|
List<volumeType> volType;
|
|
allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
|
|
|
|
forAll(volType, i)
|
|
{
|
|
label pointi = candidateMap[i];
|
|
|
|
if
|
|
(
|
|
(
|
|
modes_[shellI] == INSIDE
|
|
&& volType[i] == volumeType::INSIDE
|
|
)
|
|
|| (
|
|
modes_[shellI] == OUTSIDE
|
|
&& volType[i] == volumeType::OUTSIDE
|
|
)
|
|
)
|
|
{
|
|
maxLevel[pointi] = levels[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findHigherGapLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
const label shellI,
|
|
labelList& gapShell,
|
|
List<FixedList<label, 3>>& gapInfo,
|
|
List<volumeType>& gapMode
|
|
) const
|
|
{
|
|
//TBD: hardcoded for region 0 information
|
|
const FixedList<label, 3>& info = extendedGapLevel_[shellI][0];
|
|
volumeType mode = extendedGapMode_[shellI][0];
|
|
|
|
if (info[2] == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
// Collect all those points that have a current maxLevel less than the
|
|
// shell.
|
|
|
|
labelList candidateMap(pt.size());
|
|
label candidateI = 0;
|
|
|
|
forAll(ptLevel, pointI)
|
|
{
|
|
if (ptLevel[pointI] >= info[1] && ptLevel[pointI] < info[2])
|
|
{
|
|
candidateMap[candidateI++] = pointI;
|
|
}
|
|
}
|
|
candidateMap.setSize(candidateI);
|
|
|
|
// Do the expensive nearest test only for the candidate points.
|
|
List<volumeType> volType;
|
|
allGeometry_[shells_[shellI]].getVolumeType
|
|
(
|
|
pointField(pt, candidateMap),
|
|
volType
|
|
);
|
|
|
|
forAll(volType, i)
|
|
{
|
|
label pointI = candidateMap[i];
|
|
|
|
bool isInside = (volType[i] == volumeType::INSIDE);
|
|
|
|
if
|
|
(
|
|
(
|
|
(modes_[shellI] == INSIDE && isInside)
|
|
|| (modes_[shellI] == OUTSIDE && !isInside)
|
|
)
|
|
&& info[2] > gapInfo[pointI][2]
|
|
)
|
|
{
|
|
gapShell[pointI] = shellI;
|
|
gapInfo[pointI] = info;
|
|
gapMode[pointI] = mode;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findLevel
|
|
(
|
|
const pointField& pt,
|
|
const label shellI,
|
|
labelList& minLevel,
|
|
labelList& shell
|
|
) const
|
|
{
|
|
const labelList& levels = levels_[shellI];
|
|
|
|
if (modes_[shellI] == DISTANCE)
|
|
{
|
|
// Distance mode.
|
|
|
|
const scalarField& distances = distances_[shellI];
|
|
|
|
// Collect all those points that have a current level equal/greater
|
|
// (any of) the shell. Also collect the furthest distance allowable
|
|
// to any shell with a higher level.
|
|
|
|
pointField candidates(pt.size());
|
|
labelList candidateMap(pt.size());
|
|
scalarField candidateDistSqr(pt.size());
|
|
label candidateI = 0;
|
|
|
|
forAll(shell, pointI)
|
|
{
|
|
if (shell[pointI] == -1)
|
|
{
|
|
forAllReverse(levels, levelI)
|
|
{
|
|
if (levels[levelI] <= minLevel[pointI])
|
|
{
|
|
candidates[candidateI] = pt[pointI];
|
|
candidateMap[candidateI] = pointI;
|
|
candidateDistSqr[candidateI] = sqr(distances[levelI]);
|
|
candidateI++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
candidates.setSize(candidateI);
|
|
candidateMap.setSize(candidateI);
|
|
candidateDistSqr.setSize(candidateI);
|
|
|
|
// Do the expensive nearest test only for the candidate points.
|
|
List<pointIndexHit> nearInfo;
|
|
allGeometry_[shells_[shellI]].findNearest
|
|
(
|
|
candidates,
|
|
candidateDistSqr,
|
|
nearInfo
|
|
);
|
|
|
|
// Update maxLevel
|
|
forAll(nearInfo, i)
|
|
{
|
|
if (nearInfo[i].hit())
|
|
{
|
|
// Check which level it actually is in.
|
|
label minDistI = findLower
|
|
(
|
|
distances,
|
|
mag(nearInfo[i].hitPoint()-candidates[i])
|
|
);
|
|
|
|
label pointI = candidateMap[i];
|
|
|
|
// pt is inbetween shell[minDistI] and shell[minDistI+1]
|
|
shell[pointI] = shellI;
|
|
minLevel[pointI] = levels[minDistI+1];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Inside/outside mode
|
|
|
|
// Collect all those points that have a current maxLevel less than the
|
|
// shell.
|
|
|
|
pointField candidates(pt.size());
|
|
labelList candidateMap(pt.size());
|
|
label candidateI = 0;
|
|
|
|
forAll(shell, pointI)
|
|
{
|
|
if (shell[pointI] == -1 && levels[0] <= minLevel[pointI])
|
|
{
|
|
candidates[candidateI] = pt[pointI];
|
|
candidateMap[candidateI] = pointI;
|
|
candidateI++;
|
|
}
|
|
}
|
|
candidates.setSize(candidateI);
|
|
candidateMap.setSize(candidateI);
|
|
|
|
// Do the expensive nearest test only for the candidate points.
|
|
List<volumeType> volType;
|
|
allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
|
|
|
|
forAll(volType, i)
|
|
{
|
|
if
|
|
(
|
|
(
|
|
modes_[shellI] == INSIDE
|
|
&& volType[i] == volumeType::INSIDE
|
|
)
|
|
|| (
|
|
modes_[shellI] == OUTSIDE
|
|
&& volType[i] == volumeType::OUTSIDE
|
|
)
|
|
)
|
|
{
|
|
label pointI = candidateMap[i];
|
|
shell[pointI] = shellI;
|
|
minLevel[pointI] = levels[0];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
Foam::shellSurfaces::shellSurfaces
|
|
(
|
|
const searchableSurfaces& allGeometry,
|
|
const dictionary& shellsDict
|
|
)
|
|
:
|
|
allGeometry_(allGeometry)
|
|
{
|
|
// Wilcard specification : loop over all surfaces and try to find a match.
|
|
|
|
// Count number of shells.
|
|
label shellI = 0;
|
|
for (const word& geomName : allGeometry_.names())
|
|
{
|
|
if (shellsDict.found(geomName))
|
|
{
|
|
++shellI;
|
|
}
|
|
}
|
|
|
|
|
|
// Size lists
|
|
shells_.setSize(shellI);
|
|
modes_.setSize(shellI);
|
|
distances_.setSize(shellI);
|
|
levels_.setSize(shellI);
|
|
dirLevels_.setSize(shellI);
|
|
smoothDirection_.setSize(shellI);
|
|
nSmoothExpansion_.setSize(shellI);
|
|
nSmoothPosition_.setSize(shellI);
|
|
|
|
extendedGapLevel_.setSize(shellI);
|
|
extendedGapMode_.setSize(shellI);
|
|
|
|
FixedList<label, 3> nullGapLevel;
|
|
nullGapLevel[0] = 0;
|
|
nullGapLevel[1] = 0;
|
|
nullGapLevel[2] = 0;
|
|
|
|
|
|
wordHashSet unmatchedKeys(shellsDict.toc());
|
|
shellI = 0;
|
|
|
|
forAll(allGeometry_.names(), geomI)
|
|
{
|
|
const word& geomName = allGeometry_.names()[geomI];
|
|
|
|
const entry* eptr = shellsDict.findEntry(geomName, keyType::LITERAL);
|
|
|
|
if (eptr)
|
|
{
|
|
const dictionary& dict = eptr->dict();
|
|
unmatchedKeys.erase(eptr->keyword());
|
|
|
|
shells_[shellI] = geomI;
|
|
modes_[shellI] = refineModeNames_.lookup("mode", dict);
|
|
|
|
// Read pairs of distance+level
|
|
setAndCheckLevels(shellI, dict.lookup("levels"));
|
|
|
|
|
|
// Directional refinement
|
|
// ~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
dirLevels_[shellI] = Tuple2<labelPair,labelVector>
|
|
(
|
|
labelPair(labelMax, labelMin),
|
|
labelVector::zero
|
|
);
|
|
const entry* levelPtr =
|
|
dict.findEntry("levelIncrement", keyType::REGEX);
|
|
|
|
if (levelPtr)
|
|
{
|
|
// Do reading ourselves since using labelPair would require
|
|
// additional bracket pair
|
|
Istream& is = levelPtr->stream();
|
|
|
|
is.readBegin("levelIncrement");
|
|
is >> dirLevels_[shellI].first().first()
|
|
>> dirLevels_[shellI].first().second()
|
|
>> dirLevels_[shellI].second();
|
|
is.readEnd("levelIncrement");
|
|
|
|
if (modes_[shellI] == INSIDE)
|
|
{
|
|
Info<< "Additional directional refinement level"
|
|
<< " for all cells inside " << geomName << endl;
|
|
}
|
|
else if (modes_[shellI] == OUTSIDE)
|
|
{
|
|
Info<< "Additional directional refinement level"
|
|
<< " for all cells outside " << geomName << endl;
|
|
}
|
|
else
|
|
{
|
|
FatalIOErrorInFunction(shellsDict)
|
|
<< "Unsupported mode "
|
|
<< refineModeNames_[modes_[shellI]]
|
|
<< exit(FatalIOError);
|
|
}
|
|
}
|
|
|
|
// Directional smoothing
|
|
// ~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
nSmoothExpansion_[shellI] = 0;
|
|
nSmoothPosition_[shellI] = 0;
|
|
smoothDirection_[shellI] =
|
|
dict.lookupOrDefault("smoothDirection", vector::zero);
|
|
|
|
if (smoothDirection_[shellI] != vector::zero)
|
|
{
|
|
dict.readEntry("nSmoothExpansion", nSmoothExpansion_[shellI]);
|
|
dict.readEntry("nSmoothPosition", nSmoothPosition_[shellI]);
|
|
}
|
|
|
|
|
|
// Gap specification
|
|
// ~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
// Shell-wide gap level specification
|
|
const searchableSurface& surface = allGeometry_[geomI];
|
|
const wordList& regionNames = surface.regions();
|
|
|
|
FixedList<label, 3> gapSpec
|
|
(
|
|
dict.lookupOrDefault
|
|
(
|
|
"gapLevel",
|
|
nullGapLevel
|
|
)
|
|
);
|
|
extendedGapLevel_[shellI].setSize(regionNames.size());
|
|
extendedGapLevel_[shellI] = gapSpec;
|
|
|
|
extendedGapMode_[shellI].setSize(regionNames.size());
|
|
extendedGapMode_[shellI] =
|
|
volumeType("gapMode", dict, volumeType::MIXED);
|
|
|
|
|
|
// Override on a per-region basis?
|
|
|
|
if (dict.found("regions"))
|
|
{
|
|
const dictionary& regionsDict = dict.subDict("regions");
|
|
forAll(regionNames, regionI)
|
|
{
|
|
if (regionsDict.found(regionNames[regionI]))
|
|
{
|
|
// Get the dictionary for region
|
|
const dictionary& regionDict = regionsDict.subDict
|
|
(
|
|
regionNames[regionI]
|
|
);
|
|
FixedList<label, 3> gapSpec
|
|
(
|
|
regionDict.lookupOrDefault
|
|
(
|
|
"gapLevel",
|
|
nullGapLevel
|
|
)
|
|
);
|
|
extendedGapLevel_[shellI][regionI] = gapSpec;
|
|
|
|
extendedGapMode_[shellI][regionI] =
|
|
volumeType
|
|
(
|
|
"gapMode",
|
|
regionDict,
|
|
volumeType::MIXED
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
checkGapLevels(dict, shellI, extendedGapLevel_[shellI]);
|
|
|
|
shellI++;
|
|
}
|
|
}
|
|
|
|
if (unmatchedKeys.size() > 0)
|
|
{
|
|
IOWarningInFunction
|
|
(
|
|
shellsDict
|
|
) << "Not all entries in refinementRegions dictionary were used."
|
|
<< " The following entries were not used : "
|
|
<< unmatchedKeys.sortedToc()
|
|
<< endl;
|
|
}
|
|
|
|
// Orient shell surfaces before any searching is done. Note that this
|
|
// only needs to be done for inside or outside. Orienting surfaces
|
|
// constructs lots of addressing which we want to avoid.
|
|
orient();
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
|
|
|
// Highest shell level
|
|
Foam::label Foam::shellSurfaces::maxLevel() const
|
|
{
|
|
label overallMax = 0;
|
|
forAll(levels_, shellI)
|
|
{
|
|
overallMax = max(overallMax, max(levels_[shellI]));
|
|
}
|
|
return overallMax;
|
|
}
|
|
|
|
|
|
Foam::labelList Foam::shellSurfaces::maxGapLevel() const
|
|
{
|
|
labelList surfaceMax(extendedGapLevel_.size(), 0);
|
|
|
|
forAll(extendedGapLevel_, shelli)
|
|
{
|
|
const List<FixedList<label, 3>>& levels = extendedGapLevel_[shelli];
|
|
forAll(levels, i)
|
|
{
|
|
surfaceMax[shelli] = max(surfaceMax[shelli], levels[i][2]);
|
|
}
|
|
}
|
|
return surfaceMax;
|
|
}
|
|
|
|
|
|
Foam::labelPairList Foam::shellSurfaces::directionalSelectLevel() const
|
|
{
|
|
labelPairList levels(dirLevels_.size());
|
|
forAll(dirLevels_, shelli)
|
|
{
|
|
levels[shelli] = dirLevels_[shelli].first();
|
|
}
|
|
return levels;
|
|
}
|
|
|
|
|
|
const Foam::labelList& Foam::shellSurfaces::nSmoothExpansion() const
|
|
{
|
|
return nSmoothExpansion_;
|
|
}
|
|
|
|
|
|
const Foam::vectorField& Foam::shellSurfaces::smoothDirection() const
|
|
{
|
|
return smoothDirection_;
|
|
}
|
|
|
|
|
|
const Foam::labelList& Foam::shellSurfaces::nSmoothPosition() const
|
|
{
|
|
return nSmoothPosition_;
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findHigherLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
labelList& maxLevel
|
|
) const
|
|
{
|
|
// Maximum level of any shell. Start off with level of point.
|
|
maxLevel = ptLevel;
|
|
|
|
forAll(shells_, shelli)
|
|
{
|
|
findHigherLevel(pt, shelli, maxLevel);
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findHigherGapLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
labelList& gapShell,
|
|
List<FixedList<label, 3>>& gapInfo,
|
|
List<volumeType>& gapMode
|
|
) const
|
|
{
|
|
gapShell.setSize(pt.size());
|
|
gapShell = -1;
|
|
|
|
FixedList<label, 3> nullGapLevel;
|
|
nullGapLevel[0] = 0;
|
|
nullGapLevel[1] = 0;
|
|
nullGapLevel[2] = 0;
|
|
|
|
gapInfo.setSize(pt.size());
|
|
gapInfo = nullGapLevel;
|
|
|
|
gapMode.setSize(pt.size());
|
|
gapMode = volumeType::MIXED;
|
|
|
|
forAll(shells_, shelli)
|
|
{
|
|
findHigherGapLevel(pt, ptLevel, shelli, gapShell, gapInfo, gapMode);
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findHigherGapLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
List<FixedList<label, 3>>& gapInfo,
|
|
List<volumeType>& gapMode
|
|
) const
|
|
{
|
|
labelList gapShell;
|
|
findHigherGapLevel(pt, ptLevel, gapShell, gapInfo, gapMode);
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
labelList& shell
|
|
) const
|
|
{
|
|
shell.setSize(pt.size());
|
|
shell = -1;
|
|
|
|
labelList minLevel(ptLevel);
|
|
|
|
forAll(shells_, shelli)
|
|
{
|
|
findLevel(pt, shelli, minLevel, shell);
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::shellSurfaces::findDirectionalLevel
|
|
(
|
|
const pointField& pt,
|
|
const labelList& ptLevel,
|
|
const labelList& dirLevel, // directional level
|
|
const direction dir,
|
|
labelList& shell
|
|
) const
|
|
{
|
|
shell.setSize(pt.size());
|
|
shell = -1;
|
|
|
|
List<volumeType> volType;
|
|
|
|
// Current back to original
|
|
DynamicList<label> candidateMap(pt.size());
|
|
|
|
forAll(shells_, shelli)
|
|
{
|
|
if (modes_[shelli] == INSIDE || modes_[shelli] == OUTSIDE)
|
|
{
|
|
const labelPair& selectLevels = dirLevels_[shelli].first();
|
|
const label addLevel = dirLevels_[shelli].second()[dir];
|
|
|
|
// Collect the cells that are of the right original level
|
|
candidateMap.clear();
|
|
forAll(ptLevel, celli)
|
|
{
|
|
label level = ptLevel[celli];
|
|
|
|
if
|
|
(
|
|
level >= selectLevels.first()
|
|
&& level <= selectLevels.second()
|
|
&& dirLevel[celli] < level+addLevel
|
|
)
|
|
{
|
|
candidateMap.append(celli);
|
|
}
|
|
}
|
|
|
|
// Do geometric test
|
|
pointField candidatePt(pt, candidateMap);
|
|
allGeometry_[shells_[shelli]].getVolumeType(candidatePt, volType);
|
|
|
|
// Extract selected cells
|
|
forAll(candidateMap, i)
|
|
{
|
|
if
|
|
(
|
|
(
|
|
modes_[shelli] == INSIDE
|
|
&& volType[i] == volumeType::INSIDE
|
|
)
|
|
|| (
|
|
modes_[shelli] == OUTSIDE
|
|
&& volType[i] == volumeType::OUTSIDE
|
|
)
|
|
)
|
|
{
|
|
shell[candidateMap[i]] = shelli;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|