Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
Nektar::Utilities::ProcessBL Class Reference

This processing module calculates the Jacobian of elements using SpatialDomains::GeomFactors and the Element::GetGeom method. For now it simply prints a list of elements which have negative Jacobian. More...

#include <ProcessBL.h>

Inheritance diagram for Nektar::Utilities::ProcessBL:
Inheritance graph
[legend]
Collaboration diagram for Nektar::Utilities::ProcessBL:
Collaboration graph
[legend]

Public Member Functions

 ProcessBL (MeshSharedPtr m)
virtual ~ProcessBL ()
virtual void Process ()
 Write mesh to output file.
- Public Member Functions inherited from Nektar::Utilities::ProcessModule
 ProcessModule ()
 ProcessModule (FieldSharedPtr p_f)
 ProcessModule (MeshSharedPtr p_m)
- Public Member Functions inherited from Nektar::Utilities::Module
 Module (FieldSharedPtr p_f)
virtual void Process (po::variables_map &vm)=0
void RegisterConfig (string key, string value)
 Register a configuration option with a module.
void PrintConfig ()
 Print out all configuration options for a module.
void SetDefaults ()
 Sets default configuration options for those which have not been set.
bool GetRequireEquiSpaced (void)
void SetRequireEquiSpaced (bool pVal)
void EvaluateTriFieldAtEquiSpacedPts (LocalRegions::ExpansionSharedPtr &exp, const Array< OneD, const NekDouble > &infield, Array< OneD, NekDouble > &outfield)
 Module (MeshSharedPtr p_m)
void RegisterConfig (string key, string value)
void PrintConfig ()
void SetDefaults ()
MeshSharedPtr GetMesh ()
virtual void ProcessVertices ()
 Extract element vertices.

Static Public Member Functions

static boost::shared_ptr< Modulecreate (MeshSharedPtr m)
 Creates an instance of this class.

Static Public Attributes

static ModuleKey className

Additional Inherited Members

- Protected Member Functions inherited from Nektar::Utilities::Module
 Module ()
virtual void ProcessEdges (bool ReprocessEdges=true)
 Extract element edges.
virtual void ProcessFaces (bool ReprocessFaces=true)
 Extract element faces.
virtual void ProcessElements ()
 Generate element IDs.
virtual void ProcessComposites ()
 Generate composites.
void ReorderPrisms (PerMap &perFaces)
 Reorder node IDs so that prisms and tetrahedra are aligned correctly.
void PrismLines (int prism, PerMap &perFaces, set< int > &prismsDone, vector< ElementSharedPtr > &line)
- Protected Attributes inherited from Nektar::Utilities::Module
FieldSharedPtr m_f
 Field object.
map< string, ConfigOptionm_config
 List of configuration values.
bool m_requireEquiSpaced
MeshSharedPtr m_mesh
 Mesh object.

Detailed Description

This processing module calculates the Jacobian of elements using SpatialDomains::GeomFactors and the Element::GetGeom method. For now it simply prints a list of elements which have negative Jacobian.

Definition at line 51 of file ProcessBL.h.

Constructor & Destructor Documentation

Nektar::Utilities::ProcessBL::ProcessBL ( MeshSharedPtr  m)

Definition at line 106 of file ProcessBL.cpp.

References Nektar::Utilities::Module::m_config.

{
// BL mesh configuration.
m_config["layers"] = ConfigOption(false, "2",
"Number of layers to refine.");
m_config["nq"] = ConfigOption(false, "5",
"Number of points in high order elements.");
m_config["surf"] = ConfigOption(false, "",
"Tag identifying surface connected to prism.");
m_config["r"] = ConfigOption(false, "2.0",
"Ratio to use in geometry progression.");
}
Nektar::Utilities::ProcessBL::~ProcessBL ( )
virtual

Definition at line 119 of file ProcessBL.cpp.

{
}

Member Function Documentation

static boost::shared_ptr<Module> Nektar::Utilities::ProcessBL::create ( MeshSharedPtr  m)
inlinestatic

Creates an instance of this class.

Definition at line 55 of file ProcessBL.h.

{
return MemoryManager<ProcessBL>::AllocateSharedPtr(m);
}
void Nektar::Utilities::ProcessBL::Process ( )
virtual

Write mesh to output file.

Implements Nektar::Utilities::Module.

Definition at line 124 of file ProcessBL.cpp.

References ASSERTL0, Nektar::Utilities::SplitMapHelper::bfaces, Nektar::Utilities::SplitMapHelper::bfacesSize, Nektar::Utilities::SplitMapHelper::conn, Nektar::LibUtilities::eBoundaryLayerPoints, Nektar::LibUtilities::eBoundaryLayerPointsRev, Nektar::Utilities::SplitMapHelper::edge, Nektar::Utilities::SplitEdgeHelper::edge, Nektar::Utilities::SplitEdgeHelper::edgeVert, Nektar::LibUtilities::eGaussLobattoLegendre, Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::eModified_A, Nektar::LibUtilities::eModified_B, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::eQuadrilateral, Nektar::ParseUtils::GenerateSeqVector(), Nektar::Utilities::GetElementFactory(), Nektar::Utilities::helper2d(), Nektar::Utilities::SplitMapHelper::inc, Nektar::Utilities::SplitEdgeHelper::inc, Nektar::iterator, Nektar::Utilities::SplitMapHelper::layerOff, Nektar::Utilities::Module::m_config, Nektar::Utilities::Module::m_mesh, Nektar::Utilities::SplitMapHelper::offset, Nektar::Utilities::SplitEdgeHelper::offset, Nektar::LibUtilities::PointsManager(), Nektar::Utilities::Module::ProcessComposites(), Nektar::Utilities::Module::ProcessEdges(), Nektar::Utilities::Module::ProcessElements(), Nektar::Utilities::Module::ProcessFaces(), Nektar::Utilities::Module::ProcessVertices(), Nektar::Utilities::SplitMapHelper::size, and Nektar::Utilities::SplitEdgeHelper::size.

{
if (m_mesh->m_verbose)
{
cout << "ProcessBL: Refining prismatic boundary layer..."
<< endl;
}
// A set containing all element types which are valid.
set<LibUtilities::ShapeType> validElTypes;
validElTypes.insert(LibUtilities::ePrism);
validElTypes.insert(LibUtilities::eHexahedron);
int nodeId = m_mesh->m_vertexSet.size();
int nl = m_config["layers"].as<int>();
int nq = m_config["nq"]. as<int>();
// determine if geometric ratio is string or a constant.
LibUtilities::AnalyticExpressionEvaluator rEval;
NekDouble r = 1;
int rExprId = -1;
bool ratioIsString = false;
if (m_config["r"].isType<NekDouble>())
{
r = m_config["r"].as<NekDouble>();
}
else
{
std::string rstr = m_config["r"].as<string>();
rExprId = rEval.DefineFunction("x y z", rstr);
ratioIsString = true;
}
// Prismatic node -> face map.
int prismFaceNodes[5][4] = {
{0,1,2,3},{0,1,4,-1},{1,2,5,4},{3,2,5,-1},{0,3,5,4}};
int hexFaceNodes [6][4] = {
{0,1,2,3},{0,1,5,4},{1,2,6,5},{3,2,6,7},{0,3,7,4},{4,5,6,7}};
map<LibUtilities::ShapeType, int **> faceNodeMap;
faceNodeMap[LibUtilities::ePrism] = helper2d(5, prismFaceNodes);
faceNodeMap[LibUtilities::eHexahedron] = helper2d(6, hexFaceNodes);
// Default PointsType.
// Map which takes element ID to face on surface. This enables
// splitting to occur in either y-direction of the prism.
boost::unordered_map<int, int> splitEls;
// Set up maps which takes an edge (in nektar++ ordering) and return
// their offset and stride in the 3d array of collapsed quadrature
// points. Note that this map includes only the edges that are on
// the triangular faces as the edges in the normal direction are
// linear.
map<LibUtilities::ShapeType, map<int, SplitMapHelper> > splitMap;
int po = nq*(nl+1);
SplitMapHelper splitPrism;
int splitMapEdgePrism [6] = {0, 2, 4, 5, 6, 7};
int splitMapOffsetPrism[6] = {0, nq, 0, nq-1, nq+nq-1, nq};
int splitMapIncPrism [6] = {1, 1, po, po, po, po};
int splitMapBFacesPrism[3] = {0, 2, 4};
int splitMapConnPrism [6][2] = {{0,0}, {1,0}, {1,1},
{0,1}, {2,0}, {2,1}};
splitPrism.size = 6;
splitPrism.layerOff = nq;
splitPrism.edge = splitMapEdgePrism;
splitPrism.offset = splitMapOffsetPrism;
splitPrism.inc = splitMapIncPrism;
splitPrism.conn = helper2d(6, splitMapConnPrism);
splitPrism.bfacesSize = 3;
splitPrism.bfaces = splitMapBFacesPrism;
splitMap[LibUtilities::ePrism][1] = splitPrism;
splitMap[LibUtilities::ePrism][3] = splitPrism;
int ho = nq*(nq-1);
int tl = nq*nq;
SplitMapHelper splitHex0;
int splitMapEdgeHex0 [8] = {0, 1, 2, 3, 8, 9, 10, 11};
int splitMapOffsetHex0[8] = {0, nq-1, tl-1, ho, tl, tl+nq-1, 2*tl-1, tl+ho};
int splitMapIncHex0 [8] = {1, nq, -1, -nq, 1, nq, -1, -nq};
int splitMapBFacesHex0[4] = {1, 2, 3, 4};
int splitMapConnHex0 [8][2] = {{0,0}, {1,0}, {2,0}, {3,0},
{0,1}, {1,1}, {2,1}, {3,1}};
splitHex0.size = 8;
splitHex0.layerOff = nq*nq;
splitHex0.edge = splitMapEdgeHex0;
splitHex0.offset = splitMapOffsetHex0;
splitHex0.inc = splitMapIncHex0;
splitHex0.conn = helper2d(8, splitMapConnHex0);
splitHex0.bfacesSize = 4;
splitHex0.bfaces = splitMapBFacesHex0;
splitMap[LibUtilities::eHexahedron][0] = splitHex0;
splitMap[LibUtilities::eHexahedron][5] = splitHex0;
// splitEdge enumerates the edges in the standard prism along which
// new nodes should be generated. These edges are the three between
// the two triangular faces.
//
// edgeVertMap specifies the vertices which comprise those edges in
// splitEdge; for example splitEdge[0] = 3 which connects vertices 0
// and 3.
//
// edgeOffset holds the offset of each of edges 3, 1 and 8
// respectively inside the collapsed coordinate system.
map<LibUtilities::ShapeType, map<int, SplitEdgeHelper> > splitEdge;
int splitPrismEdges [3] = {3, 1, 8};
int splitPrismEdgeVert[3][2] = {{0,3}, {1,2}, {4,5}};
int splitPrismOffset [3] = {0, nq-1, nq*(nl+1)*(nq-1)};
int splitPrismInc [3] = {nq, nq, nq};
SplitEdgeHelper splitPrismEdge;
splitPrismEdge.size = 3;
splitPrismEdge.edge = splitPrismEdges;
splitPrismEdge.edgeVert = helper2d(3, splitPrismEdgeVert);
splitPrismEdge.offset = splitPrismOffset;
splitPrismEdge.inc = splitPrismInc;
splitEdge[LibUtilities::ePrism][1] = splitPrismEdge;
splitEdge[LibUtilities::ePrism][3] = splitPrismEdge;
int splitHex0Edges [4] = {4, 5, 6, 7};
int splitHex0EdgeVert[4][2] = {{0,4}, {1,5}, {2,6}, {3,7}};
int splitHex0Offset [4] = {0, nq-1, nq*nq-1, nq*(nq-1) };
int splitHex0Inc [4] = {nq*nq, nq*nq, nq*nq, nq*nq};
SplitEdgeHelper splitHex0Edge;
splitHex0Edge.size = 4;
splitHex0Edge.edge = splitHex0Edges;
splitHex0Edge.edgeVert = helper2d(4, splitHex0EdgeVert);
splitHex0Edge.offset = splitHex0Offset;
splitHex0Edge.inc = splitHex0Inc;
splitEdge[LibUtilities::eHexahedron][0] = splitHex0Edge;
splitEdge[LibUtilities::eHexahedron][5] = splitHex0Edge;
map<LibUtilities::ShapeType, map<int, bool> > revPoints;
revPoints[LibUtilities::ePrism][1] = false;
revPoints[LibUtilities::ePrism][3] = true;
revPoints[LibUtilities::eHexahedron][0] = true;
revPoints[LibUtilities::eHexahedron][5] = false;
// edgeMap associates geometry edge IDs to the (nl+1) vertices which
// are generated along that edge when a prism is split, and is used
// to avoid generation of duplicate vertices. It is stored as an
// unordered map for speed.
boost::unordered_map<int, vector<NodeSharedPtr> > edgeMap;
boost::unordered_map<int, vector<NodeSharedPtr> >::iterator eIt;
string surf = m_config["surf"].as<string>();
if (surf.size() > 0)
{
vector<unsigned int> surfs;
ParseUtils::GenerateSeqVector(surf.c_str(), surfs);
sort(surfs.begin(), surfs.end());
// If surface is defined, process list of elements to find those
// that are connected to it.
for (int i = 0; i < m_mesh->m_element[m_mesh->m_expDim].size(); ++i)
{
ElementSharedPtr el = m_mesh->m_element[m_mesh->m_expDim][i];
int nSurf = el->GetFaceCount();
for (int j = 0; j < nSurf; ++j)
{
int bl = el->GetBoundaryLink(j);
if (bl == -1)
{
continue;
}
ElementSharedPtr bEl = m_mesh->m_element[m_mesh->m_expDim-1][bl];
vector<int> tags = bEl->GetTagList();
vector<int> inter;
sort(tags.begin(), tags.end());
set_intersection(surfs.begin(), surfs.end(),
tags .begin(), tags .end(),
back_inserter(inter));
ASSERTL0(inter.size() <= 1,
"Intersection of surfaces wrong");
if (inter.size() == 1)
{
if (el->GetConf().m_e == LibUtilities::ePrism)
{
if (j % 2 == 0)
{
cerr << "WARNING: Found quadrilateral face "
<< j << " on surface " << surf
<< " connected to prism; ignoring."
<< endl;
continue;
}
if (splitEls.count(el->GetId()) > 0)
{
cerr << "WARNING: prism already found; "
<< "ignoring" << endl;
}
splitEls[el->GetId()] = j;
}
else if (validElTypes.count(el->GetConf().m_e) == 0)
{
cerr << "WARNING: Unsupported element type "
<< "found in surface " << j << "; "
<< "ignoring" << endl;
continue;
}
}
}
}
}
else
{
// Otherwise, add all prismatic elements and assume face 1 of
// the prism lies on the surface.
for (int i = 0; i < m_mesh->m_element[m_mesh->m_expDim].size(); ++i)
{
ElementSharedPtr el = m_mesh->m_element[m_mesh->m_expDim][i];
if (el->GetConf().m_e == LibUtilities::ePrism)
{
splitEls[el->GetId()] = 1;
}
else if (validElTypes.count(el->GetConf().m_e) > 0)
{
splitEls[el->GetId()] = 0;
}
else
{
continue;
}
}
}
if (splitEls.size() == 0)
{
cerr << "WARNING: No elements detected to split." << endl;
return;
}
// Erase all elements from the element list. Elements will be
// re-added as they are split.
vector<ElementSharedPtr> el = m_mesh->m_element[m_mesh->m_expDim];
m_mesh->m_element[m_mesh->m_expDim].clear();
// Iterate over list of elements of expansion dimension.
for (int i = 0; i < el.size(); ++i)
{
const int elId = el[i]->GetId();
sIt = splitEls.find(elId);
if (sIt == splitEls.end())
{
m_mesh->m_element[m_mesh->m_expDim].push_back(el[i]);
continue;
}
const int faceNum = sIt->second;
LibUtilities::ShapeType elType = el[i]->GetConf().m_e;
SplitMapHelper &sMap = splitMap [elType][faceNum];
SplitEdgeHelper &sEdge = splitEdge[elType][faceNum];
// Find quadrilateral boundary faces if any
std::map<int, int> bLink;
for (int j = 0; j < sMap.bfacesSize; ++j)
{
int bl = el[i]->GetBoundaryLink(sMap.bfaces[j]);
if (bl != -1)
{
bLink[sMap.bfaces[j]] = bl;
}
}
// Get elemental geometry object.
boost::dynamic_pointer_cast<SpatialDomains::Geometry3D>(
el[i]->GetGeom(m_mesh->m_spaceDim));
// Determine whether to use reverse points.
revPoints[elType][faceNum] ?
// Determine value of r based on geometry.
if(ratioIsString)
{
NekDouble x, y, z;
NekDouble x1, y1, z1;
int nverts = geom->GetNumVerts();
x = y = z = 0.0;
for(int i = 0; i < nverts; ++i)
{
geom->GetVertex(i)->GetCoords(x1,y1,z1);
x += x1; y += y1; z += z1;
}
x /= (NekDouble) nverts;
y /= (NekDouble) nverts;
z /= (NekDouble) nverts;
r = rEval.Evaluate(rExprId,x,y,z,0.0);
}
if (elType == LibUtilities::ePrism)
{
// Create basis.
LibUtilities::BasisKey B0(
LibUtilities::PointsKey(nq,pt));
LibUtilities::BasisKey B1(
LibUtilities::PointsKey(nl+1, t, r));
LibUtilities::BasisKey B2(
LibUtilities::PointsKey(nq,pt));
// Create local region.
boost::dynamic_pointer_cast<SpatialDomains::PrismGeom>(
geom);
q = MemoryManager<LocalRegions::PrismExp>::AllocateSharedPtr(
B0, B1, B2, g);
}
else if (elType == LibUtilities::eHexahedron)
{
// Create basis.
LibUtilities::BasisKey B0(
LibUtilities::PointsKey(nq,pt));
LibUtilities::BasisKey B1(
LibUtilities::PointsKey(nl+1, t, r));
// Create local region.
boost::dynamic_pointer_cast<SpatialDomains::HexGeom>(
geom);
q = MemoryManager<LocalRegions::HexExp>::AllocateSharedPtr(
B0, B0, B1, g);
}
// Grab co-ordinates.
Array<OneD, NekDouble> x(nq*nq*(nl+1));
Array<OneD, NekDouble> y(nq*nq*(nl+1));
Array<OneD, NekDouble> z(nq*nq*(nl+1));
q->GetCoords(x,y,z);
int nSplitEdge = sEdge.size;
vector<vector<NodeSharedPtr> > edgeNodes(nSplitEdge);
// Loop over edges to be split.
for (int j = 0; j < nSplitEdge; ++j)
{
int locEdge = sEdge.edge[j];
int edgeId = el[i]->GetEdge(locEdge)->m_id;
// Determine whether we have already generated vertices
// along this edge.
eIt = edgeMap.find(edgeId);
if (eIt == edgeMap.end())
{
// If not then resize storage to hold new points.
edgeNodes[j].resize(nl+1);
// Re-use existing vertices at endpoints of edge to
// avoid duplicating the existing vertices.
edgeNodes[j][0] = el[i]->GetVertex(sEdge.edgeVert[j][0]);
edgeNodes[j][nl] = el[i]->GetVertex(sEdge.edgeVert[j][1]);
// Variable geometric ratio
if(ratioIsString)
{
NekDouble x0,y0,z0;
NekDouble x1,y1,z1;
NekDouble xm,ym,zm;
// -> Find edge end and mid points
x0 = x[sEdge.offset[j]];
y0 = y[sEdge.offset[j]];
z0 = z[sEdge.offset[j]];
x1 = x[sEdge.offset[j]+nl*nq];
y1 = y[sEdge.offset[j]+nl*nq];
z1 = z[sEdge.offset[j]+nl*nq];
xm = 0.5*(x0+x1);
ym = 0.5*(y0+y1);
zm = 0.5*(z0+z1);
// evaluate r factor based on mid point value
NekDouble rnew;
rnew = rEval.Evaluate(rExprId,xm,ym,zm,0.0);
// Get basis with new r;
LibUtilities::PointsKey Pkey(nl+1, t, rnew);
const Array<OneD, const NekDouble> z = newP->GetZ();
// Create new interior nodes based on this new blend
for (int k = 1; k < nl; ++k)
{
xm = 0.5*(1+z[k])*(x1-x0) + x0;
ym = 0.5*(1+z[k])*(y1-y0) + y0;
zm = 0.5*(1+z[k])*(z1-z0) + z0;
edgeNodes[j][k] = NodeSharedPtr(
new Node(nodeId++, xm,ym,zm));
}
}
else
{
// Create new interior nodes.
for (int k = 1; k < nl; ++k)
{
int pos = sEdge.offset[j] + k*sEdge.inc[j];
edgeNodes[j][k] = NodeSharedPtr(
new Node(nodeId++, x[pos], y[pos], z[pos]));
}
}
// Store these edges in edgeMap.
edgeMap[edgeId] = edgeNodes[j];
}
else
{
edgeNodes[j] = eIt->second;
}
}
// Create element layers.
for (int j = 0; j < nl; ++j)
{
// Offset of this layer within the collapsed coordinate
// system.
int offset = j * sMap.layerOff;
// Get corner vertices.
vector<NodeSharedPtr> nodeList(sMap.size);
for (int k = 0; k < sMap.size; ++k)
{
nodeList[k] =
edgeNodes[sMap.conn[k][0]][j + sMap.conn[k][1]];
}
// Create the element.
ElmtConfig conf(elType, 1, true, true, false);
CreateInstance(
elType, conf, nodeList, el[i]->GetTagList());
// Add high order nodes to split prismatic edges.
for (int l = 0; l < sMap.size; ++l)
{
EdgeSharedPtr HOedge = elmt->GetEdge(
sMap.edge[l]);
for (int k = 1; k < nq-1; ++k)
{
int pos = offset + sMap.offset[l] + k*sMap.inc[l];
HOedge->m_edgeNodes.push_back(
new Node(nodeId++,x[pos],y[pos],z[pos])));
}
HOedge->m_curveType = pt;
}
// Change the surface elements to match the layers of
// elements on the boundary of the domain.
for (it = bLink.begin(); it != bLink.end(); ++it)
{
int fid = it->first;
int bl = it->second;
if (j == 0)
{
// For first layer reuse existing 2D element.
ElementSharedPtr e = m_mesh->m_element[m_mesh->m_expDim-1][bl];
for (int k = 0; k < 4; ++k)
{
e->SetVertex(
k, nodeList[faceNodeMap[elType][fid][k]]);
}
}
else
{
// For all other layers create new element.
vector<NodeSharedPtr> qNodeList(4);
for (int k = 0; k < 4; ++k)
{
qNodeList[k] = nodeList[faceNodeMap[elType][fid][k]];
}
vector<int> tagBE;
tagBE = m_mesh->m_element[m_mesh->m_expDim-1][bl]->GetTagList();
ElmtConfig bconf(LibUtilities::eQuadrilateral,1,true,true,false);
CreateInstance(LibUtilities::eQuadrilateral,bconf,
qNodeList,tagBE);
m_mesh->m_element[m_mesh->m_expDim-1].push_back(boundaryElmt);
}
}
m_mesh->m_element[m_mesh->m_expDim].push_back(elmt);
}
}
// Re-process mesh to eliminate duplicate vertices and edges.
}

Member Data Documentation

ModuleKey Nektar::Utilities::ProcessBL::className
static
Initial value:
"Refines a prismatic boundary layer.")

Definition at line 58 of file ProcessBL.h.