/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2020-2022 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 .
\*---------------------------------------------------------------------------*/
#include "refinementFeatures.H"
#include "Time.H"
#include "Tuple2.H"
#include "DynamicField.H"
#include "featureEdgeMesh.H"
#include "meshRefinement.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::refinementFeatures::read
(
const objectRegistry& io,
const PtrList& featDicts
)
{
forAll(featDicts, featI)
{
const dictionary& dict = featDicts[featI];
fileName featFileName
(
meshRefinement::get
(
dict,
"file",
dryRun_,
keyType::REGEX,
fileName::null
)
);
// Try reading extendedEdgeMesh first
IOobject extFeatObj
(
featFileName, // name
io.time().constant(), // instance
"extendedFeatureEdgeMesh", // local
io.time(), // registry
IOobject::MUST_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
const fileName fName
(
extFeatObj.typeFilePath()
);
if (!fName.empty() && extendedEdgeMesh::canRead(fName))
{
autoPtr eMeshPtr = extendedEdgeMesh::New
(
fName
);
if (!dryRun_)
{
Info<< "Read extendedFeatureEdgeMesh " << extFeatObj.name()
<< nl << incrIndent;
eMeshPtr().writeStats(Info);
Info<< decrIndent << endl;
}
set(featI, new extendedFeatureEdgeMesh(extFeatObj, eMeshPtr()));
}
else
{
// Try reading edgeMesh
IOobject featObj
(
featFileName, // name
io.time().constant(), // instance
"triSurface", // local
io.time(), // registry
IOobject::MUST_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
const fileName fName
(
featObj.typeFilePath()
);
if (fName.empty())
{
FatalIOErrorInFunction(dict)
<< "Could not open " << featObj.objectPath()
<< exit(FatalIOError);
}
// Read as edgeMesh
autoPtr eMeshPtr = edgeMesh::New(fName);
const edgeMesh& eMesh = eMeshPtr();
if (!dryRun_)
{
Info<< "Read edgeMesh " << featObj.name() << nl
<< incrIndent;
eMesh.writeStats(Info);
Info<< decrIndent << endl;
}
// Analyse for feature points. These are all classified as mixed
// points for lack of anything better
const labelListList& pointEdges = eMesh.pointEdges();
labelList oldToNew(eMesh.points().size(), -1);
DynamicField newPoints(eMesh.points().size());
forAll(pointEdges, pointi)
{
if (pointEdges[pointi].size() > 2)
{
oldToNew[pointi] = newPoints.size();
newPoints.append(eMesh.points()[pointi]);
}
//else if (pointEdges[pointi].size() == 2)
//MEJ: do something based on a feature angle?
}
label nFeatures = newPoints.size();
forAll(oldToNew, pointi)
{
if (oldToNew[pointi] == -1)
{
oldToNew[pointi] = newPoints.size();
newPoints.append(eMesh.points()[pointi]);
}
}
const edgeList& edges = eMesh.edges();
edgeList newEdges(edges.size());
forAll(edges, edgeI)
{
const edge& e = edges[edgeI];
newEdges[edgeI] = edge
(
oldToNew[e[0]],
oldToNew[e[1]]
);
}
// Construct an extendedEdgeMesh with
// - all points on more than 2 edges : mixed feature points
// - all edges : external edges
extendedEdgeMesh eeMesh
(
newPoints, // pts
newEdges, // eds
0, // (point) concaveStart
0, // (point) mixedStart
nFeatures, // (point) nonFeatureStart
edges.size(), // (edge) internalStart
edges.size(), // (edge) flatStart
edges.size(), // (edge) openStart
edges.size(), // (edge) multipleStart
vectorField(0), // normals
List(0),// normalVolumeTypes
vectorField(0), // edgeDirections
labelListList(0), // normalDirections
labelListList(0), // edgeNormals
labelListList(0), // featurePointNormals
labelListList(0), // featurePointEdges
identity(newEdges.size()) // regionEdges
);
//Info<< "Constructed extendedFeatureEdgeMesh " << featObj.name()
// << nl << incrIndent;
//eeMesh.writeStats(Info);
//Info<< decrIndent << endl;
set(featI, new extendedFeatureEdgeMesh(featObj, eeMesh));
}
const extendedEdgeMesh& eMesh = operator[](featI);
if (dict.found("levels"))
{
List> distLevels(dict.lookup("levels"));
if (dict.size() < 1)
{
FatalErrorInFunction
<< " : levels should be at least size 1" << endl
<< "levels : " << dict.lookup("levels")
<< exit(FatalError);
}
distances_[featI].setSize(distLevels.size());
levels_[featI].setSize(distLevels.size());
forAll(distLevels, j)
{
distances_[featI][j] = distLevels[j].first();
levels_[featI][j] = distLevels[j].second();
if (levels_[featI][j] < 0)
{
FatalErrorInFunction
<< "Feature " << featFileName
<< " has illegal refinement level " << levels_[featI][j]
<< exit(FatalError);
}
// Check in incremental order
if (j > 0)
{
if
(
(distances_[featI][j] <= distances_[featI][j-1])
|| (levels_[featI][j] > levels_[featI][j-1])
)
{
FatalErrorInFunction
<< " : Refinement should be specified in order"
<< " of increasing distance"
<< " (and decreasing refinement level)." << endl
<< "Distance:" << distances_[featI][j]
<< " refinementLevel:" << levels_[featI][j]
<< exit(FatalError);
}
}
}
}
else
{
// Look up 'level' for single level
levels_[featI] =
labelList
(
1,
meshRefinement::get