Commit 382be47b authored by 's avatar
Browse files

merge conflict

parents bb7852af e025603b
......@@ -75,10 +75,11 @@ v4.4.0
- Add flag to `insertsurface` process for non-conforming geometries (!700)
- Bug fix to get two meshgen regression tests working (!700)
- Remove libANN in deference to boost::geometry (!703)
- 2D to 3D mesh extrusion module (!715)
- Add a mesh extract option to the linearise module to visualise the result
(!712)
- Refactor library to use NekMesh modules for CAD generation (!704)
- Add a mesh extract option to the linearise module to visualise the result
(!712)
- 2D to 3D mesh extrusion module (!715)
- Add new two-dimensional mesher from NACA code or step file (!720)
**FieldConvert:**
- Move all modules to a new library, FieldUtils, to support post-processing
......
////////////////////////////////////////////////////////////////////////////////
//
// File: Generator2D.cpp
//
// For more information, please see: http://www.nektar.info/
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: 2D generator object methods.
//
////////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include <NekMeshUtils/2DGenerator/2DGenerator.h>
#include <LibUtilities/BasicUtils/ParseUtils.hpp>
#include <LibUtilities/BasicUtils/Progressbar.hpp>
using namespace std;
namespace Nektar
{
namespace NekMeshUtils
{
ModuleKey Generator2D::className = GetModuleFactory().RegisterCreatorFunction(
ModuleKey(eProcessModule, "2dgenerator"), Generator2D::create,
"Generates a 2D mesh");
Generator2D::Generator2D(MeshSharedPtr m) : ProcessModule(m)
{
m_config["blcurves"] =
ConfigOption(false, "0", "Generate parallelograms on these curves");
m_config["blthick"] =
ConfigOption(false, "0", "Parallelogram layer thickness");
}
Generator2D::~Generator2D()
{
}
void Generator2D::Process()
{
if (m_mesh->m_verbose)
{
cout << endl << "2D meshing" << endl;
cout << endl << "\tCurve meshing:" << endl << endl;
}
m_mesh->m_numNodes = m_mesh->m_cad->GetNumVerts();
// linear mesh all curves
for (int i = 1; i <= m_mesh->m_cad->GetNumCurve(); i++)
{
if (m_mesh->m_verbose)
{
LibUtilities::PrintProgressbar(i, m_mesh->m_cad->GetNumCurve(),
"Curve progress");
}
m_curvemeshes[i] =
MemoryManager<CurveMesh>::AllocateSharedPtr(i, m_mesh);
m_curvemeshes[i]->Mesh();
}
EdgeSet::iterator it;
for (it = m_mesh->m_edgeSet.begin(); it != m_mesh->m_edgeSet.end(); it++)
{
vector<NodeSharedPtr> ns;
ns.push_back((*it)->m_n1);
ns.push_back((*it)->m_n2);
// for each iterator create a LibUtilities::eSegement
// push segment into m_mesh->m_element[1]
// tag for the elements shoudl be the CAD number of the curves
ElmtConfig conf(LibUtilities::eSegment, 1, false, false);
vector<int> tags;
tags.push_back((*it)->m_parentCAD->GetId());
ElementSharedPtr E2 = GetElementFactory().CreateInstance(
LibUtilities::eSegment, conf, ns, tags);
m_mesh->m_element[1].push_back(E2);
}
if (m_config["blcurves"].beenSet)
{
// we need to do the boundary layer generation in a face by face basis
MakeBLPrep();
// Im going to do a horrendous trick to get the edge orientaion.
// Going to activate the first routine of facemeshing without actually
// face meshing, this will orientate the edgeloop objects (hopefully);
// which can be used by the makebl command to know the normal
// orienation
for (int i = 1; i <= m_mesh->m_cad->GetNumSurf(); i++)
{
m_facemeshes[i] = MemoryManager<FaceMesh>::AllocateSharedPtr(
i, m_mesh, m_curvemeshes, m_mesh->m_cad->GetNumSurf() > 100);
m_facemeshes[i]->OrientateCurves();
MakeBL(i, m_facemeshes[i]->GetEdges());
}
}
//m_mesh->m_element[1].clear();
if (m_mesh->m_verbose)
{
cout << endl << "\tFace meshing:" << endl << endl;
}
// linear mesh all surfaces
for (int i = 1; i <= m_mesh->m_cad->GetNumSurf(); i++)
{
if (m_mesh->m_verbose)
{
LibUtilities::PrintProgressbar(i, m_mesh->m_cad->GetNumSurf(),
"Face progress");
}
m_facemeshes[i] = MemoryManager<FaceMesh>::AllocateSharedPtr(
i, m_mesh, m_curvemeshes, m_mesh->m_cad->GetNumSurf() > 100);
m_facemeshes[i]->Mesh();
}
ProcessVertices();
ProcessEdges();
ProcessFaces();
ProcessElements();
ProcessComposites();
Report();
}
void Generator2D::MakeBLPrep()
{
if (m_mesh->m_verbose)
{
cout << endl << "\tBoundary layer meshing:" << endl << endl;
}
// identify the nodes which will become the boundary layer.
ParseUtils::GenerateSeqVector(m_config["blcurves"].as<string>().c_str(),
m_blCurves);
m_thickness = m_config["blthick"].as<NekDouble>();
for (vector<unsigned>::iterator it = m_blCurves.begin();
it != m_blCurves.end(); ++it)
{
vector<EdgeSharedPtr> localedges = m_curvemeshes[*it]->GetMeshEdges();
for (int i = 0; i < localedges.size(); i++)
{
m_nodesToEdge[localedges[i]->m_n1].push_back(localedges[i]);
m_nodesToEdge[localedges[i]->m_n2].push_back(localedges[i]);
}
}
}
void Generator2D::MakeBL(int faceid, vector<EdgeLoop> e)
{
map<int, int> edgeToOrient;
for (vector<EdgeLoop>::iterator lit = e.begin(); lit != e.end(); ++lit)
{
for (int i = 0; i < lit->edges.size(); ++i)
{
edgeToOrient[lit->edges[i]->GetId()] = lit->edgeo[i];
}
}
map<int, Array<OneD, NekDouble> > edgeNormals;
int eid = 0;
for (vector<unsigned>::iterator it = m_blCurves.begin();
it != m_blCurves.end(); ++it)
{
int edgeo = edgeToOrient[*it];
vector<EdgeSharedPtr> es = m_curvemeshes[*it]->GetMeshEdges();
// on each !!!EDGE!!! calculate a normal
// always to the left unless edgeo is 1
for(int j = 0; j < es.size(); j++)
{
es[j]->m_id = eid++;
Array<OneD, NekDouble> p1 = (edgeo == 0) ? es[j]->m_n1->GetLoc()
: es[j]->m_n2->GetLoc();
Array<OneD, NekDouble> p2 = (edgeo == 0) ? es[j]->m_n2->GetLoc()
: es[j]->m_n1->GetLoc();
Array<OneD, NekDouble> n(2);
n[0] = p1[1] - p2[1];
n[1] = p2[0] - p1[0];
NekDouble mag = sqrt(n[0]*n[0]+n[1]*n[1]);
n[0] /= mag;
n[1] /= mag;
edgeNormals[es[j]->m_id] = n;
}
}
map<NodeSharedPtr, NodeSharedPtr> nodeNormals;
map<NodeSharedPtr, vector<EdgeSharedPtr> >::iterator it;
for(it = m_nodesToEdge.begin(); it != m_nodesToEdge.end(); it++)
{
Array<OneD, NekDouble> n(3);
ASSERTL0(it->second.size() == 2,
"wierdness, most likely bl_surfs are incorrect");
Array<OneD, NekDouble> n1 = edgeNormals[it->second[0]->m_id];
Array<OneD, NekDouble> n2 = edgeNormals[it->second[1]->m_id];
n[0] = (n1[0] + n2[0]) / 2.0;
n[1] = (n1[1] + n2[1]) / 2.0;
NekDouble mag = sqrt(n[0]*n[0]+n[1]*n[1]);
n[0] /= mag;
n[1] /= mag;
n[0] = n[0] * m_thickness + it->first->m_x;
n[1] = n[1] * m_thickness + it->first->m_y;
n[2] = 0.0;
NodeSharedPtr nn = boost::shared_ptr<Node>(
new Node(m_mesh->m_numNodes++, n[0], n[1], 0.0));
CADSurfSharedPtr s = m_mesh->m_cad->GetSurf(faceid);
Array<OneD, NekDouble> uv = s->locuv(n);
nn->SetCADSurf(faceid,s,uv);
nodeNormals[it->first] = nn;
}
for (vector<unsigned>::iterator it = m_blCurves.begin();
it != m_blCurves.end(); ++it)
{
int edgeo = edgeToOrient[*it];
vector<NodeSharedPtr> ns = m_curvemeshes[*it]->GetMeshPoints();
vector<NodeSharedPtr> newNs;
for(int i = 0; i < ns.size(); i++)
{
newNs.push_back(nodeNormals[ns[i]]);
}
m_curvemeshes[*it] = MemoryManager<CurveMesh>::AllocateSharedPtr(
*it, m_mesh, newNs);
if(edgeo == 1)
{
reverse(ns.begin(), ns.end());
}
for (int i = 0; i < ns.size() - 1; ++i)
{
vector<NodeSharedPtr> qns;
qns.push_back(ns[i]);
qns.push_back(ns[i+1]);
qns.push_back(nodeNormals[ns[i+1]]);
qns.push_back(nodeNormals[ns[i]]);
ElmtConfig conf(LibUtilities::eQuadrilateral, 1, false, false);
vector<int> tags;
tags.push_back(102);
ElementSharedPtr E = GetElementFactory().CreateInstance(
LibUtilities::eQuadrilateral, conf, qns, tags);
E->m_parentCAD = m_mesh->m_cad->GetSurf(faceid);
for (int j = 0; j < E->GetEdgeCount(); ++j)
{
pair<EdgeSet::iterator,bool> testIns;
EdgeSharedPtr ed = E->GetEdge(j);
// look for edge in m_mesh edgeset from curves
EdgeSet::iterator s = m_mesh->m_edgeSet.find(ed);
if (!(s == m_mesh->m_edgeSet.end()))
{
ed = *s;
E->SetEdge(j, *s);
}
}
m_mesh->m_element[2].push_back(E);
}
}
}
void Generator2D::Report()
{
if (m_mesh->m_verbose)
{
int ns = m_mesh->m_vertexSet.size();
int es = m_mesh->m_edgeSet.size();
int ts = m_mesh->m_element[2].size();
int ep = ns - es + ts;
cout << endl << "\tSurface mesh statistics" << endl;
cout << "\t\tNodes: " << ns << endl;
cout << "\t\tEdges: " << es << endl;
cout << "\t\tTriangles " << ts << endl;
cout << "\t\tEuler-Poincaré characteristic: " << ep << endl;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// File: SurfaceMeshing.h
//
// For more information, please see: http://www.nektar.info/
//
// The MIT License
//
// Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
// Department of Aeronautics, Imperial College London (UK), and Scientific
// Computing and Imaging Institute, University of Utah (USA).
//
// License for the specific language governing rights and limitations under
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Description: class containing all surfacemeshing routines and classes.
//
////////////////////////////////////////////////////////////////////////////////
#ifndef NEKMESHUTILS_2D_2D
#define NEKMESHUTILS_2D_2D
#include <NekMeshUtils/Module/Module.h>
#include <NekMeshUtils/SurfaceMeshing/CurveMesh.h>
#include <NekMeshUtils/SurfaceMeshing/FaceMesh.h>
namespace Nektar
{
namespace NekMeshUtils
{
/**
* @brief class containing all surface meshing routines methods and classes
*/
class Generator2D : public ProcessModule
{
public:
/// Creates an instance of this class
static boost::shared_ptr<Module> create(MeshSharedPtr m)
{
return MemoryManager<Generator2D>::AllocateSharedPtr(m);
}
static ModuleKey className;
Generator2D(MeshSharedPtr m);
virtual ~Generator2D();
virtual void Process();
private:
void MakeBLPrep();
void MakeBL(int faceid, std::vector<EdgeLoop> e);
void Report();
/// map of individual surface meshes from parametric surfaces
std::map<int, FaceMeshSharedPtr> m_facemeshes;
/// map of individual curve meshes of the curves in the domain
std::map<int, CurveMeshSharedPtr> m_curvemeshes;
std::vector<unsigned int> m_blCurves;
NekDouble m_thickness;
std::map<NodeSharedPtr, std::vector<EdgeSharedPtr> > m_nodesToEdge;
};
}
}
#endif
......@@ -97,6 +97,8 @@ public:
*/
virtual Array<OneD, NekDouble> D2(NekDouble t) = 0;
virtual NekDouble Curvature(NekDouble t) = 0;
/**
* @brief Calculates the parametric coordinate and arclength location
* defined by \p s.
......
......@@ -86,6 +86,7 @@ public:
*/
CADSystem(std::string name) : m_name(name)
{
m_2d = false;
}
~CADSystem()
......@@ -100,6 +101,16 @@ public:
return m_name;
}
void Set2D()
{
m_2d = true;
}
bool Is2D()
{
return m_2d;
}
/**
* @brief Initialises CAD and makes surface, curve and vertex maps.
*
......@@ -190,6 +201,8 @@ protected:
std::map<int, CADSurfSharedPtr> m_surfs;
/// Map of vertices
std::map<int, CADVertSharedPtr> m_verts;
bool m_2d;
};
typedef boost::shared_ptr<CADSystem> CADSystemSharedPtr;
......
......@@ -128,6 +128,14 @@ Array<OneD, NekDouble> CADCurveOCE::D2(NekDouble t)
return out;
}
NekDouble CADCurveOCE::Curvature(NekDouble t)
{
GeomLProp_CLProps d(m_c,2,1e-8);
d.SetParameter(t);
return d.Curvature() * 1000.0;
}
Array<OneD, NekDouble> CADCurveOCE::Bounds()
{
Array<OneD, NekDouble> t(2);
......
......@@ -70,6 +70,7 @@ public:
virtual NekDouble tAtArcLength(NekDouble s);
virtual Array<OneD, NekDouble> GetMinMax();
virtual NekDouble loct(Array<OneD, NekDouble> xyz);
virtual NekDouble Curvature(NekDouble t);
void Initialise(int i, TopoDS_Shape in)
{
......
......@@ -51,18 +51,25 @@ std::string CADSystemOCE::key = GetEngineFactory().RegisterCreatorFunction(
bool CADSystemOCE::LoadCAD()
{
cout << "trying " << m_name << endl;
// Takes step file and makes OpenCascade shape
STEPControl_Reader reader;
reader = STEPControl_Reader();
reader.ReadFile(m_name.c_str());
reader.NbRootsForTransfer();
reader.TransferRoots();
shape = reader.OneShape();
if (shape.IsNull())
if (m_name.find('.') != std::string::npos)
{
return false;
// Takes step file and makes OpenCascade shape
STEPControl_Reader reader;
reader = STEPControl_Reader();
reader.ReadFile(m_name.c_str());
reader.NbRootsForTransfer();
reader.TransferRoots();
shape = reader.OneShape();
if (shape.IsNull())
{
return false;
}
}
else
{
cout << m_name << " is not a STEP file, assuming it is "
<< "a 4 digit NACA code" << endl;
shape = BuildNACA(m_name);
}
// faces and verts can be extracted straight from shape
......@@ -105,8 +112,8 @@ bool CADSystemOCE::LoadCAD()
}
}
map<int, vector<int> > adjsurfmap; // from id of curve to list of ids of
// surfs
// from id of curve to list of ids of surfs
map<int, vector<int> > adjsurfmap;
// Adds edges to our type and map
for (int i = 1; i <= mapOfEdges.Extent(); i++)
......@@ -267,7 +274,11 @@ bool CADSystemOCE::LoadCAD()
for (map<int, vector<int> >::iterator it = adjsurfmap.begin();
it != adjsurfmap.end(); it++)
{
ASSERTL0(it->second.size() == 2, "no three curve surfaces");
if(!m_2d)
{
ASSERTL0(it->second.size() == 2, "no three curve surfaces");
}
vector<CADSurfSharedPtr> sfs;
for (int i = 0; i < it->second.size(); i++)
{
......@@ -347,5 +358,111 @@ Array<OneD, NekDouble> CADSystemOCE::GetBoundingBox()
return bound;
}
TopoDS_Shape CADSystemOCE::BuildNACA(string naca)
{
ASSERTL0(naca.length() == 4, "not a 4 digit code");
int n = boost::lexical_cast<int>(naca);
NekDouble T = (n%100) / 100.0;
n/=100;
NekDouble P = (n%10)/10.0;
n/=10;
NekDouble M = (n%10)/100.0;
int np = 25;
Array<OneD, NekDouble> xc(np);
NekDouble dtheta = M_PI/(np-1);
for(int i = 0; i < np; i++)
{
xc[i] = (1.0 - cos(i*dtheta)) / 2.0;
}
Array<OneD, NekDouble> yc(np), dyc(np);
for(int i = 0; i < np; i++)
{
if(xc[i] < P)
{
yc[i] = M / P / P * (2.0 * P * xc[i] - xc[i] * xc[i]);
dyc[i] = 2.0 * M / P / P * (P - xc[i]);
}
else
{
yc[i] = M / (1.0 - P) / (1.0 - P) * (
1.0 - 2.0 * P + 2.0 * P * xc[i] - xc[i] * xc[i]);
dyc[i] = 2.0 * M / (1.0 - P) / (1.0 - P) * (P - xc[i]);
}