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 // 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  LibUtilities::ShapeType surfElType = surfEl->GetConf().m_e;
816 
817  if (!found)
818  {
819  // If condition does not already exist, add to condition
820  // list, create new composite tag and put inside
821  // surfaceCompMap.
822  conditionId = m_mesh->m_condition.size();
823  compTag = nComposite;
824  c->m_composite.push_back(compTag);
825  m_mesh->m_condition[conditionId] = c;
826 
827  surfaceCompMap[conditionId].push_back(
828  pair<int,LibUtilities::ShapeType>(nComposite,surfElType));
829 
830  nComposite++;
831  }
832  else
833  {
834  // Otherwise find existing composite inside surfaceCompMap.
835  map<int,vector<pair<int,LibUtilities::ShapeType> > >::iterator it2;
836  it2 = surfaceCompMap.find(it->first);
837 
838  found = false;
839  if (it2 == surfaceCompMap.end())
840  {
841  // This should never happen!
842  cerr << "Unable to find condition!" << endl;
843  abort();
844  }
845 
846  for (j = 0; j < it2->second.size(); ++j)
847  {
848  pair<int,LibUtilities::ShapeType> tmp = it2->second[j];
849  if (tmp.second == surfElType)
850  {
851  found = true;
852  compTag = tmp.first;
853  break;
854  }
855  }
856 
857  // If no pairs were found, then this condition contains
858  // multiple element types (i.e. both triangles and
859  // quads). Create another composite for the new shape type
860  // and insert into the map.
861  if (!found)
862  {
863  it2->second.push_back(pair<int,LibUtilities::ShapeType>(
864  nComposite,surfElType));
865  compTag = nComposite;
866  m_mesh->m_condition[it->first]->m_composite.push_back(compTag);
867  nComposite++;
868  }
869 
870  conditionId = it->first;
871  }
872 
873  // Insert composite tag into element and insert element into
874  // mesh.
875  vector<int> existingTags = surfEl->GetTagList();
876 
877  existingTags.insert(existingTags.begin(), compTag);
878  surfEl->SetTagList (existingTags);
879  surfEl->SetId (nSurfaces);
880 
881  m_mesh->m_element[surfEl->GetDim()].push_back(surfEl);
882  nSurfaces++;
883  }
884 
885  m_mshFile.close();
886 
887  // -- Process rest of mesh.
888  ProcessEdges ();
889  ProcessFaces ();
890  ProcessElements ();
892  }
893 
894  /**
895  * Load high order surface information from hsf file.
896  */
898  {
899  map<string, pair<NekCurve, string> >::iterator it;
900  int nodeId = m_mesh->GetNumEntities();
901 
902  for (it = curveTags.begin(); it != curveTags.end(); ++it)
903  {
904  ifstream hsf;
905  string line, fileName = it->second.second;
906  size_t pos;
907  int N, Nface, dot;
908 
909  if (it->second.first != eFile)
910  {
911  continue;
912  }
913 
914  // Replace fro extension with hsf.
915  dot = fileName.find_last_of('.');
916  fileName = fileName.substr(0,dot);
917  fileName += ".hsf";
918 
919  // Open hsf file.
920  hsf.open(fileName.c_str());
921  if (!hsf.is_open())
922  {
923  cerr << "Could not open surface file " << fileName << endl;
924  abort();
925  }
926 
927  // Read in header line; determine element order, number of faces
928  // from this line.
929  getline(hsf, line);
930  pos = line.find("=");
931  if (pos == string::npos)
932  {
933  cerr << "hsf header error: cannot read number of "
934  << "nodal points." << endl;
935  abort();
936  }
937  line = line.substr(pos+1);
938  stringstream ss(line);
939  ss >> N;
940 
941  pos = line.find("=");
942  if (pos == string::npos)
943  {
944  cerr << "hsf header error: cannot read number of "
945  << "faces." << endl;
946  abort();
947  }
948  line = line.substr(pos+1);
949  ss.clear(); ss.str(line);
950  ss >> Nface;
951 
952  int Ntot = N*(N+1)/2;
953 
954  // Skip a line, then read in r,s positions inside the next
955  // comments.
956  Array<OneD, NekDouble> r(Ntot), s(Ntot);
957  getline(hsf, line);
958 
959  for (int i = 0; i < 2; ++i)
960  {
961  string word;
962 
963  getline(hsf, line);
964  ss.clear(); ss.str(line);
965  ss >> word;
966 
967  if (word != "#")
968  {
969  cerr << "hsf header error: cannot read in "
970  << "r/s points" << endl;
971  abort();
972  }
973 
974  for (int j = 0; j < Ntot; ++j)
975  {
976  ss >> (i == 0 ? r[j] : s[j]);
977  }
978  }
979 
980  // Generate electrostatic points so that re-mapping array can
981  // be constructed.
982  Array<OneD, NekDouble> rp(Ntot), sp(Ntot);
984  LibUtilities::PointsManager()[elec]->GetPoints(rp,sp);
985 
986  // Expensively construct remapping array nodemap. This will
987  // map nodal ordering from hsf order to Nektar++ ordering
988  // (i.e. vertices followed by edges followed by interior
989  // points.)
990  for (int i = 0; i < Ntot; ++i)
991  {
992  for (int j = 0; j < Ntot; ++j)
993  {
994  if (fabs(r[i]-rp[j]) < 1e-5 && fabs(s[i]-sp[j]) < 1e-5)
995  {
996  hoMap[i] = j;
997  break;
998  }
999  }
1000  }
1001 
1002  // Skip variables line
1003  getline(hsf, line);
1004 
1005  // Read in nodal points for each face.
1006  map<int, vector<NodeSharedPtr> > faceMap;
1007  for (int i = 0; i < Nface; ++i)
1008  {
1009  getline(hsf, line);
1010  vector<NodeSharedPtr> faceNodes(Ntot);
1011  for (int j = 0; j < Ntot; ++j, ++nodeId)
1012  {
1013  double x, y, z;
1014  getline(hsf, line);
1015  ss.clear(); ss.str(line);
1016  ss >> x >> y >> z;
1017  faceNodes[j] = NodeSharedPtr(new Node(nodeId, x, y, z));
1018  }
1019  // Skip over tecplot connectivity information.
1020  for (int j = 0; j < (N-1)*(N-1); ++j)
1021  {
1022  getline(hsf, line);
1023  }
1024  faceMap[i] = faceNodes;
1025  }
1026 
1027  // Finally, read in connectivity information to set up after
1028  // reading rea file.
1029  getline(hsf, line);
1030  for (int i = 0; i < Nface; ++i)
1031  {
1032  string tmp;
1033  int fid;
1034  vector<int> nodeIds(3);
1035 
1036  getline(hsf, line);
1037  ss.clear(); ss.str(line);
1038  ss >> tmp >> fid >> nodeIds[0] >> nodeIds[1] >> nodeIds[2];
1039 
1040  if (tmp != "#")
1041  {
1042  cerr << "Unable to read hsf connectivity information."
1043  << endl;
1044  abort();
1045  }
1046 
1047  hoData[it->first].insert(
1048  HOSurfSharedPtr(new HOSurf(nodeIds, faceMap[i])));
1049  }
1050 
1051  hsf.close();
1052  }
1053  }
1054 
1055  /**
1056  * This routine aids the reading of Nektar files only; it returns the
1057  * number of nodes for a given entity typw.
1058  */
1060  {
1061  int nNodes = 0;
1062 
1063  switch(InputNekEntity)
1064  {
1065  case LibUtilities::ePoint: nNodes = 1; break;
1066  case LibUtilities::eSegment: nNodes = 2; break;
1067  case LibUtilities::eTriangle: nNodes = 3; break;
1068  case LibUtilities::eQuadrilateral: nNodes = 4; break;
1069  case LibUtilities::eTetrahedron: nNodes = 4; break;
1070  case LibUtilities::ePyramid: nNodes = 5; break;
1071  case LibUtilities::ePrism: nNodes = 6; break;
1072  case LibUtilities::eHexahedron: nNodes = 8; break;
1073  default:
1074  cerr << "unknown Nektar element type" << endl;
1075  }
1076 
1077  return nNodes;
1078  }
1079 
1080  /**
1081  * @brief Compares two %HOSurf objects referred to as shared pointers.
1082  *
1083  * Two %HOSurf objects are defined to be equal if they contain identical
1084  * vertex ids contained in HOSurf::vertId.
1085  */
1086  bool operator==(HOSurfSharedPtr const &p1, HOSurfSharedPtr const &p2)
1087  {
1088  if (p1->vertId.size() != p2->vertId.size())
1089  {
1090  return false;
1091  }
1092 
1093  vector<int> ids1 = p1->vertId;
1094  vector<int> ids2 = p2->vertId;
1095  sort(ids1.begin(), ids1.end());
1096  sort(ids2.begin(), ids2.end());
1097 
1098  for (int i = 0; i < ids1.size(); ++i)
1099  {
1100  if (ids1[i] != ids2[i])
1101  return false;
1102  }
1103 
1104  return true;
1105  }
1106  }
1107 }
std::ifstream m_mshFile
Input stream.
pair< ModuleType, string > ModuleKey
static boost::shared_ptr< DataType > AllocateSharedPtr()
Allocate a shared pointer from the memory pool.
std::map< string, HOSurfSet > hoData
Definition: InputNek.h:109
boost::shared_ptr< HOSurf > HOSurfSharedPtr
Definition: InputNek.h:52
boost::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: MeshElements.h:318
STL namespace.
MeshSharedPtr m_mesh
Mesh object.
boost::shared_ptr< Face > FaceSharedPtr
Shared pointer to a face.
Definition: MeshElements.h:550
NodeSharedPtr GetVertex(unsigned int i) const
Access a vertex node.
Definition: MeshElements.h:675
boost::shared_ptr< Node > NodeSharedPtr
Shared pointer to a Node.
Definition: MeshElements.h:195
virtual void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
boost::shared_ptr< Condition > ConditionSharedPtr
boost::shared_ptr< Element > ElementSharedPtr
Shared pointer to an element.
Definition: MeshElements.h:63
std::map< int, int > hoMap
Definition: InputNek.h:114
A 3-dimensional five-faced element (2 triangles, 3 quadrilaterals).
virtual void ProcessElements()
Generate element IDs.
HOTriangle< NodeSharedPtr > HOSurf
Definition: InputNek.h:51
std::map< string, pair< NekCurve, string > > curveTags
Definition: InputNek.h:104
boost::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
PointsManagerT & PointsManager(void)
Defines a specification for a set of points.
Definition: Points.h:58
Basic information about an element.
Definition: MeshElements.h:583
virtual void ProcessComposites()
Generate composites.
Represents a point in the domain.
Definition: MeshElements.h:74
virtual void Process()
Processes Nektar file format.
Definition: InputNek.cpp:77
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
bool operator==(TriFaceIDs const &p1, TriFaceIDs const &p2)
int GetNnodes(LibUtilities::ShapeType elType)
Definition: InputNek.cpp:1059
virtual void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
A 3-dimensional four-faced element.
void OpenStream()
Open a file for input.
ElementFactory & GetElementFactory()
1D Gauss-Lobatto-Legendre quadrature points
Definition: PointsType.h:50
2D Nodal Electrostatic Points on a Triangle
Definition: PointsType.h:68
ModuleFactory & GetModuleFactory()
Abstract base class for input modules.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, tDescription pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:215