openfoam/src/meshTools/triSurface/triSurfaceLoader/triSurfaceLoader.C
Mark Olesen 6563c98d6c ENH: support different triSurface loading options
- "single" = One region for all files
 - "file"   = One region for each file
 - "offset" = Offset regions per file
 - "merge"  = Merge regions by name

These specifications provide finer control when loading multiple
surfaces.
2017-05-29 18:25:23 +02:00

396 lines
10 KiB
C

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2017 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "triSurfaceLoader.H"
#include "fileNameList.H"
#include "Time.H"
#include "OSspecific.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::Enum<Foam::triSurfaceLoader::loadingOption>
Foam::triSurfaceLoader::loadingOptionNames
(
SINGLE_REGION, { "single", "file", "offset", "merge" }
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::triSurfaceLoader::triSurfaceLoader(const fileName& directory)
:
directory_(directory),
available_(),
selected_()
{
readDir();
}
Foam::triSurfaceLoader::triSurfaceLoader(const Time& runTime)
:
directory_(runTime.constantPath()/"triSurface"),
available_(),
selected_()
{
readDir();
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::triSurfaceLoader::~triSurfaceLoader()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::triSurfaceLoader::readDir()
{
fileNameList files = Foam::readDir(directory_, fileName::FILE);
// Will be using triSurface
//
// - filter according to what is supported
//
// Transform from fileName to word and eliminate duplicates
// (eg, files with/without .gz)
wordHashSet names(2*files.size());
forAll(files, filei)
{
const fileName& f = files[filei];
if (triSurface::canRead(f))
{
names.insert(f.name());
}
}
available_ = names.sortedToc(); // Also hashes the names
return available_.size();
}
Foam::label Foam::triSurfaceLoader::selectAll()
{
selected_ = available_;
return selected_.size();
}
Foam::label Foam::triSurfaceLoader::select(const word& name)
{
if (available_.found(name))
{
selected_ = wordList{name}; // hashedWordList::operator[] is hidden!
}
else
{
selected_.clear();
}
return selected_.size();
}
Foam::label Foam::triSurfaceLoader::select(const wordRe& mat)
{
DynamicList<label> foundIds(available_.size());
if (mat.isPattern())
{
foundIds = findMatchingStrings(mat, available_);
sort(foundIds);
}
else
{
const word& plain = static_cast<const word&>(mat);
if (available_.found(plain))
{
foundIds.append(available_[plain]);
}
else
{
FatalErrorInFunction
<< "Specified the surfaces " << mat << nl
<< " - but could not find it"
<< exit(FatalError);
}
}
selected_ = wordList(available_, foundIds);
return selected_.size();
}
Foam::label Foam::triSurfaceLoader::select(const wordReList& matcher)
{
// Need to be more careful when select.
// - preserve same order as the input matcher itself
// - avoid duplicate selections
// - flag explicitly named files as missing.
// (Eg, foo.stl must exist, but "foo.*\.stl" is optional)
// Track which files have already been selected
DynamicList<label> foundIds(available_.size());
labelHashSet hashedFound(2*available_.size());
DynamicList<word> missing(matcher.size());
wordHashSet hashedMissing(2*matcher.size());
// Exact matches must exist
forAll(matcher, i)
{
const wordRe& mat = matcher[i];
if (mat.isPattern())
{
labelList indices = findMatchingStrings(mat, available_);
sort(indices);
forAll(indices, j)
{
const label idx = indices[j];
if (hashedFound.insert(idx))
{
foundIds.append(idx);
}
}
}
else
{
const word& plain = static_cast<const word&>(mat);
if (available_.found(plain))
{
const label idx = available_[plain];
if (hashedFound.insert(idx))
{
foundIds.append(idx);
}
}
else if (hashedMissing.insert(plain))
{
missing.append(plain);
}
}
}
if (missing.size())
{
FatalErrorInFunction
<< "Specified the surfaces " << flatOutput(matcher) << nl
<< " - but could not find " << flatOutput(missing)
<< exit(FatalError);
}
selected_ = wordList(available_, foundIds);
return selected_.size();
}
Foam::autoPtr<Foam::triSurface> Foam::triSurfaceLoader::load
(
const enum loadingOption opt
) const
{
autoPtr<triSurface> output;
if (selected_.empty())
{
return output;
}
else if (selected_.size() == 1)
{
output.set(new triSurface(directory_/selected_[0]));
triSurface& surf = output();
if
(
opt == loadingOption::SINGLE_REGION
|| opt == loadingOption::FILE_REGION
)
{
for (labelledTri& f : surf)
{
f.region() = 0;
}
if (surf.patches().size())
{
surf.patches().setSize(1);
}
else
{
surf.patches().append
(
geometricSurfacePatch(selected_[0].lessExt(), 0)
);
}
}
return output;
}
List<labelledTri> faces;
pointField points;
Map<label> oldToNew;
HashTable<label> patchNameLookup;
DynamicList<geometricSurfacePatch> patches(16*selected_.size());
forAll(selected_, surfi)
{
triSurface addsurf(directory_/selected_[surfi]);
List<labelledTri> addfaces(addsurf.xferFaces());
List<point> addpoints(addsurf.xferPoints());
// Offset the points for all additional surfaces
if (surfi)
{
const label ptoff = points.size();
for (labelledTri& f : addfaces)
{
forAll(f, fi)
{
f[fi] += ptoff;
}
}
}
switch (opt)
{
case loadingOption::SINGLE_REGION:
{
for (labelledTri& f : addfaces)
{
f.region() = 0;
}
if (patches.empty() && !addsurf.patches().empty())
{
patches.append(addsurf.patches().first());
}
break;
}
case loadingOption::FILE_REGION:
{
for (labelledTri& f : addfaces)
{
f.region() = surfi;
}
// Use surface name for region
patches.append
(
geometricSurfacePatch(selected_[surfi].lessExt(), surfi)
);
break;
}
case loadingOption::OFFSET_REGION:
{
// Collect all patches, preserving names.
// This will be horrible for output, but is good if we rely
// on the names for defining baffles.
// region offset
const label regoff = patches.size();
patches.append(addsurf.patches());
if (surfi)
{
for (labelledTri& f : addfaces)
{
f.region() += regoff;
}
}
break;
}
case loadingOption::MERGE_REGION:
{
// Merge by name
geometricSurfacePatchList& addpatches = addsurf.patches();
// Build lookup tables with name->id and localId -> mergedId
oldToNew.clear();
forAll(addpatches, patchi)
{
geometricSurfacePatch& p = addpatches[patchi];
const word& patchName = p.name();
label patchId = patches.size();
if (patchNameLookup.insert(patchName, patchId))
{
p.index() = patchId;
patches.append(p);
}
else
{
patchId = patchNameLookup[patchName];
}
oldToNew.insert(patchi, patchId);
}
if (surfi)
{
// Relabel regions accordingly
for (labelledTri& f : addfaces)
{
f.region() = oldToNew[f.region()];
}
}
break;
}
}
if (surfi)
{
faces.append(addfaces);
points.append(addpoints);
}
else
{
faces.transfer(addfaces);
points.transfer(addpoints);
}
}
output.set(new triSurface(faces, patches, points, true));
return output;
}
// ************************************************************************* //