Nektar++
InputNek.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: InputNek.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Nektar file format converter.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <map>
36 #include <vector>
37 #include <sstream>
38 #include <string>
39 
40 #include <boost/algorithm/string.hpp>
45 
46 #include "InputNek.h"
47 
48 using namespace std;
49 using namespace Nektar::NekMeshUtils;
50 
51 namespace Nektar
52 {
53 namespace Utilities
54 {
55 
56 ModuleKey InputNek::className = GetModuleFactory().RegisterCreatorFunction(
57  ModuleKey(eInputModule, "rea"), InputNek::create, "Reads Nektar rea file.");
58 
59 InputNek::InputNek(MeshSharedPtr m) : InputModule(m)
60 {
61  m_config["scalar"] = ConfigOption(
62  true, "0", "If defined then assume input rea is for scalar problem");
63 }
64 
66 {
67 }
68 
69 /**
70  * @brief Processes Nektar file format.
71  *
72  * Nektar sessions are defined by rea files, and contain sections defining a DNS
73  * simulation in a specific order. The converter only reads mesh information,
74  * curve information if it exists and boundary information.
75  *
76  * @param pFilename Filename of Nektar session file to read.
77  */
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 }
946 
947 /**
948  * Load high order surface information from hsf file.
949  */
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);
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 }
1109 
1110 /**
1111  * This routine aids the reading of Nektar files only; it returns the
1112  * number of nodes for a given entity typw.
1113  */
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 }
1150 }
1151 }
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
STL namespace.
std::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: Edge.h:136
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
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
std::pair< ModuleType, std::string > ModuleKey
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.
Represents a command-line configuration option.
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
PointsManagerT & PointsManager(void)
Defines a specification for a set of points.
Definition: Points.h:59
std::map< std::string, ConfigOption > m_config
List of configuration values.
virtual void Process()
Processes Nektar file format.
Definition: InputNek.cpp:78
Abstract base class for input modules.
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
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
std::pair< ModuleType, std::string > ModuleKey
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
ModuleFactory & GetModuleFactory()