Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 // License for the specific language governing rights and limitations under
14 // Permission is hereby granted, free of charge, to any person obtaining a
15 // copy of this software and associated documentation files (the "Software"),
16 // to deal in the Software without restriction, including without limitation
17 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
18 // and/or sell copies of the Software, and to permit persons to whom the
19 // Software is furnished to do so, subject to the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be included
22 // in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
27 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30 // DEALINGS IN THE SOFTWARE.
31 //
32 // Description: Nektar file format converter.
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 #include "MeshElements.h"
37 #include "InputNek.h"
38 
40 #include <boost/algorithm/string.hpp>
41 
42 #include <map>
43 #include <vector>
44 #include <sstream>
45 #include <string>
46 using namespace std;
47 
48 namespace Nektar
49 {
50  namespace Utilities
51  {
52  ModuleKey InputNek::className =
54  ModuleKey(eInputModule, "rea"), InputNek::create,
55  "Reads Nektar rea file.");
56 
57  InputNek::InputNek(MeshSharedPtr m) : InputModule(m)
58  {
59 
60  }
61 
63  {
64 
65  }
66 
67  /**
68  * @brief Processes Nektar file format.
69  *
70  * Nektar sessions are defined by rea files, and contain sections
71  * defining a DNS simulation in a specific order. The converter only
72  * reads mesh information, curve information if it exists and boundary
73  * information.
74  *
75  * @param pFilename Filename of Nektar session file to read.
76  */
78  {
79  // Open the file stream.
80  OpenStream();
81 
82  string line, word;
83  int nParam, nElements, nCurves;
84  int i, j, k, nodeCounter = 0;
85  int nComposite = 0;
87  double vertex[3][8];
88  map<LibUtilities::ShapeType,int> domainComposite;
89  map<LibUtilities::ShapeType,vector< vector<NodeSharedPtr> > > elNodes;
90  map<LibUtilities::ShapeType,vector<int> > elIds;
91  boost::unordered_map<int,int> elMap;
92  vector<LibUtilities::ShapeType> elmOrder;
93 
94  // Set up vector of processing orders.
95  elmOrder.push_back(LibUtilities::eSegment);
96  elmOrder.push_back(LibUtilities::eTriangle);
97  elmOrder.push_back(LibUtilities::eQuadrilateral);
98  elmOrder.push_back(LibUtilities::ePrism);
99  elmOrder.push_back(LibUtilities::ePyramid);
100  elmOrder.push_back(LibUtilities::eTetrahedron);
101  elmOrder.push_back(LibUtilities::eHexahedron);
102 
103  m_mesh->m_expDim = 0;
104  m_mesh->m_spaceDim = 0;
105 
106  if (m_mesh->m_verbose)
107  {
108  cout << "InputNek: Start reading file..." << endl;
109  }
110 
111  // -- Read in parameters.
112 
113  // Ignore first 3 lines. 4th line contains number of parameters.
114  for (i = 0; i < 4; ++i)
115  {
116  getline(m_mshFile, line);
117  }
118 
119  stringstream s(line);
120  s >> nParam;
121 
122  for (i = 0; i < nParam; ++i)
123  {
124  string tmp1, tmp2;
125  getline(m_mshFile, line);
126  s.str(line);
127  s >> tmp1 >> tmp2;
128  }
129 
130  // -- Read in passive scalars (ignore)
131  getline(m_mshFile, line);
132  s.clear();
133  s.str(line);
134  s >> j;
135  for (i = 0; i < j; ++i)
136  {
137  getline(m_mshFile, line);
138  }
139 
140  // -- Read in logical switches (ignore)
141  getline(m_mshFile, line);
142  s.clear();
143  s.str(line);
144  s >> j;
145  for (i = 0; i < j; ++i)
146  {
147  getline(m_mshFile, line);
148  }
149 
150  // -- Read in mesh data.
151 
152  // First hunt for MESH tag
153  bool foundMesh = false;
154  while (!m_mshFile.eof())
155  {
156  getline(m_mshFile, line);
157  if (line.find("MESH") != string::npos)
158  {
159  foundMesh = true;
160  break;
161  }
162  }
163 
164  if (!foundMesh)
165  {
166  cerr << "Couldn't find MESH tag inside file." << endl;
167  abort();
168  }
169 
170  // Now read in number of elements and space dimension.
171  getline(m_mshFile, line);
172  s.clear(); s.str(line);
173  s >> nElements >> m_mesh->m_expDim;
174  m_mesh->m_spaceDim = m_mesh->m_expDim;
175 
176  // Set up field names.
177  m_mesh->m_fields.push_back("u");
178  m_mesh->m_fields.push_back("v");
179  if (m_mesh->m_spaceDim > 2)
180  {
181  m_mesh->m_fields.push_back("w");
182  }
183  m_mesh->m_fields.push_back("p");
184 
185  // Loop over and create elements.
186  for (i = 0; i < nElements; ++i)
187  {
188  getline(m_mshFile, line);
189 
190  if (m_mesh->m_expDim == 2)
191  {
192  if (line.find("Qua") != string::npos ||
193  line.find("qua") != string::npos)
194  {
196  }
197  else
198  {
199  // Default element type in 2D is triangle.
200  elType = LibUtilities::eTriangle;
201  }
202  }
203  else
204  {
205  if (line.find("Tet") != string::npos ||
206  line.find("tet") != string::npos)
207  {
209  }
210  else if (line.find("Hex") != string::npos ||
211  line.find("hex") != string::npos)
212  {
213  elType = LibUtilities::eHexahedron;
214  }
215  else if (line.find("Prism") != string::npos ||
216  line.find("prism") != string::npos)
217  {
218  elType = LibUtilities::ePrism;
219  }
220  else if (line.find("Pyr") != string::npos ||
221  line.find("pyr") != string::npos)
222  {
223  elType = LibUtilities::ePyramid;
224  }
225  else if (line.find("Qua") != string::npos ||
226  line.find("qua") != string::npos)
227  {
229  }
230  else
231  {
232  // Default element type in 2D is tetrahedron.
234  }
235  }
236 
237  // Read in number of vertices for element type.
238  const int nNodes = GetNnodes(elType);
239 
240  for (j = 0; j < m_mesh->m_expDim; ++j)
241  {
242  getline(m_mshFile,line);
243  s.clear(); s.str(line);
244  for (k = 0; k < nNodes; ++k)
245  {
246  s >> vertex[j][k];
247  }
248  }
249 
250  // Zero co-ordinates bigger than expansion dimension.
251  for (j = m_mesh->m_expDim; j < 3; ++j)
252  {
253  for (k = 0; k < nNodes; ++k)
254  {
255  vertex[j][k] = 0.0;
256  }
257  }
258 
259  // Nektar meshes do not contain a unique list of nodes, so this
260  // block constructs a unique set so that elements can be created
261  // with unique nodes.
262  vector<NodeSharedPtr> nodeList;
263  for (k = 0; k < nNodes; ++k)
264  {
265  NodeSharedPtr n = boost::shared_ptr<Node>(
266  new Node(nodeCounter++, vertex[0][k],
267  vertex[1][k], vertex[2][k]));
268  nodeList.push_back(n);
269  }
270 
271  elNodes[elType].push_back(nodeList);
272  elIds [elType].push_back(i);
273  }
274 
275  int reorderedId = 0;
276  nodeCounter = 0;
277 
278  for (i = 0; i < elmOrder.size(); ++i)
279  {
280  LibUtilities::ShapeType elType = elmOrder[i];
281  vector<vector<NodeSharedPtr> > &tmp = elNodes[elType];
282 
283  for (j = 0; j < tmp.size(); ++j)
284  {
285  vector<int> tags;
287  domainComposite.find(elType);
288  if (compIt == domainComposite.end())
289  {
290  tags.push_back(nComposite);
291  domainComposite[elType] = nComposite;
292  nComposite++;
293  }
294  else
295  {
296  tags.push_back(compIt->second);
297  }
298 
299  elMap[elIds[elType][j]] = reorderedId++;
300 
301  vector<NodeSharedPtr> nodeList = tmp[j];
302 
303  for (k = 0; k < nodeList.size(); ++k)
304  {
305  pair<NodeSet::iterator, bool> testIns =
306  m_mesh->m_vertexSet.insert(nodeList[k]);
307 
308  if (!testIns.second)
309  {
310  nodeList[k] = *(testIns.first);
311  }
312  else
313  {
314  nodeList[k]->m_id = nodeCounter++;
315  }
316  }
317 
318  // Create linear element
319  ElmtConfig conf(elType,1,false,false);
321  CreateInstance(elType,conf,nodeList,tags);
322  m_mesh->m_element[E->GetDim()].push_back(E);
323  }
324  }
325 
326  // -- Read in curved data.
327  getline(m_mshFile, line);
328  if (line.find("CURVE") == string::npos)
329  {
330  cerr << "Cannot find curved side data." << endl;
331  abort();
332  }
333 
334  // Read number of curves.
335  getline(m_mshFile, line);
336  s.clear(); s.str(line);
337  s >> nCurves;
338 
339  if (nCurves > 0)
340  {
341  string curveTag;
342 
343  for (i = 0; i < nCurves; ++i)
344  {
345  getline(m_mshFile, line);
346  s.clear(); s.str(line);
347  s >> word;
348 
349  if (word == "File")
350  {
351  // Next line contains filename and curve tag.
352  getline(m_mshFile, line);
353  s.clear(); s.str(line);
354  s >> word >> curveTag;
355  curveTags[curveTag] = make_pair(eFile, word);
356  }
357  else if (word == "Recon")
358  {
359  // Next line contains curve tag.
360  getline(m_mshFile, line);
361  s.clear(); s.str(line);
362  s >> word >> curveTag;
363  curveTags[curveTag] = make_pair(eRecon, word);
364  }
365  else
366  {
367  cerr << "Unsupported curve type " << word << endl;
368  abort();
369  }
370  }
371 
372  // Load high order surface information.
373  LoadHOSurfaces();
374 
375  // Read in curve information. First line should contain number
376  // of curved sides.
377  getline(m_mshFile,line);
378 
379  if (line.find("side") == string::npos)
380  {
381  cerr << "Unable to read number of curved sides" << endl;
382  abort();
383  }
384 
385  int nCurvedSides;
386  int faceId, elId;
387  map<string,pair<NekCurve, string> >::iterator it;
388  HOSurfSet::iterator hoIt;
389 
390  s.clear(); s.str(line);
391  s >> nCurvedSides;
392 
393  // Iterate over curved sides, and look up high-order surface
394  // information in the HOSurfSet, then map this onto faces.
395  for (i = 0; i < nCurvedSides; ++i)
396  {
397  getline(m_mshFile, line);
398  s.clear(); s.str(line);
399  s >> faceId >> elId >> word;
400  faceId--;
401  elId = elMap[elId-1];
402  ElementSharedPtr el = m_mesh->m_element[m_mesh->m_expDim][elId];
403 
404  int origFaceId = faceId;
405 
406  if (el->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 0)
407  {
408  boost::shared_ptr<Prism> p =
409  boost::dynamic_pointer_cast<Prism>(el);
410  if (p->m_orientation == 1)
411  {
412  faceId = (faceId+2) % 6;
413  }
414  else if (p->m_orientation == 2)
415  {
416  faceId = (faceId+4) % 6;
417  }
418  }
419  else if (el->GetConf().m_e == LibUtilities::eTetrahedron)
420  {
421  boost::shared_ptr<Tetrahedron> t =
422  boost::dynamic_pointer_cast<Tetrahedron>(el);
423  faceId = t->m_orientationMap[faceId];
424  }
425 
426  it = curveTags.find(word);
427  if (it == curveTags.end())
428  {
429  cerr << "Unrecognised curve tag " << word
430  << " in curved lines" << endl;
431  abort();
432  }
433 
434  if (it->second.first == eRecon)
435  {
436  // Spherigon information: read in vertex normals.
437  vector<NodeSharedPtr> &tmp =
438  el->GetFace(faceId)->m_vertexList;
439  vector<Node> n(tmp.size());
440 
441  int offset = 0;
442  if (el->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 1)
443  {
444  offset = boost::dynamic_pointer_cast<Prism>(
445  el)->m_orientation;
446  }
447 
448  // Read x/y/z coordinates.
449  getline(m_mshFile, line);
450  s.clear(); s.str(line);
451  for (j = 0; j < tmp.size(); ++j)
452  {
453  s >> n[j].m_x;
454  }
455 
456  getline(m_mshFile, line);
457  s.clear(); s.str(line);
458  for (j = 0; j < tmp.size(); ++j)
459  {
460  s >> n[j].m_y;
461  }
462 
463  getline(m_mshFile, line);
464  s.clear(); s.str(line);
465  for (j = 0; j < tmp.size(); ++j)
466  {
467  s >> n[j].m_z;
468  }
469 
470  for (j = 0; j < tmp.size(); ++j)
471  {
472  int id = tmp[(j+offset) % tmp.size()]->m_id;
474  m_mesh->m_vertexNormals.find(id);
475 
476  if (vIt == m_mesh->m_vertexNormals.end())
477  {
478  m_mesh->m_vertexNormals[id] = n[j];
479  }
480  }
481 
482  // Add edge/face to list of faces to apply spherigons
483  // to.
484  m_mesh->m_spherigonSurfs.insert(make_pair(elId, faceId));
485  }
486  else if (it->second.first == eFile)
487  {
488  FaceSharedPtr f = el->GetFace(faceId);
489  static int tetFaceVerts[4][3] = {
490  {0,1,2},{0,1,3},{1,2,3},{0,2,3}};
491 
492  vector<int> vertId(3);
493  s >> vertId[0] >> vertId[1] >> vertId[2];
494 
495  // Prisms and tets may have been rotated by OrientPrism
496  // routine which reorders vertices. This block rotates
497  // vertex ids accordingly.
498  if (el->GetConf().m_e == LibUtilities::eTetrahedron)
499  {
500  boost::shared_ptr<Tetrahedron> tet =
501  boost::static_pointer_cast<Tetrahedron>(el);
502  vector<int> tmpVertId = vertId;
503 
504  for (j = 0; j < 3; ++j)
505  {
506  int v = tet->GetVertex(
507  tet->m_origVertMap[
508  tetFaceVerts[origFaceId][j]])->m_id;
509 
510  for (k = 0; k < 3; ++k)
511  {
512  int w = f->m_vertexList[k]->m_id;
513  if (v == w)
514  {
515  vertId[k] = tmpVertId[j];
516  break;
517  }
518  }
519  }
520  }
521  else if (el->GetConf().m_e == LibUtilities::ePrism)
522  {
523  boost::shared_ptr<Prism> pr =
524  boost::static_pointer_cast<Prism>(el);
525  if (pr->m_orientation == 1)
526  {
527  swap(vertId[2], vertId[1]);
528  swap(vertId[0], vertId[1]);
529  }
530  else if (pr->m_orientation == 2)
531  {
532  swap(vertId[0], vertId[1]);
533  swap(vertId[2], vertId[1]);
534  }
535  }
536 
537  // Find vertex combination in hoData.
538  hoIt = hoData[word].find(HOSurfSharedPtr(
539  new HOSurf(vertId)));
540 
541  if (hoIt == hoData[word].end())
542  {
543  cerr << "Unable to find high-order surface data "
544  << "for element id " << elId+1 << endl;
545  abort();
546  }
547 
548  // Depending on order of vertices in rea file, surface
549  // information may need to be rotated or reflected.
550  HOSurfSharedPtr surf = *hoIt;
551  surf->Align(vertId);
552 
553  // Finally, add high order data to appropriate face.
554  int Ntot = (*hoIt)->surfVerts.size();
555  int N = ((int)sqrt(8.0*Ntot+1.0)-1)/2;
556  EdgeSharedPtr edge;
557 
558  // Apply high-order map to convert face data to Nektar++
559  // ordering (vertices->edges->internal).
560  vector<NodeSharedPtr> tmpVerts = (*hoIt)->surfVerts;
561  for (j = 0; j < tmpVerts.size(); ++j)
562  {
563  (*hoIt)->surfVerts[hoMap[j]] = tmpVerts[j];
564  }
565 
566  for (j = 0; j < tmpVerts.size(); ++j)
567  {
568  NodeSharedPtr a = (*hoIt)->surfVerts[j];
569  }
570 
571  vector<int> faceVertIds(3);
572  faceVertIds[0] = f->m_vertexList[0]->m_id;
573  faceVertIds[1] = f->m_vertexList[1]->m_id;
574  faceVertIds[2] = f->m_vertexList[2]->m_id;
575 
576  for (j = 0; j < f->m_edgeList.size(); ++j)
577  {
578  edge = f->m_edgeList[j];
579 
580  // Skip over edges which have already been
581  // populated.
582  if (edge->m_edgeNodes.size() > 0)
583  {
584  continue;
585  }
586 
587  //edge->m_edgeNodes.clear();
588  edge->m_curveType
590 
591  for (int k = 0; k < N-2; ++k)
592  {
593  edge->m_edgeNodes.push_back(
594  (*hoIt)->surfVerts[3+j*(N-2)+k]);
595  }
596 
597  // Nodal triangle data is always
598  // counter-clockwise. Add this check to reorder
599  // where necessary.
600  if (edge->m_n1->m_id != faceVertIds[j])
601  {
602  reverse(edge->m_edgeNodes.begin(),
603  edge->m_edgeNodes.end());
604  }
605  }
606 
607  // Insert interior face curvature.
608  f->m_curveType = LibUtilities::eNodalTriElec;
609  for (int j = 3+3*(N-2); j < Ntot; ++j)
610  {
611  f->m_faceNodes.push_back((*hoIt)->surfVerts[j]);
612  }
613  }
614  }
615  }
616 
617  // -- Process fluid boundary conditions.
618 
619  // Define a fairly horrendous map: key is the condition ID, the
620  // value is a vector of pairs of composites and element
621  // types. Essentially this map takes conditions -> composites for
622  // each element type.
623  map<int,vector<pair<int,LibUtilities::ShapeType> > > surfaceCompMap;
624 
625  // Skip boundary conditions line.
626  getline(m_mshFile, line);
627  getline(m_mshFile, line);
628 
629  int nSurfaces = 0;
630 
631  while (true)
632  {
633  getline(m_mshFile, line);
634 
635  // Break out of loop at end of boundary conditions section.
636  if (line.find("*") != string::npos || m_mshFile.eof() ||
637  line.length() == 0)
638  {
639  break;
640  }
641 
642  // Read boundary type, element ID and face ID.
643  char bcType;
644  int elId, faceId;
645  s.clear(); s.str(line);
646  s >> bcType >> elId >> faceId;
647  faceId--;
648  elId = elMap[elId-1];
649 
650  vector<string> vals;
651  vector<ConditionType> type;
652  ConditionSharedPtr c =
654 
655  // First character on each line describes type of BC. Currently
656  // only support V, W, and O. In this switch statement we
657  // construct the quantities needed to search for the condition.
658  switch(bcType)
659  {
660  // Wall boundary.
661  case 'W':
662  {
663  for (i = 0; i < m_mesh->m_fields.size()-1; ++i)
664  {
665  vals.push_back("0");
666  type.push_back(eDirichlet);
667  }
668  // Set high-order boundary condition for wall.
669  vals.push_back("0");
670  type.push_back(eHOPCondition);
671  break;
672  }
673 
674  // Velocity boundary condition (either constant or dependent
675  // upon x,y,z).
676  case 'V':
677  case 'v':
678  {
679  for (i = 0; i < m_mesh->m_fields.size()-1; ++i)
680  {
681  getline(m_mshFile, line);
682  size_t p = line.find_first_of('=');
683  vals.push_back(boost::algorithm::trim_copy(
684  line.substr(p+1)));
685  type.push_back(eDirichlet);
686  }
687  // Set high-order boundary condition for Dirichlet
688  // condition.
689  vals.push_back("0");
690  type.push_back(eHOPCondition);
691  break;
692  }
693 
694  // Natural outflow condition (default value = 0.0?)
695  case 'O':
696  {
697  for (i = 0; i < m_mesh->m_fields.size(); ++i)
698  {
699  vals.push_back("0");
700  type.push_back(eNeumann);
701  }
702  // Set zero Dirichlet condition for outflow.
703  type[m_mesh->m_fields.size()-1] = eDirichlet;
704  break;
705  }
706 
707  // Ignore unsupported BCs
708  case 'P':
709  case 'E':
710  case 'F':
711  case 'f':
712  case 'N':
713  continue;
714  break;
715 
716  default:
717  cerr << "Unknown boundary condition type "
718  << line[0] << endl;
719  abort();
720  }
721 
722  // Populate condition information.
723  c->field = m_mesh->m_fields;
724  c->type = type;
725  c->value = vals;
726 
727  // Now attempt to find this boundary condition inside
728  // m_mesh->condition. This is currently a linear search and should
729  // probably be made faster!
731  bool found = false;
732  for (it = m_mesh->m_condition.begin(); it != m_mesh->m_condition.end(); ++it)
733  {
734  if (c == it->second)
735  {
736  found = true;
737  break;
738  }
739  }
740 
741  int compTag, conditionId;
742  ElementSharedPtr elm = m_mesh->m_element[m_mesh->m_spaceDim][elId];
743  ElementSharedPtr surfEl;
744 
745  // Create element for face (3D) or segment (2D). At the moment
746  // this is a bit of a hack since high-order nodes are not
747  // copied, so some output modules (e.g. Gmsh) will not output
748  // correctly.
749  if (elm->GetDim() == 3)
750  {
751  // 3D elements may have been reoriented, so face IDs will
752  // change.
753  if (elm->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 0)
754  {
755  boost::shared_ptr<Prism> p =
756  boost::dynamic_pointer_cast<Prism>(elm);
757  if (p->m_orientation == 1)
758  {
759  faceId = (faceId+2) % 6;
760  }
761  else if (p->m_orientation == 2)
762  {
763  faceId = (faceId+4) % 6;
764  }
765  }
766  else if (elm->GetConf().m_e == LibUtilities::eTetrahedron)
767  {
768  boost::shared_ptr<Tetrahedron> t =
769  boost::dynamic_pointer_cast<Tetrahedron>(elm);
770  faceId = t->m_orientationMap[faceId];
771  }
772 
773  FaceSharedPtr f = elm->GetFace(faceId);
774  bool tri = f->m_vertexList.size() == 3;
775 
776  vector<NodeSharedPtr> nodeList;
777  nodeList.insert(nodeList.begin(),
778  f->m_vertexList.begin(),
779  f->m_vertexList.end());
780 
781  vector<int> tags;
782 
785  ElmtConfig conf(seg,1,true,true,false,
787  surfEl = GetElementFactory().
788  CreateInstance(seg,conf,nodeList,tags);
789 
790  // Copy high-order surface information from edges.
791  for (int i = 0; i < f->m_vertexList.size(); ++i)
792  {
793  surfEl->GetEdge(i)->m_edgeNodes =
794  f->m_edgeList[i]->m_edgeNodes;
795  surfEl->GetEdge(i)->m_curveType =
796  f->m_edgeList[i]->m_curveType;
797  }
798  }
799  else
800  {
801  EdgeSharedPtr f = elm->GetEdge(faceId);
802 
803  vector<NodeSharedPtr> nodeList;
804  nodeList.push_back(f->m_n1);
805  nodeList.push_back(f->m_n2);
806 
807  vector<int> tags;
808 
809  ElmtConfig conf(LibUtilities::eSegment,1,true,true,false,
811  surfEl = GetElementFactory().
812  CreateInstance(LibUtilities::eSegment,conf,nodeList,tags);
813  }
814 
815  if (!found)
816  {
817  // If condition does not already exist, add to condition
818  // list, create new composite tag and put inside
819  // surfaceCompMap.
820  conditionId = m_mesh->m_condition.size();
821  compTag = nComposite;
822  c->m_composite.push_back(compTag);
823  m_mesh->m_condition[conditionId] = c;
824 
825  surfaceCompMap[conditionId].push_back(
826  pair<int,LibUtilities::ShapeType>(nComposite,surfEl->GetConf().m_e));
827 
828  nComposite++;
829  }
830  else
831  {
832  // Otherwise find existing composite inside surfaceCompMap.
833  map<int,vector<pair<int,LibUtilities::ShapeType> > >::iterator it2;
834  it2 = surfaceCompMap.find(it->first);
835 
836  found = false;
837  if (it2 == surfaceCompMap.end())
838  {
839  // This should never happen!
840  cerr << "Unable to find condition!" << endl;
841  abort();
842  }
843 
844  for (j = 0; j < it2->second.size(); ++j)
845  {
846  pair<int,LibUtilities::ShapeType> tmp = it2->second[j];
847  if (tmp.second == surfEl->GetConf().m_e)
848  {
849  found = true;
850  compTag = tmp.first;
851  break;
852  }
853  }
854 
855  // If no pairs were found, then this condition contains
856  // multiple element types (i.e. both triangles and
857  // quads). Create another composite for the new shape type
858  // and insert into the map.
859  if (!found)
860  {
861  it2->second.push_back(pair<int,LibUtilities::ShapeType>(
862  nComposite,surfEl->GetConf().m_e));
863  compTag = nComposite;
864  m_mesh->m_condition[it->first]->m_composite.push_back(compTag);
865  nComposite++;
866  }
867 
868  conditionId = it->first;
869  }
870 
871  // Insert composite tag into element and insert element into
872  // mesh.
873  vector<int> existingTags = surfEl->GetTagList();
874 
875  existingTags.insert(existingTags.begin(), compTag);
876  surfEl->SetTagList (existingTags);
877  surfEl->SetId (nSurfaces);
878 
879  m_mesh->m_element[surfEl->GetDim()].push_back(surfEl);
880  nSurfaces++;
881  }
882 
883  m_mshFile.close();
884 
885  // -- Process rest of mesh.
886  ProcessEdges ();
887  ProcessFaces ();
888  ProcessElements ();
890  }
891 
892  /**
893  * Load high order surface information from hsf file.
894  */
896  {
897  map<string, pair<NekCurve, string> >::iterator it;
898  int nodeId = m_mesh->GetNumEntities();
899 
900  for (it = curveTags.begin(); it != curveTags.end(); ++it)
901  {
902  ifstream hsf;
903  string line, fileName = it->second.second;
904  size_t pos;
905  int N, Nface, dot;
906 
907  if (it->second.first != eFile)
908  {
909  continue;
910  }
911 
912  // Replace fro extension with hsf.
913  dot = fileName.find_last_of('.');
914  fileName = fileName.substr(0,dot);
915  fileName += ".hsf";
916 
917  // Open hsf file.
918  hsf.open(fileName.c_str());
919  if (!hsf.is_open())
920  {
921  cerr << "Could not open surface file " << fileName << endl;
922  abort();
923  }
924 
925  // Read in header line; determine element order, number of faces
926  // from this line.
927  getline(hsf, line);
928  pos = line.find("=");
929  if (pos == string::npos)
930  {
931  cerr << "hsf header error: cannot read number of "
932  << "nodal points." << endl;
933  abort();
934  }
935  line = line.substr(pos+1);
936  stringstream ss(line);
937  ss >> N;
938 
939  pos = line.find("=");
940  if (pos == string::npos)
941  {
942  cerr << "hsf header error: cannot read number of "
943  << "faces." << endl;
944  abort();
945  }
946  line = line.substr(pos+1);
947  ss.clear(); ss.str(line);
948  ss >> Nface;
949 
950  int Ntot = N*(N+1)/2;
951 
952  // Skip a line, then read in r,s positions inside the next
953  // comments.
954  Array<OneD, NekDouble> r(Ntot), s(Ntot);
955  getline(hsf, line);
956 
957  for (int i = 0; i < 2; ++i)
958  {
959  string word;
960 
961  getline(hsf, line);
962  ss.clear(); ss.str(line);
963  ss >> word;
964 
965  if (word != "#")
966  {
967  cerr << "hsf header error: cannot read in "
968  << "r/s points" << endl;
969  abort();
970  }
971 
972  for (int j = 0; j < Ntot; ++j)
973  {
974  ss >> (i == 0 ? r[j] : s[j]);
975  }
976  }
977 
978  // Generate electrostatic points so that re-mapping array can
979  // be constructed.
980  Array<OneD, NekDouble> rp(Ntot), sp(Ntot);
982  LibUtilities::PointsManager()[elec]->GetPoints(rp,sp);
983 
984  // Expensively construct remapping array nodemap. This will
985  // map nodal ordering from hsf order to Nektar++ ordering
986  // (i.e. vertices followed by edges followed by interior
987  // points.)
988  for (int i = 0; i < Ntot; ++i)
989  {
990  for (int j = 0; j < Ntot; ++j)
991  {
992  if (fabs(r[i]-rp[j]) < 1e-5 && fabs(s[i]-sp[j]) < 1e-5)
993  {
994  hoMap[i] = j;
995  break;
996  }
997  }
998  }
999 
1000  // Skip variables line
1001  getline(hsf, line);
1002 
1003  // Read in nodal points for each face.
1004  map<int, vector<NodeSharedPtr> > faceMap;
1005  for (int i = 0; i < Nface; ++i)
1006  {
1007  getline(hsf, line);
1008  vector<NodeSharedPtr> faceNodes(Ntot);
1009  for (int j = 0; j < Ntot; ++j, ++nodeId)
1010  {
1011  double x, y, z;
1012  getline(hsf, line);
1013  ss.clear(); ss.str(line);
1014  ss >> x >> y >> z;
1015  faceNodes[j] = NodeSharedPtr(new Node(nodeId, x, y, z));
1016  }
1017  // Skip over tecplot connectivity information.
1018  for (int j = 0; j < (N-1)*(N-1); ++j)
1019  {
1020  getline(hsf, line);
1021  }
1022  faceMap[i] = faceNodes;
1023  }
1024 
1025  // Finally, read in connectivity information to set up after
1026  // reading rea file.
1027  getline(hsf, line);
1028  for (int i = 0; i < Nface; ++i)
1029  {
1030  string tmp;
1031  int fid;
1032  vector<int> nodeIds(3);
1033 
1034  getline(hsf, line);
1035  ss.clear(); ss.str(line);
1036  ss >> tmp >> fid >> nodeIds[0] >> nodeIds[1] >> nodeIds[2];
1037 
1038  if (tmp != "#")
1039  {
1040  cerr << "Unable to read hsf connectivity information."
1041  << endl;
1042  abort();
1043  }
1044 
1045  hoData[it->first].insert(
1046  HOSurfSharedPtr(new HOSurf(nodeIds, faceMap[i])));
1047  }
1048 
1049  hsf.close();
1050  }
1051  }
1052 
1053  /**
1054  * This routine aids the reading of Nektar files only; it returns the
1055  * number of nodes for a given entity typw.
1056  */
1058  {
1059  int nNodes = 0;
1060 
1061  switch(InputNekEntity)
1062  {
1063  case LibUtilities::ePoint: nNodes = 1; break;
1064  case LibUtilities::eSegment: nNodes = 2; break;
1065  case LibUtilities::eTriangle: nNodes = 3; break;
1066  case LibUtilities::eQuadrilateral: nNodes = 4; break;
1067  case LibUtilities::eTetrahedron: nNodes = 4; break;
1068  case LibUtilities::ePyramid: nNodes = 5; break;
1069  case LibUtilities::ePrism: nNodes = 6; break;
1070  case LibUtilities::eHexahedron: nNodes = 8; break;
1071  default:
1072  cerr << "unknown Nektar element type" << endl;
1073  }
1074 
1075  return nNodes;
1076  }
1077 
1078  /**
1079  * @brief Compares two %HOSurf objects referred to as shared pointers.
1080  *
1081  * Two %HOSurf objects are defined to be equal if they contain identical
1082  * vertex ids contained in HOSurf::vertId.
1083  */
1084  bool operator==(HOSurfSharedPtr const &p1, HOSurfSharedPtr const &p2)
1085  {
1086  if (p1->vertId.size() != p2->vertId.size())
1087  {
1088  return false;
1089  }
1090 
1091  vector<int> ids1 = p1->vertId;
1092  vector<int> ids2 = p2->vertId;
1093  sort(ids1.begin(), ids1.end());
1094  sort(ids2.begin(), ids2.end());
1095 
1096  for (int i = 0; i < ids1.size(); ++i)
1097  {
1098  if (ids1[i] != ids2[i])
1099  return false;
1100  }
1101 
1102  return true;
1103  }
1104  }
1105 }