Nektar++
Public Member Functions | Static Public Member Functions | Static Public Attributes | Private Member Functions | Private Attributes | List of all members
Nektar::Utilities::InputNek Class Reference

#include <InputNek.h>

Inheritance diagram for Nektar::Utilities::InputNek:
[legend]

Public Member Functions

 InputNek (NekMeshUtils::MeshSharedPtr p_m)
 
virtual ~InputNek ()
 
virtual void Process ()
 Processes Nektar file format. More...
 
- Public Member Functions inherited from Nektar::NekMeshUtils::InputModule
NEKMESHUTILS_EXPORT InputModule (MeshSharedPtr p_m)
 
NEKMESHUTILS_EXPORT void OpenStream ()
 Open a file for input. More...
 
- Public Member Functions inherited from Nektar::NekMeshUtils::Module
NEKMESHUTILS_EXPORT Module (MeshSharedPtr p_m)
 
NEKMESHUTILS_EXPORT void RegisterConfig (std::string key, std::string value=std::string())
 Register a configuration option with a module. More...
 
NEKMESHUTILS_EXPORT void PrintConfig ()
 Print out all configuration options for a module. More...
 
NEKMESHUTILS_EXPORT void SetDefaults ()
 Sets default configuration options for those which have not been set. More...
 
NEKMESHUTILS_EXPORT MeshSharedPtr GetMesh ()
 
virtual NEKMESHUTILS_EXPORT void ProcessVertices ()
 Extract element vertices. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessEdges (bool ReprocessEdges=true)
 Extract element edges. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessFaces (bool ReprocessFaces=true)
 Extract element faces. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessElements ()
 Generate element IDs. More...
 
virtual NEKMESHUTILS_EXPORT void ProcessComposites ()
 Generate composites. More...
 
virtual NEKMESHUTILS_EXPORT void ClearElementLinks ()
 

Static Public Member Functions

static NekMeshUtils::ModuleSharedPtr create (NekMeshUtils::MeshSharedPtr m)
 Creates an instance of this class. More...
 

Static Public Attributes

static NekMeshUtils::ModuleKey className
 ModuleKey for class. More...
 

Private Member Functions

void LoadHOSurfaces ()
 
int GetNnodes (LibUtilities::ShapeType elType)
 

Private Attributes

std::map< std::string, std::pair< NekCurve, std::string > > curveTags
 
std::map< std::string, NekMeshUtils::HOSurfSethoData
 
std::map< int, int > hoMap
 

Additional Inherited Members

- Protected Member Functions inherited from Nektar::NekMeshUtils::InputModule
NEKMESHUTILS_EXPORT void PrintSummary ()
 Print summary of elements. More...
 
- Protected Member Functions inherited from Nektar::NekMeshUtils::Module
NEKMESHUTILS_EXPORT void ReorderPrisms (PerMap &perFaces)
 Reorder node IDs so that prisms and tetrahedra are aligned correctly. More...
 
NEKMESHUTILS_EXPORT void PrismLines (int prism, PerMap &perFaces, std::set< int > &prismsDone, std::vector< ElementSharedPtr > &line)
 
- Protected Attributes inherited from Nektar::NekMeshUtils::InputModule
io::filtering_istream m_mshFile
 Input stream. More...
 
std::ifstream m_mshFileStream
 Input stream. More...
 
- Protected Attributes inherited from Nektar::NekMeshUtils::Module
MeshSharedPtr m_mesh
 Mesh object. More...
 
std::map< std::string, ConfigOptionm_config
 List of configuration values. More...
 

Detailed Description

Converter class for Nektar session files.

Definition at line 59 of file InputNek.h.

Constructor & Destructor Documentation

◆ InputNek()

Nektar::Utilities::InputNek::InputNek ( NekMeshUtils::MeshSharedPtr  p_m)

Definition at line 59 of file InputNek.cpp.

References Nektar::NekMeshUtils::Module::m_config.

59  : InputModule(m)
60 {
61  m_config["scalar"] = ConfigOption(
62  true, "0", "If defined then assume input rea is for scalar problem");
63 }
Represents a command-line configuration option.
std::map< std::string, ConfigOption > m_config
List of configuration values.
NEKMESHUTILS_EXPORT InputModule(MeshSharedPtr p_m)

◆ ~InputNek()

Nektar::Utilities::InputNek::~InputNek ( )
virtual

Definition at line 65 of file InputNek.cpp.

66 {
67 }

Member Function Documentation

◆ create()

static NekMeshUtils::ModuleSharedPtr Nektar::Utilities::InputNek::create ( NekMeshUtils::MeshSharedPtr  m)
inlinestatic

Creates an instance of this class.

Definition at line 67 of file InputNek.h.

References Nektar::MemoryManager< DataType >::AllocateSharedPtr().

68  {
70  }
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.

◆ GetNnodes()

int Nektar::Utilities::InputNek::GetNnodes ( LibUtilities::ShapeType  InputNekEntity)
private

This routine aids the reading of Nektar files only; it returns the number of nodes for a given entity typw.

Definition at line 1114 of file InputNek.cpp.

References Nektar::LibUtilities::eHexahedron, Nektar::LibUtilities::ePoint, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::ePyramid, Nektar::LibUtilities::eQuadrilateral, Nektar::LibUtilities::eSegment, Nektar::LibUtilities::eTetrahedron, and Nektar::LibUtilities::eTriangle.

Referenced by Process().

1115 {
1116  int nNodes = 0;
1117 
1118  switch (InputNekEntity)
1119  {
1120  case LibUtilities::ePoint:
1121  nNodes = 1;
1122  break;
1124  nNodes = 2;
1125  break;
1127  nNodes = 3;
1128  break;
1130  nNodes = 4;
1131  break;
1133  nNodes = 4;
1134  break;
1136  nNodes = 5;
1137  break;
1138  case LibUtilities::ePrism:
1139  nNodes = 6;
1140  break;
1142  nNodes = 8;
1143  break;
1144  default:
1145  cerr << "unknown Nektar element type" << endl;
1146  }
1147 
1148  return nNodes;
1149 }

◆ LoadHOSurfaces()

void Nektar::Utilities::InputNek::LoadHOSurfaces ( )
private

Load high order surface information from hsf file.

Definition at line 950 of file InputNek.cpp.

References curveTags, Nektar::Utilities::eFile, Nektar::LibUtilities::eNodalTriElec, hoData, hoMap, Nektar::NekMeshUtils::Module::m_mesh, class_topology::Node, and Nektar::LibUtilities::PointsManager().

Referenced by Process().

951 {
952  int nodeId = m_mesh->GetNumEntities();
953 
954  for (auto &it : curveTags)
955  {
956  ifstream hsf;
957  string line, fileName = it.second.second;
958  size_t pos;
959  int N, Nface, dot;
960 
961  if (it.second.first != eFile)
962  {
963  continue;
964  }
965 
966  // Replace fro extension with hsf.
967  dot = fileName.find_last_of('.');
968  fileName = fileName.substr(0, dot);
969  fileName += ".hsf";
970 
971  // Open hsf file.
972  hsf.open(fileName.c_str());
973  if (!hsf.is_open())
974  {
975  cerr << "Could not open surface file " << fileName << endl;
976  abort();
977  }
978 
979  // Read in header line; determine element order, number of faces
980  // from this line.
981  getline(hsf, line);
982  pos = line.find("=");
983  if (pos == string::npos)
984  {
985  cerr << "hsf header error: cannot read number of "
986  << "nodal points." << endl;
987  abort();
988  }
989  line = line.substr(pos + 1);
990  stringstream ss(line);
991  ss >> N;
992 
993  pos = line.find("=");
994  if (pos == string::npos)
995  {
996  cerr << "hsf header error: cannot read number of "
997  << "faces." << endl;
998  abort();
999  }
1000  line = line.substr(pos + 1);
1001  ss.clear();
1002  ss.str(line);
1003  ss >> Nface;
1004 
1005  int Ntot = N * (N + 1) / 2;
1006 
1007  // Skip a line, then read in r,s positions inside the next
1008  // comments.
1009  Array<OneD, NekDouble> r(Ntot), s(Ntot);
1010  getline(hsf, line);
1011 
1012  for (int i = 0; i < 2; ++i)
1013  {
1014  string word;
1015 
1016  getline(hsf, line);
1017  ss.clear();
1018  ss.str(line);
1019  ss >> word;
1020 
1021  if (word != "#")
1022  {
1023  cerr << "hsf header error: cannot read in "
1024  << "r/s points" << endl;
1025  abort();
1026  }
1027 
1028  for (int j = 0; j < Ntot; ++j)
1029  {
1030  ss >> (i == 0 ? r[j] : s[j]);
1031  }
1032  }
1033 
1034  // Generate electrostatic points so that re-mapping array can
1035  // be constructed.
1036  Array<OneD, NekDouble> rp(Ntot), sp(Ntot);
1037  LibUtilities::PointsKey elec(N, LibUtilities::eNodalTriElec);
1038  LibUtilities::PointsManager()[elec]->GetPoints(rp, sp);
1039 
1040  // Expensively construct remapping array nodemap. This will
1041  // map nodal ordering from hsf order to Nektar++ ordering
1042  // (i.e. vertices followed by edges followed by interior
1043  // points.)
1044  for (int i = 0; i < Ntot; ++i)
1045  {
1046  for (int j = 0; j < Ntot; ++j)
1047  {
1048  if (fabs(r[i] - rp[j]) < 1e-5 && fabs(s[i] - sp[j]) < 1e-5)
1049  {
1050  hoMap[i] = j;
1051  break;
1052  }
1053  }
1054  }
1055 
1056  // Skip variables line
1057  getline(hsf, line);
1058 
1059  // Read in nodal points for each face.
1060  map<int, vector<NodeSharedPtr> > faceMap;
1061  for (int i = 0; i < Nface; ++i)
1062  {
1063  getline(hsf, line);
1064  vector<NodeSharedPtr> faceNodes(Ntot);
1065  for (int j = 0; j < Ntot; ++j, ++nodeId)
1066  {
1067  double x, y, z;
1068  getline(hsf, line);
1069  ss.clear();
1070  ss.str(line);
1071  ss >> x >> y >> z;
1072  faceNodes[j] = NodeSharedPtr(new Node(nodeId, x, y, z));
1073  }
1074  // Skip over tecplot connectivity information.
1075  for (int j = 0; j < (N - 1) * (N - 1); ++j)
1076  {
1077  getline(hsf, line);
1078  }
1079  faceMap[i] = faceNodes;
1080  }
1081 
1082  // Finally, read in connectivity information to set up after
1083  // reading rea file.
1084  getline(hsf, line);
1085  for (int i = 0; i < Nface; ++i)
1086  {
1087  string tmp;
1088  int fid;
1089  vector<int> nodeIds(3);
1090 
1091  getline(hsf, line);
1092  ss.clear();
1093  ss.str(line);
1094  ss >> tmp >> fid >> nodeIds[0] >> nodeIds[1] >> nodeIds[2];
1095 
1096  if (tmp != "#")
1097  {
1098  cerr << "Unable to read hsf connectivity information." << endl;
1099  abort();
1100  }
1101 
1102  hoData[it.first].insert(
1103  HOSurfSharedPtr(new HOSurf(nodeIds, faceMap[i])));
1104  }
1105 
1106  hsf.close();
1107  }
1108 }
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
std::map< int, int > hoMap
Definition: InputNek.h:91
std::map< std::string, NekMeshUtils::HOSurfSet > hoData
Definition: InputNek.h:86
PointsManagerT & PointsManager(void)
std::map< std::string, std::pair< NekCurve, std::string > > curveTags
Definition: InputNek.h:81
std::shared_ptr< HOSurf > HOSurfSharedPtr
Definition: HOAlignment.h:180
HOTriangle< NodeSharedPtr > HOSurf
Definition: HOAlignment.h:179
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:69

◆ Process()

void Nektar::Utilities::InputNek::Process ( )
virtual

Processes Nektar file format.

Nektar sessions are defined by rea files, and contain sections defining a DNS simulation in a specific order. The converter only reads mesh information, curve information if it exists and boundary information.

Parameters
pFilenameFilename of Nektar session file to read.

Implements Nektar::NekMeshUtils::Module.

Definition at line 78 of file InputNek.cpp.

References Nektar::MemoryManager< DataType >::AllocateSharedPtr(), Nektar::LibUtilities::NekFactory< tKey, tBase, tParam >::CreateInstance(), curveTags, Nektar::SpatialDomains::eDirichlet, Nektar::Utilities::eFile, Nektar::LibUtilities::eGaussLobattoLegendre, Nektar::LibUtilities::eHexahedron, Nektar::NekMeshUtils::eHOPCondition, Nektar::SpatialDomains::eNeumann, Nektar::LibUtilities::eNodalTriElec, Nektar::LibUtilities::ePrism, Nektar::LibUtilities::ePyramid, Nektar::LibUtilities::eQuadrilateral, Nektar::Utilities::eRecon, Nektar::LibUtilities::eSegment, Nektar::LibUtilities::eTetrahedron, Nektar::LibUtilities::eTriangle, Nektar::NekMeshUtils::GetElementFactory(), GetNnodes(), Nektar::NekMeshUtils::Element::GetVertex(), hoData, hoMap, LoadHOSurfaces(), Nektar::NekMeshUtils::Module::m_config, Nektar::NekMeshUtils::Module::m_mesh, Nektar::NekMeshUtils::InputModule::m_mshFile, Nektar::NekMeshUtils::Tetrahedron::m_orientationMap, class_topology::Node, Nektar::NekMeshUtils::InputModule::OpenStream(), CellMLToNektar.cellml_metadata::p, Nektar::NekMeshUtils::Module::ProcessComposites(), Nektar::NekMeshUtils::Module::ProcessEdges(), Nektar::NekMeshUtils::Module::ProcessElements(), and Nektar::NekMeshUtils::Module::ProcessFaces().

79 {
80  // Open the file stream.
81  OpenStream();
82 
83  string line, word;
84  int nParam, nElements, nCurves;
85  int i, j, k, nodeCounter = 0;
86  int nComposite = 0;
88  double vertex[3][8];
89  map<LibUtilities::ShapeType, int> domainComposite;
90  map<LibUtilities::ShapeType, vector<vector<NodeSharedPtr> > > elNodes;
91  map<LibUtilities::ShapeType, vector<int> > elIds;
92  std::unordered_map<int, int> elMap;
93  vector<LibUtilities::ShapeType> elmOrder;
94 
95  bool scalar = m_config["scalar"].as<bool>();
96 
97  // Set up vector of processing orders.
98  elmOrder.push_back(LibUtilities::eSegment);
99  elmOrder.push_back(LibUtilities::eTriangle);
100  elmOrder.push_back(LibUtilities::eQuadrilateral);
101  elmOrder.push_back(LibUtilities::ePrism);
102  elmOrder.push_back(LibUtilities::ePyramid);
103  elmOrder.push_back(LibUtilities::eTetrahedron);
104  elmOrder.push_back(LibUtilities::eHexahedron);
105 
106  m_mesh->m_expDim = 0;
107  m_mesh->m_spaceDim = 0;
108 
109  if (m_mesh->m_verbose)
110  {
111  cout << "InputNek: Start reading file..." << endl;
112  }
113 
114  // -- Read in parameters.
115 
116  // Ignore first 3 lines. 4th line contains number of parameters.
117  for (i = 0; i < 4; ++i)
118  {
119  getline(m_mshFile, line);
120  }
121 
122  stringstream s(line);
123  s >> nParam;
124 
125  for (i = 0; i < nParam; ++i)
126  {
127  string tmp1, tmp2;
128  getline(m_mshFile, line);
129  s.str(line);
130  s >> tmp1 >> tmp2;
131  }
132 
133  // -- Read in passive scalars (ignore)
134  getline(m_mshFile, line);
135  s.clear();
136  s.str(line);
137  s >> j;
138  for (i = 0; i < j; ++i)
139  {
140  getline(m_mshFile, line);
141  }
142 
143  // -- Read in logical switches (ignore)
144  getline(m_mshFile, line);
145  s.clear();
146  s.str(line);
147  s >> j;
148  for (i = 0; i < j; ++i)
149  {
150  getline(m_mshFile, line);
151  }
152 
153  // -- Read in mesh data.
154 
155  // First hunt for MESH tag
156  bool foundMesh = false;
157  while (!m_mshFile.eof())
158  {
159  getline(m_mshFile, line);
160  if (line.find("MESH") != string::npos)
161  {
162  foundMesh = true;
163  break;
164  }
165  }
166 
167  if (!foundMesh)
168  {
169  cerr << "Couldn't find MESH tag inside file." << endl;
170  abort();
171  }
172 
173  // Now read in number of elements and space dimension.
174  getline(m_mshFile, line);
175  s.clear();
176  s.str(line);
177  s >> nElements >> m_mesh->m_expDim;
178  m_mesh->m_spaceDim = m_mesh->m_expDim;
179 
180  // Set up field names.
181  m_mesh->m_fields.push_back("u");
182 
183  if (!scalar)
184  {
185  m_mesh->m_fields.push_back("v");
186  if (m_mesh->m_spaceDim > 2)
187  {
188  m_mesh->m_fields.push_back("w");
189  }
190  m_mesh->m_fields.push_back("p");
191  }
192 
193  // Loop over and create elements.
194  for (i = 0; i < nElements; ++i)
195  {
196  getline(m_mshFile, line);
197 
198  if (m_mesh->m_expDim == 2)
199  {
200  if (line.find("Qua") != string::npos ||
201  line.find("qua") != string::npos)
202  {
204  }
205  else
206  {
207  // Default element type in 2D is triangle.
208  elType = LibUtilities::eTriangle;
209  }
210  }
211  else
212  {
213  if (line.find("Tet") != string::npos ||
214  line.find("tet") != string::npos)
215  {
217  }
218  else if (line.find("Hex") != string::npos ||
219  line.find("hex") != string::npos)
220  {
221  elType = LibUtilities::eHexahedron;
222  }
223  else if (line.find("Prism") != string::npos ||
224  line.find("prism") != string::npos)
225  {
226  elType = LibUtilities::ePrism;
227  }
228  else if (line.find("Pyr") != string::npos ||
229  line.find("pyr") != string::npos)
230  {
231  elType = LibUtilities::ePyramid;
232  }
233  else if (line.find("Qua") != string::npos ||
234  line.find("qua") != string::npos)
235  {
237  }
238  else
239  {
240  // Default element type in 2D is tetrahedron.
242  }
243  }
244 
245  // Read in number of vertices for element type.
246  const int nNodes = GetNnodes(elType);
247 
248  for (j = 0; j < m_mesh->m_expDim; ++j)
249  {
250  getline(m_mshFile, line);
251  s.clear();
252  s.str(line);
253  for (k = 0; k < nNodes; ++k)
254  {
255  s >> vertex[j][k];
256  }
257  }
258 
259  // Zero co-ordinates bigger than expansion dimension.
260  for (j = m_mesh->m_expDim; j < 3; ++j)
261  {
262  for (k = 0; k < nNodes; ++k)
263  {
264  vertex[j][k] = 0.0;
265  }
266  }
267 
268  // Nektar meshes do not contain a unique list of nodes, so this
269  // block constructs a unique set so that elements can be created
270  // with unique nodes.
271  vector<NodeSharedPtr> nodeList;
272  for (k = 0; k < nNodes; ++k)
273  {
274  NodeSharedPtr n = std::shared_ptr<Node>(new Node(
275  nodeCounter++, vertex[0][k], vertex[1][k], vertex[2][k]));
276  nodeList.push_back(n);
277  }
278 
279  elNodes[elType].push_back(nodeList);
280  elIds[elType].push_back(i);
281  }
282 
283  int reorderedId = 0;
284  nodeCounter = 0;
285 
286  for (i = 0; i < elmOrder.size(); ++i)
287  {
288  LibUtilities::ShapeType elType = elmOrder[i];
289  vector<vector<NodeSharedPtr> > &tmp = elNodes[elType];
290 
291  for (j = 0; j < tmp.size(); ++j)
292  {
293  vector<int> tags;
294  auto compIt = domainComposite.find(elType);
295  if (compIt == domainComposite.end())
296  {
297  tags.push_back(nComposite);
298  domainComposite[elType] = nComposite;
299  nComposite++;
300  }
301  else
302  {
303  tags.push_back(compIt->second);
304  }
305 
306  elMap[elIds[elType][j]] = reorderedId++;
307 
308  vector<NodeSharedPtr> nodeList = tmp[j];
309 
310  for (k = 0; k < nodeList.size(); ++k)
311  {
312  auto testIns = m_mesh->m_vertexSet.insert(nodeList[k]);
313 
314  if (!testIns.second)
315  {
316  nodeList[k] = *(testIns.first);
317  }
318  else
319  {
320  nodeList[k]->m_id = nodeCounter++;
321  }
322  }
323 
324  // Create linear element
325  ElmtConfig conf(elType, 1, false, false);
327  elType, conf, nodeList, tags);
328  m_mesh->m_element[E->GetDim()].push_back(E);
329  }
330  }
331 
332  // -- Read in curved data.
333  getline(m_mshFile, line);
334  if (line.find("CURVE") == string::npos)
335  {
336  cerr << "Cannot find curved side data." << endl;
337  abort();
338  }
339 
340  // Read number of curves.
341  getline(m_mshFile, line);
342  s.clear();
343  s.str(line);
344  s >> nCurves;
345 
346  if (nCurves > 0)
347  {
348  string curveTag;
349 
350  for (i = 0; i < nCurves; ++i)
351  {
352  getline(m_mshFile, line);
353  s.clear();
354  s.str(line);
355  s >> word;
356 
357  if (word == "File")
358  {
359  // Next line contains filename and curve tag.
360  getline(m_mshFile, line);
361  s.clear();
362  s.str(line);
363  s >> word >> curveTag;
364  curveTags[curveTag] = make_pair(eFile, word);
365  }
366  else if (word == "Recon")
367  {
368  // Next line contains curve tag.
369  getline(m_mshFile, line);
370  s.clear();
371  s.str(line);
372  s >> word >> curveTag;
373  curveTags[curveTag] = make_pair(eRecon, word);
374  }
375  else
376  {
377  cerr << "Unsupported curve type " << word << endl;
378  abort();
379  }
380  }
381 
382  // Load high order surface information.
383  LoadHOSurfaces();
384 
385  // Read in curve information. First line should contain number
386  // of curved sides.
387  getline(m_mshFile, line);
388 
389  if (line.find("side") == string::npos)
390  {
391  cerr << "Unable to read number of curved sides" << endl;
392  abort();
393  }
394 
395  int nCurvedSides;
396  int faceId, elId;
397 
398  s.clear();
399  s.str(line);
400  s >> nCurvedSides;
401 
402  // Iterate over curved sides, and look up high-order surface
403  // information in the HOSurfSet, then map this onto faces.
404  for (i = 0; i < nCurvedSides; ++i)
405  {
406  getline(m_mshFile, line);
407  s.clear();
408  s.str(line);
409  s >> faceId >> elId >> word;
410  faceId--;
411  elId = elMap[elId - 1];
412  ElementSharedPtr el = m_mesh->m_element[m_mesh->m_expDim][elId];
413 
414  int origFaceId = faceId;
415 
416  if (el->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 0)
417  {
418  std::shared_ptr<Prism> p =
419  std::dynamic_pointer_cast<Prism>(el);
420  if (p->m_orientation == 1)
421  {
422  faceId = (faceId + 2) % 6;
423  }
424  else if (p->m_orientation == 2)
425  {
426  faceId = (faceId + 4) % 6;
427  }
428  }
429  else if (el->GetConf().m_e == LibUtilities::eTetrahedron)
430  {
431  std::shared_ptr<Tetrahedron> t =
432  std::dynamic_pointer_cast<Tetrahedron>(el);
433  faceId = t->m_orientationMap[faceId];
434  }
435 
436  auto it = curveTags.find(word);
437  if (it == curveTags.end())
438  {
439  cerr << "Unrecognised curve tag " << word << " in curved lines"
440  << endl;
441  abort();
442  }
443 
444  if (it->second.first == eRecon)
445  {
446  // Spherigon information: read in vertex normals.
447  vector<NodeSharedPtr> &tmp = el->GetFace(faceId)->m_vertexList;
448  vector<Node> n(tmp.size());
449 
450  int offset = 0;
451  if (el->GetConf().m_e == LibUtilities::ePrism &&
452  faceId % 2 == 1)
453  {
454  offset =
455  std::dynamic_pointer_cast<Prism>(el)->m_orientation;
456  }
457 
458  // Read x/y/z coordinates.
459  getline(m_mshFile, line);
460  s.clear();
461  s.str(line);
462  for (j = 0; j < tmp.size(); ++j)
463  {
464  s >> n[j].m_x;
465  }
466 
467  getline(m_mshFile, line);
468  s.clear();
469  s.str(line);
470  for (j = 0; j < tmp.size(); ++j)
471  {
472  s >> n[j].m_y;
473  }
474 
475  getline(m_mshFile, line);
476  s.clear();
477  s.str(line);
478  for (j = 0; j < tmp.size(); ++j)
479  {
480  s >> n[j].m_z;
481  }
482 
483  for (j = 0; j < tmp.size(); ++j)
484  {
485  int id = tmp[(j + offset) % tmp.size()]->m_id;
486  auto vIt = m_mesh->m_vertexNormals.find(id);
487 
488  if (vIt == m_mesh->m_vertexNormals.end())
489  {
490  m_mesh->m_vertexNormals[id] = n[j];
491  }
492  }
493 
494  // Add edge/face to list of faces to apply spherigons
495  // to.
496  m_mesh->m_spherigonSurfs.insert(make_pair(elId, faceId));
497  }
498  else if (it->second.first == eFile)
499  {
500  FaceSharedPtr f = el->GetFace(faceId);
501  static int tetFaceVerts[4][3] = {
502  {0, 1, 2}, {0, 1, 3}, {1, 2, 3}, {0, 2, 3}};
503 
504  vector<int> vertId(3);
505  s >> vertId[0] >> vertId[1] >> vertId[2];
506 
507  // Prisms and tets may have been rotated by OrientPrism
508  // routine which reorders vertices. This block rotates
509  // vertex ids accordingly.
510  if (el->GetConf().m_e == LibUtilities::eTetrahedron)
511  {
512  std::shared_ptr<Tetrahedron> tet =
513  std::static_pointer_cast<Tetrahedron>(el);
514  vector<int> tmpVertId = vertId;
515 
516  for (j = 0; j < 3; ++j)
517  {
518  int v =
519  tet->GetVertex(tet->m_origVertMap
520  [tetFaceVerts[origFaceId][j]])
521  ->m_id;
522 
523  for (k = 0; k < 3; ++k)
524  {
525  int w = f->m_vertexList[k]->m_id;
526  if (v == w)
527  {
528  vertId[k] = tmpVertId[j];
529  break;
530  }
531  }
532  }
533  }
534  else if (el->GetConf().m_e == LibUtilities::ePrism)
535  {
536  std::shared_ptr<Prism> pr =
537  std::static_pointer_cast<Prism>(el);
538  if (pr->m_orientation == 1)
539  {
540  swap(vertId[2], vertId[1]);
541  swap(vertId[0], vertId[1]);
542  }
543  else if (pr->m_orientation == 2)
544  {
545  swap(vertId[0], vertId[1]);
546  swap(vertId[2], vertId[1]);
547  }
548  }
549 
550  HOSurfSharedPtr hs =
551  std::shared_ptr<HOSurf>(new HOSurf(vertId));
552  // Find vertex combination in hoData.
553  auto hoIt = hoData[word].find(hs);
554 
555  if (hoIt == hoData[word].end())
556  {
557  cerr << "Unable to find high-order surface data "
558  << "for element id " << elId + 1 << endl;
559  abort();
560  }
561 
562  // Depending on order of vertices in rea file, surface
563  // information may need to be rotated or reflected.
564  HOSurfSharedPtr surf = *hoIt;
565  surf->Align(vertId);
566 
567  // Finally, add high order data to appropriate face.
568  int Ntot = (*hoIt)->surfVerts.size();
569  int N = ((int)sqrt(8.0 * Ntot + 1.0) - 1) / 2;
570  EdgeSharedPtr edge;
571 
572  // Apply high-order map to convert face data to Nektar++
573  // ordering (vertices->edges->internal).
574  vector<NodeSharedPtr> tmpVerts = (*hoIt)->surfVerts;
575  for (j = 0; j < tmpVerts.size(); ++j)
576  {
577  (*hoIt)->surfVerts[hoMap[j]] = tmpVerts[j];
578  }
579 
580  for (j = 0; j < tmpVerts.size(); ++j)
581  {
582  NodeSharedPtr a = (*hoIt)->surfVerts[j];
583  }
584 
585  vector<int> faceVertIds(3);
586  faceVertIds[0] = f->m_vertexList[0]->m_id;
587  faceVertIds[1] = f->m_vertexList[1]->m_id;
588  faceVertIds[2] = f->m_vertexList[2]->m_id;
589 
590  for (j = 0; j < f->m_edgeList.size(); ++j)
591  {
592  edge = f->m_edgeList[j];
593 
594  // Skip over edges which have already been
595  // populated.
596  if (edge->m_edgeNodes.size() > 0)
597  {
598  continue;
599  }
600 
601  // edge->m_edgeNodes.clear();
602  edge->m_curveType = LibUtilities::eGaussLobattoLegendre;
603 
604  for (int k = 0; k < N - 2; ++k)
605  {
606  edge->m_edgeNodes.push_back(
607  (*hoIt)->surfVerts[3 + j * (N - 2) + k]);
608  }
609 
610  // Nodal triangle data is always
611  // counter-clockwise. Add this check to reorder
612  // where necessary.
613  if (edge->m_n1->m_id != faceVertIds[j])
614  {
615  reverse(edge->m_edgeNodes.begin(),
616  edge->m_edgeNodes.end());
617  }
618  }
619 
620  // Insert interior face curvature.
621  f->m_curveType = LibUtilities::eNodalTriElec;
622  for (int j = 3 + 3 * (N - 2); j < Ntot; ++j)
623  {
624  f->m_faceNodes.push_back((*hoIt)->surfVerts[j]);
625  }
626  }
627  }
628  }
629 
630  // -- Process fluid boundary conditions.
631 
632  // Define a fairly horrendous map: key is the condition ID, the
633  // value is a vector of pairs of composites and element
634  // types. Essentially this map takes conditions -> composites for
635  // each element type.
636  map<int, vector<pair<int, LibUtilities::ShapeType> > > surfaceCompMap;
637 
638  // Skip boundary conditions line.
639  getline(m_mshFile, line);
640  getline(m_mshFile, line);
641 
642  int nSurfaces = 0;
643 
644  while (true)
645  {
646  getline(m_mshFile, line);
647 
648  // Break out of loop at end of boundary conditions section.
649  if (line.find("*") != string::npos || m_mshFile.eof() ||
650  line.length() == 0)
651  {
652  break;
653  }
654 
655  // Read boundary type, element ID and face ID.
656  char bcType;
657  int elId, faceId;
658  s.clear();
659  s.str(line);
660  s >> bcType >> elId >> faceId;
661  faceId--;
662  elId = elMap[elId - 1];
663 
664  vector<string> vals;
665  vector<ConditionType> type;
667 
668  ElementSharedPtr elm = m_mesh->m_element[m_mesh->m_spaceDim][elId];
669 
670  // Ignore BCs for undefined edges/faces
671  if ((elm->GetDim() == 2 && faceId >= elm->GetEdgeCount()) ||
672  (elm->GetDim() == 3 && faceId >= elm->GetFaceCount()))
673  {
674  continue;
675  }
676 
677  // First character on each line describes type of BC. Currently
678  // only support V, W, and O. In this switch statement we
679  // construct the quantities needed to search for the condition.
680  switch (bcType)
681  {
682  // Wall boundary.
683  case 'W':
684  {
685  if (scalar)
686  {
687  vals.push_back("0");
688  type.push_back(eDirichlet);
689  }
690  else
691  {
692  for (i = 0; i < m_mesh->m_fields.size() - 1; ++i)
693  {
694  vals.push_back("0");
695  type.push_back(eDirichlet);
696  }
697  // Set high-order boundary condition for wall.
698  vals.push_back("0");
699  type.push_back(eHOPCondition);
700  }
701  break;
702  }
703 
704  // Velocity boundary condition (either constant or dependent
705  // upon x,y,z).
706  case 'V':
707  case 'v':
708  {
709  if (scalar)
710  {
711  getline(m_mshFile, line);
712  size_t p = line.find_first_of('=');
713  vals.push_back(
714  boost::algorithm::trim_copy(line.substr(p + 1)));
715  type.push_back(eDirichlet);
716  }
717  else
718  {
719  for (i = 0; i < m_mesh->m_fields.size() - 1; ++i)
720  {
721  getline(m_mshFile, line);
722  size_t p = line.find_first_of('=');
723  vals.push_back(
724  boost::algorithm::trim_copy(line.substr(p + 1)));
725  type.push_back(eDirichlet);
726  }
727  // Set high-order boundary condition for Dirichlet
728  // condition.
729  vals.push_back("0");
730  type.push_back(eHOPCondition);
731  }
732  break;
733  }
734 
735  // Natural outflow condition (default value = 0.0?)
736  case 'O':
737  {
738  if (scalar)
739  {
740  vals.push_back("0");
741  type.push_back(eNeumann);
742  }
743  else
744  {
745  for (i = 0; i < m_mesh->m_fields.size(); ++i)
746  {
747  vals.push_back("0");
748  type.push_back(eNeumann);
749  }
750  // Set zero Dirichlet condition for outflow.
751  type[m_mesh->m_fields.size() - 1] = eDirichlet;
752  }
753  break;
754  }
755 
756  // Ignore unsupported BCs
757  case 'P':
758  case 'E':
759  case 'F':
760  case 'f':
761  case 'N':
762  continue;
763  break;
764 
765  default:
766  cerr << "Unknown boundary condition type " << line[0] << endl;
767  abort();
768  }
769 
770  // Populate condition information.
771  c->field = m_mesh->m_fields;
772  c->type = type;
773  c->value = vals;
774 
775  // Now attempt to find this boundary condition inside
776  // m_mesh->condition. This is currently a linear search and should
777  // probably be made faster!
778  bool found = false;
779  auto it = m_mesh->m_condition.begin();
780  for (; it != m_mesh->m_condition.end(); ++it)
781  {
782  if (c == it->second)
783  {
784  found = true;
785  break;
786  }
787  }
788 
789  int compTag, conditionId;
790  ElementSharedPtr surfEl;
791 
792  // Create element for face (3D) or segment (2D). At the moment
793  // this is a bit of a hack since high-order nodes are not
794  // copied, so some output modules (e.g. Gmsh) will not output
795  // correctly.
796  if (elm->GetDim() == 3)
797  {
798  // 3D elements may have been reoriented, so face IDs will
799  // change.
800  if (elm->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 0)
801  {
802  std::shared_ptr<Prism> p =
803  std::dynamic_pointer_cast<Prism>(elm);
804  if (p->m_orientation == 1)
805  {
806  faceId = (faceId + 2) % 6;
807  }
808  else if (p->m_orientation == 2)
809  {
810  faceId = (faceId + 4) % 6;
811  }
812  }
813  else if (elm->GetConf().m_e == LibUtilities::eTetrahedron)
814  {
815  std::shared_ptr<Tetrahedron> t =
816  std::dynamic_pointer_cast<Tetrahedron>(elm);
817  faceId = t->m_orientationMap[faceId];
818  }
819 
820  FaceSharedPtr f = elm->GetFace(faceId);
821  bool tri = f->m_vertexList.size() == 3;
822 
823  vector<NodeSharedPtr> nodeList;
824  nodeList.insert(nodeList.begin(),
825  f->m_vertexList.begin(),
826  f->m_vertexList.end());
827 
828  vector<int> tags;
829 
832  ElmtConfig conf(
833  seg, 1, true, true, false, LibUtilities::eGaussLobattoLegendre);
834  surfEl =
835  GetElementFactory().CreateInstance(seg, conf, nodeList, tags);
836 
837  // Copy high-order surface information from edges.
838  for (int i = 0; i < f->m_vertexList.size(); ++i)
839  {
840  surfEl->GetEdge(i)->m_edgeNodes = f->m_edgeList[i]->m_edgeNodes;
841  surfEl->GetEdge(i)->m_curveType = f->m_edgeList[i]->m_curveType;
842  }
843  }
844  else if (faceId < elm->GetEdgeCount())
845  {
846  EdgeSharedPtr f = elm->GetEdge(faceId);
847 
848  vector<NodeSharedPtr> nodeList;
849  nodeList.push_back(f->m_n1);
850  nodeList.push_back(f->m_n2);
851 
852  vector<int> tags;
853 
855  1,
856  true,
857  true,
858  false,
861  LibUtilities::eSegment, conf, nodeList, tags);
862  }
863 
864  if (!surfEl)
865  {
866  continue;
867  }
868 
869  LibUtilities::ShapeType surfElType = surfEl->GetConf().m_e;
870 
871  if (!found)
872  {
873  // If condition does not already exist, add to condition
874  // list, create new composite tag and put inside
875  // surfaceCompMap.
876  conditionId = m_mesh->m_condition.size();
877  compTag = nComposite;
878  c->m_composite.push_back(compTag);
879  m_mesh->m_condition[conditionId] = c;
880 
881  surfaceCompMap[conditionId].push_back(
882  pair<int, LibUtilities::ShapeType>(nComposite, surfElType));
883 
884  nComposite++;
885  }
886  else
887  {
888  // Otherwise find existing composite inside surfaceCompMap.
889  auto it2 = surfaceCompMap.find(it->first);
890 
891  found = false;
892  if (it2 == surfaceCompMap.end())
893  {
894  // This should never happen!
895  cerr << "Unable to find condition!" << endl;
896  abort();
897  }
898 
899  for (j = 0; j < it2->second.size(); ++j)
900  {
901  pair<int, LibUtilities::ShapeType> tmp = it2->second[j];
902  if (tmp.second == surfElType)
903  {
904  found = true;
905  compTag = tmp.first;
906  break;
907  }
908  }
909 
910  // If no pairs were found, then this condition contains
911  // multiple element types (i.e. both triangles and
912  // quads). Create another composite for the new shape type
913  // and insert into the map.
914  if (!found)
915  {
916  it2->second.push_back(
917  pair<int, LibUtilities::ShapeType>(nComposite, surfElType));
918  compTag = nComposite;
919  m_mesh->m_condition[it->first]->m_composite.push_back(compTag);
920  nComposite++;
921  }
922 
923  conditionId = it->first;
924  }
925 
926  // Insert composite tag into element and insert element into
927  // mesh.
928  vector<int> existingTags = surfEl->GetTagList();
929 
930  existingTags.insert(existingTags.begin(), compTag);
931  surfEl->SetTagList(existingTags);
932  surfEl->SetId(nSurfaces);
933 
934  m_mesh->m_element[surfEl->GetDim()].push_back(surfEl);
935  nSurfaces++;
936  }
937 
938  m_mshFile.reset();
939 
940  // -- Process rest of mesh.
941  ProcessEdges();
942  ProcessFaces();
943  ProcessElements();
945 }
A 3-dimensional four-faced element.
Definition: Tetrahedron.h:49
Basic information about an element.
Definition: ElementConfig.h:49
io::filtering_istream m_mshFile
Input stream.
A 3-dimensional five-faced element (2 triangles, 3 quadrilaterals).
Definition: Prism.h:49
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
std::shared_ptr< Face > FaceSharedPtr
Definition: Face.h:155
std::map< int, int > hoMap
Definition: InputNek.h:91
NEKMESHUTILS_EXPORT void OpenStream()
Open a file for input.
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::map< std::string, NekMeshUtils::HOSurfSet > hoData
Definition: InputNek.h:86
virtual NEKMESHUTILS_EXPORT void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
NEKMESHUTILS_EXPORT NodeSharedPtr GetVertex(unsigned int i) const
Access a vertex node.
Definition: Element.h:101
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
virtual NEKMESHUTILS_EXPORT void ProcessElements()
Generate element IDs.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
std::map< std::string, ConfigOption > m_config
List of configuration values.
int GetNnodes(LibUtilities::ShapeType elType)
Definition: InputNek.cpp:1114
std::map< std::string, std::pair< NekCurve, std::string > > curveTags
Definition: InputNek.h:81
virtual NEKMESHUTILS_EXPORT void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
std::shared_ptr< HOSurf > HOSurfSharedPtr
Definition: HOAlignment.h:180
HOTriangle< NodeSharedPtr > HOSurf
Definition: HOAlignment.h:179
std::shared_ptr< Condition > ConditionSharedPtr
Definition: Mesh.h:85
virtual NEKMESHUTILS_EXPORT void ProcessComposites()
Generate composites.
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:51
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:69

Member Data Documentation

◆ className

ModuleKey Nektar::Utilities::InputNek::className
static
Initial value:

ModuleKey for class.

Definition at line 72 of file InputNek.h.

◆ curveTags

std::map<std::string, std::pair<NekCurve, std::string> > Nektar::Utilities::InputNek::curveTags
private

Maps a curve tag to a filename containing surface information.

Definition at line 81 of file InputNek.h.

Referenced by LoadHOSurfaces(), and Process().

◆ hoData

std::map<std::string, NekMeshUtils::HOSurfSet> Nektar::Utilities::InputNek::hoData
private

Maps a curve tag to the high-order surface data for that tag.

Definition at line 86 of file InputNek.h.

Referenced by LoadHOSurfaces(), and Process().

◆ hoMap

std::map<int, int> Nektar::Utilities::InputNek::hoMap
private

Maps ordering of hsf standard element to Nektar++ ordering.

Definition at line 91 of file InputNek.h.

Referenced by LoadHOSurfaces(), and Process().