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 
37 #include "MeshElements.h"
38 #include "InputNek.h"
39 
41 #include <boost/algorithm/string.hpp>
42 
43 #include <map>
44 #include <vector>
45 #include <sstream>
46 #include <string>
47 using namespace std;
48 
49 namespace Nektar
50 {
51  namespace Utilities
52  {
53  ModuleKey InputNek::className =
55  ModuleKey(eInputModule, "rea"), InputNek::create,
56  "Reads Nektar rea file.");
57 
58  InputNek::InputNek(MeshSharedPtr m) : InputModule(m)
59  {
60 
61  }
62 
64  {
65 
66  }
67 
68  /**
69  * @brief Processes Nektar file format.
70  *
71  * Nektar sessions are defined by rea files, and contain sections
72  * defining a DNS simulation in a specific order. The converter only
73  * reads mesh information, curve information if it exists and boundary
74  * 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][6];
89  map<LibUtilities::ShapeType,int> domainComposite;
90  map<LibUtilities::ShapeType,vector< vector<NodeSharedPtr> > > elNodes;
91  map<LibUtilities::ShapeType,vector<int> > elIds;
92  boost::unordered_map<int,int> elMap;
93  vector<LibUtilities::ShapeType> elmOrder;
94 
95  // Set up vector of processing orders.
96  elmOrder.push_back(LibUtilities::eSegment);
97  elmOrder.push_back(LibUtilities::eTriangle);
98  elmOrder.push_back(LibUtilities::eQuadrilateral);
99  elmOrder.push_back(LibUtilities::ePrism);
100  elmOrder.push_back(LibUtilities::ePyramid);
101  elmOrder.push_back(LibUtilities::eTetrahedron);
102  elmOrder.push_back(LibUtilities::eHexahedron);
103 
104  m_mesh->m_expDim = 0;
105  m_mesh->m_spaceDim = 0;
106 
107  if (m_mesh->m_verbose)
108  {
109  cout << "InputNek: Start reading file..." << endl;
110  }
111 
112  // -- Read in parameters.
113 
114  // Ignore first 3 lines. 4th line contains number of parameters.
115  for (i = 0; i < 4; ++i)
116  {
117  getline(m_mshFile, line);
118  }
119 
120  stringstream s(line);
121  s >> nParam;
122 
123  for (i = 0; i < nParam; ++i)
124  {
125  string tmp1, tmp2;
126  getline(m_mshFile, line);
127  s.str(line);
128  s >> tmp1 >> tmp2;
129  }
130 
131  // -- Read in passive scalars (ignore)
132  getline(m_mshFile, line);
133  s.clear();
134  s.str(line);
135  s >> j;
136  for (i = 0; i < j; ++i)
137  {
138  getline(m_mshFile, line);
139  }
140 
141  // -- Read in logical switches (ignore)
142  getline(m_mshFile, line);
143  s.clear();
144  s.str(line);
145  s >> j;
146  for (i = 0; i < j; ++i)
147  {
148  getline(m_mshFile, line);
149  }
150 
151  // -- Read in mesh data.
152 
153  // First hunt for MESH tag
154  bool foundMesh = false;
155  while (!m_mshFile.eof())
156  {
157  getline(m_mshFile, line);
158  if (line.find("MESH") != string::npos)
159  {
160  foundMesh = true;
161  break;
162  }
163  }
164 
165  if (!foundMesh)
166  {
167  cerr << "Couldn't find MESH tag inside file." << endl;
168  abort();
169  }
170 
171  // Now read in number of elements and space dimension.
172  getline(m_mshFile, line);
173  s.clear(); s.str(line);
174  s >> nElements >> m_mesh->m_expDim;
175  m_mesh->m_spaceDim = m_mesh->m_expDim;
176 
177  // Set up field names.
178  m_mesh->m_fields.push_back("u");
179  m_mesh->m_fields.push_back("v");
180  if (m_mesh->m_spaceDim > 2)
181  {
182  m_mesh->m_fields.push_back("w");
183  }
184  m_mesh->m_fields.push_back("p");
185 
186  // Loop over and create elements.
187  for (i = 0; i < nElements; ++i)
188  {
189  getline(m_mshFile, line);
190 
191  if (m_mesh->m_expDim == 2)
192  {
193  if (line.find("Qua") != string::npos ||
194  line.find("qua") != string::npos)
195  {
197  }
198  else
199  {
200  // Default element type in 2D is triangle.
201  elType = LibUtilities::eTriangle;
202  }
203  }
204  else
205  {
206  if (line.find("Tet") != string::npos ||
207  line.find("tet") != string::npos)
208  {
210  }
211  else if (line.find("Hex") != string::npos ||
212  line.find("hex") != string::npos)
213  {
214  elType = LibUtilities::eHexahedron;
215  }
216  else if (line.find("Prism") != string::npos ||
217  line.find("prism") != string::npos)
218  {
219  elType = LibUtilities::ePrism;
220  }
221  else if (line.find("Pyr") != string::npos ||
222  line.find("pyr") != string::npos)
223  {
224  cerr << "Pyramid elements not yet supported." << endl;
225  abort();
226  }
227  else if (line.find("Qua") != string::npos ||
228  line.find("qua") != string::npos)
229  {
231  }
232  else
233  {
234  // Default element type in 2D is tetrahedron.
236  }
237  }
238 
239  // Read in number of vertices for element type.
240  const int nNodes = GetNnodes(elType);
241 
242  for (j = 0; j < m_mesh->m_expDim; ++j)
243  {
244  getline(m_mshFile,line);
245  s.clear(); s.str(line);
246  for (k = 0; k < nNodes; ++k)
247  {
248  s >> vertex[j][k];
249  }
250  }
251 
252  // Zero co-ordinates bigger than expansion dimension.
253  for (j = m_mesh->m_expDim; j < 3; ++j)
254  {
255  for (k = 0; k < nNodes; ++k)
256  {
257  vertex[j][k] = 0.0;
258  }
259  }
260 
261  // Nektar meshes do not contain a unique list of nodes, so this
262  // block constructs a unique set so that elements can be created
263  // with unique nodes.
264  vector<NodeSharedPtr> nodeList;
265  for (k = 0; k < nNodes; ++k)
266  {
267  NodeSharedPtr n = boost::shared_ptr<Node>(
268  new Node(nodeCounter++, vertex[0][k],
269  vertex[1][k], vertex[2][k]));
270  nodeList.push_back(n);
271  }
272 
273  elNodes[elType].push_back(nodeList);
274  elIds [elType].push_back(i);
275  }
276 
277  int reorderedId = 0;
278  nodeCounter = 0;
279 
280  for (i = 0; i < elmOrder.size(); ++i)
281  {
282  LibUtilities::ShapeType elType = elmOrder[i];
283  vector<vector<NodeSharedPtr> > &tmp = elNodes[elType];
284 
285  for (j = 0; j < tmp.size(); ++j)
286  {
287  vector<int> tags;
289  domainComposite.find(elType);
290  if (compIt == domainComposite.end())
291  {
292  tags.push_back(nComposite);
293  domainComposite[elType] = nComposite;
294  nComposite++;
295  }
296  else
297  {
298  tags.push_back(compIt->second);
299  }
300 
301  elMap[elIds[elType][j]] = reorderedId++;
302 
303  vector<NodeSharedPtr> nodeList = tmp[j];
304 
305  for (k = 0; k < nodeList.size(); ++k)
306  {
307  pair<NodeSet::iterator, bool> testIns =
308  m_mesh->m_vertexSet.insert(nodeList[k]);
309 
310  if (!testIns.second)
311  {
312  nodeList[k] = *(testIns.first);
313  }
314  else
315  {
316  nodeList[k]->m_id = nodeCounter++;
317  }
318  }
319 
320  // Create linear element
321  ElmtConfig conf(elType,1,false,false);
323  CreateInstance(elType,conf,nodeList,tags);
324  m_mesh->m_element[E->GetDim()].push_back(E);
325  }
326  }
327 
328  // -- Read in curved data.
329  getline(m_mshFile, line);
330  if (line.find("CURVE") == string::npos)
331  {
332  cerr << "Cannot find curved side data." << endl;
333  abort();
334  }
335 
336  // Read number of curves.
337  getline(m_mshFile, line);
338  s.clear(); s.str(line);
339  s >> nCurves;
340 
341  if (nCurves > 0)
342  {
343  string curveTag;
344 
345  for (i = 0; i < nCurves; ++i)
346  {
347  getline(m_mshFile, line);
348  s.clear(); s.str(line);
349  s >> word;
350 
351  if (word == "File")
352  {
353  // Next line contains filename and curve tag.
354  getline(m_mshFile, line);
355  s.clear(); s.str(line);
356  s >> word >> curveTag;
357  curveTags[curveTag] = make_pair(eFile, word);
358  }
359  else if (word == "Recon")
360  {
361  // Next line contains curve tag.
362  getline(m_mshFile, line);
363  s.clear(); s.str(line);
364  s >> word >> curveTag;
365  curveTags[curveTag] = make_pair(eRecon, word);
366  }
367  else
368  {
369  cerr << "Unsupported curve type " << word << endl;
370  abort();
371  }
372  }
373 
374  // Load high order surface information.
375  LoadHOSurfaces();
376 
377  // Read in curve information. First line should contain number
378  // of curved sides.
379  getline(m_mshFile,line);
380 
381  if (line.find("side") == string::npos)
382  {
383  cerr << "Unable to read number of curved sides" << endl;
384  abort();
385  }
386 
387  int nCurvedSides;
388  int faceId, elId;
389  map<string,pair<NekCurve, string> >::iterator it;
390  HOSurfSet::iterator hoIt;
391 
392  s.clear(); s.str(line);
393  s >> nCurvedSides;
394 
395  // Iterate over curved sides, and look up high-order surface
396  // information in the HOSurfSet, then map this onto faces.
397  for (i = 0; i < nCurvedSides; ++i)
398  {
399  getline(m_mshFile, line);
400  s.clear(); s.str(line);
401  s >> faceId >> elId >> word;
402  faceId--;
403  elId = elMap[elId-1];
404  ElementSharedPtr el = m_mesh->m_element[m_mesh->m_expDim][elId];
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  vector<unsigned int> vertId(3);
489  s >> vertId[0] >> vertId[1] >> vertId[2];
490 
491  // Find vertex combination in hoData.
492  hoIt = hoData[word].find(HOSurfSharedPtr(
493  new HOSurf(vertId)));
494 
495  if (hoIt == hoData[word].end())
496  {
497  cerr << "Unable to find high-order surface data "
498  << "for element id " << elId+1 << endl;
499  abort();
500  }
501 
502  // Depending on order of vertices in rea file, surface
503  // information may need to be rotated or
504  // reflected. These procedures are taken from
505  // nektar/Hlib/src/HOSurf.C
506  HOSurfSharedPtr surf = *hoIt;
507 
508  if (vertId[0] == surf->vertId[0])
509  {
510  if (vertId[1] == surf->vertId[1] ||
511  vertId[1] == surf->vertId[2])
512  {
513  if (vertId[1] == surf->vertId[2])
514  {
515  surf->Rotate(1);
516  surf->Reflect();
517  }
518  }
519  }
520  else if (vertId[0] == surf->vertId[1])
521  {
522  if (vertId[1] == surf->vertId[0] ||
523  vertId[1] == surf->vertId[2])
524  {
525  if (vertId[1] == surf->vertId[0])
526  {
527  surf->Reflect();
528  }
529  else
530  {
531  surf->Rotate(2);
532  }
533  }
534  }
535  else if (vertId[0] == surf->vertId[2])
536  {
537  if (vertId[1] == surf->vertId[0] ||
538  vertId[1] == surf->vertId[1])
539  {
540  if (vertId[1] == surf->vertId[1])
541  {
542  surf->Rotate(2);
543  surf->Reflect();
544  }
545  else
546  {
547  surf->Rotate(1);
548  }
549  }
550  }
551 
552  // If the element is a prism, check to see if
553  // orientation has changed and update order of surface
554  // vertices.
555  int reverseSide = 2;
556 
557  // Prisms may have been rotated by OrientPrism routine
558  // and break curved faces. This block rotates faces
559  // accordingly. TODO: Add similar routine for tets.
560  if (el->GetConf().m_e == LibUtilities::ePrism)
561  {
562  boost::shared_ptr<Prism> pr =
563  boost::static_pointer_cast<Prism>(el);
564  if (pr->m_orientation == 1)
565  {
566  // Prism has been rotated counter-clockwise;
567  // rotate face, reverse what was the last edge
568  // (now located at edge 0).
569  (*hoIt)->Rotate(1);
570  reverseSide = 0;
571  }
572  else if (pr->m_orientation == 2)
573  {
574  // Prism has been rotated clockwise; rotate
575  // face, reverse what was the last edge (now
576  // located at edge 1).
577  (*hoIt)->Rotate(2);
578  reverseSide = 1;
579  }
580  }
581 
582  // Finally, add high order data to appropriate
583  // face. NOTE: this is a bit of a hack since the
584  // elements are technically linear, but should work just
585  // fine.
586  FaceSharedPtr f = el->GetFace(faceId);
587  int Ntot = (*hoIt)->surfVerts.size();
588  int N = ((int)sqrt(8.0*Ntot+1.0)-1)/2;
589  EdgeSharedPtr edge;
590 
591  // Apply high-order map to convert face data to Nektar++
592  // ordering (vertices->edges->internal).
593  vector<NodeSharedPtr> tmpVerts = (*hoIt)->surfVerts;
594  for (j = 0; j < tmpVerts.size(); ++j)
595  {
596  (*hoIt)->surfVerts[hoMap[j]] = tmpVerts[j];
597  }
598 
599  for (j = 0; j < tmpVerts.size(); ++j)
600  {
601  NodeSharedPtr a = (*hoIt)->surfVerts[j];
602  }
603 
604  for (j = 0; j < f->m_edgeList.size(); ++j)
605  {
606  edge = f->m_edgeList[j];
607 
608  // Skip over edges which have already been
609  // populated, apart from those which need to be
610  // reoriented.
611  if (edge->m_edgeNodes.size() > 0 && reverseSide == 2)
612  {
613  continue;
614  }
615 
616  edge->m_edgeNodes.clear();
617  edge->m_curveType = LibUtilities::eGaussLobattoLegendre;
618 
619  for (int k = 0; k < N-2; ++k)
620  {
621  edge->m_edgeNodes.push_back(
622  (*hoIt)->surfVerts[3+j*(N-2)+k]);
623  }
624 
625  // Reverse order of modes along correct side.
626  if (j == reverseSide)
627  {
628  reverse(edge->m_edgeNodes.begin(),
629  edge->m_edgeNodes.end());
630  }
631  }
632 
633  f->m_curveType = LibUtilities::eNodalTriElec;
634  for (int j = 3+3*(N-2); j < Ntot; ++j)
635  {
636  f->m_faceNodes.push_back((*hoIt)->surfVerts[j]);
637  }
638  }
639  }
640  }
641 
642  // -- Process fluid boundary conditions.
643 
644  // Define a fairly horrendous map: key is the condition ID, the
645  // value is a vector of pairs of composites and element
646  // types. Essentially this map takes conditions -> composites for
647  // each element type.
648  map<int,vector<pair<int,LibUtilities::ShapeType> > > surfaceCompMap;
649 
650  // Skip boundary conditions line.
651  getline(m_mshFile, line);
652  getline(m_mshFile, line);
653 
654  int nSurfaces = 0;
655 
656  while (true)
657  {
658  getline(m_mshFile, line);
659 
660  // Break out of loop at end of boundary conditions section.
661  if (line.find("*") != string::npos || m_mshFile.eof() ||
662  line.length() == 0)
663  {
664  break;
665  }
666 
667  // Read boundary type, element ID and face ID.
668  char bcType;
669  int elId, faceId;
670  s.clear(); s.str(line);
671  s >> bcType >> elId >> faceId;
672  faceId--;
673  elId = elMap[elId-1];
674 
675  vector<string> vals;
676  vector<ConditionType> type;
677  ConditionSharedPtr c =
679 
680  // First character on each line describes type of BC. Currently
681  // only support V, W, and O. In this switch statement we
682  // construct the quantities needed to search for the condition.
683  switch(bcType)
684  {
685  // Wall boundary.
686  case 'W':
687  {
688  for (i = 0; i < m_mesh->m_fields.size()-1; ++i)
689  {
690  vals.push_back("0");
691  type.push_back(eDirichlet);
692  }
693  // Set high-order boundary condition for wall.
694  vals.push_back("0");
695  type.push_back(eHOPCondition);
696  break;
697  }
698 
699  // Velocity boundary condition (either constant or dependent
700  // upon x,y,z).
701  case 'V':
702  case 'v':
703  {
704  for (i = 0; i < m_mesh->m_fields.size()-1; ++i)
705  {
706  getline(m_mshFile, line);
707  size_t p = line.find_first_of('=');
708  vals.push_back(boost::algorithm::trim_copy(
709  line.substr(p+1)));
710  type.push_back(eDirichlet);
711  }
712  // Set high-order boundary condition for Dirichlet
713  // condition.
714  vals.push_back("0");
715  type.push_back(eHOPCondition);
716  break;
717  }
718 
719  // Natural outflow condition (default value = 0.0?)
720  case 'O':
721  {
722  for (i = 0; i < m_mesh->m_fields.size(); ++i)
723  {
724  vals.push_back("0");
725  type.push_back(eNeumann);
726  }
727  // Set zero Dirichlet condition for outflow.
728  type[m_mesh->m_fields.size()-1] = eDirichlet;
729  break;
730  }
731 
732  // Ignore unsupported BCs
733  case 'P':
734  case 'E':
735  case 'F':
736  case 'f':
737  case 'N':
738  continue;
739  break;
740 
741  default:
742  cerr << "Unknown boundary condition type "
743  << line[0] << endl;
744  abort();
745  }
746 
747  // Populate condition information.
748  c->field = m_mesh->m_fields;
749  c->type = type;
750  c->value = vals;
751 
752  // Now attempt to find this boundary condition inside
753  // m_mesh->condition. This is currently a linear search and should
754  // probably be made faster!
756  bool found = false;
757  for (it = m_mesh->m_condition.begin(); it != m_mesh->m_condition.end(); ++it)
758  {
759  if (c == it->second)
760  {
761  found = true;
762  break;
763  }
764  }
765 
766  int compTag, conditionId;
767  ElementSharedPtr elm = m_mesh->m_element[m_mesh->m_spaceDim][elId];
768  ElementSharedPtr surfEl;
769 
770  // Create element for face (3D) or segment (2D). At the moment
771  // this is a bit of a hack since high-order nodes are not
772  // copied, so some output modules (e.g. Gmsh) will not output
773  // correctly.
774  if (elm->GetDim() == 3)
775  {
776  // 3D elements may have been reoriented, so face IDs will
777  // change.
778  if (elm->GetConf().m_e == LibUtilities::ePrism && faceId % 2 == 0)
779  {
780  boost::shared_ptr<Prism> p =
781  boost::dynamic_pointer_cast<Prism>(elm);
782  if (p->m_orientation == 1)
783  {
784  faceId = (faceId+2) % 6;
785  }
786  else if (p->m_orientation == 2)
787  {
788  faceId = (faceId+4) % 6;
789  }
790  }
791  else if (elm->GetConf().m_e == LibUtilities::eTetrahedron)
792  {
793  boost::shared_ptr<Tetrahedron> t =
794  boost::dynamic_pointer_cast<Tetrahedron>(elm);
795  faceId = t->m_orientationMap[faceId];
796  }
797 
798  FaceSharedPtr f = elm->GetFace(faceId);
799  bool tri = f->m_vertexList.size() == 3;
800 
801  vector<NodeSharedPtr> nodeList;
802  nodeList.insert(nodeList.begin(),
803  f->m_vertexList.begin(),
804  f->m_vertexList.end());
805 
806  vector<int> tags;
807 
810  ElmtConfig conf(seg,1,true,true,false,
812  surfEl = GetElementFactory().
813  CreateInstance(seg,conf,nodeList,tags);
814 
815  // Copy high-order surface information from edges.
816  for (int i = 0; i < f->m_vertexList.size(); ++i)
817  {
818  surfEl->GetEdge(i)->m_edgeNodes =
819  f->m_edgeList[i]->m_edgeNodes;
820  surfEl->GetEdge(i)->m_curveType =
821  f->m_edgeList[i]->m_curveType;
822  }
823  }
824  else
825  {
826  EdgeSharedPtr f = elm->GetEdge(faceId);
827 
828  vector<NodeSharedPtr> nodeList;
829  nodeList.push_back(f->m_n1);
830  nodeList.push_back(f->m_n2);
831 
832  vector<int> tags;
833 
834  ElmtConfig conf(LibUtilities::eSegment,1,true,true,false,
836  surfEl = GetElementFactory().
837  CreateInstance(LibUtilities::eSegment,conf,nodeList,tags);
838  }
839 
840  if (!found)
841  {
842  // If condition does not already exist, add to condition
843  // list, create new composite tag and put inside
844  // surfaceCompMap.
845  conditionId = m_mesh->m_condition.size();
846  compTag = nComposite;
847  c->m_composite.push_back(compTag);
848  m_mesh->m_condition[conditionId] = c;
849 
850  surfaceCompMap[conditionId].push_back(
851  pair<int,LibUtilities::ShapeType>(nComposite,surfEl->GetConf().m_e));
852 
853  nComposite++;
854  }
855  else
856  {
857  // Otherwise find existing composite inside surfaceCompMap.
858  map<int,vector<pair<int,LibUtilities::ShapeType> > >::iterator it2;
859  it2 = surfaceCompMap.find(it->first);
860 
861  found = false;
862  if (it2 == surfaceCompMap.end())
863  {
864  // This should never happen!
865  cerr << "Unable to find condition!" << endl;
866  abort();
867  }
868 
869  for (j = 0; j < it2->second.size(); ++j)
870  {
871  pair<int,LibUtilities::ShapeType> tmp = it2->second[j];
872  if (tmp.second == surfEl->GetConf().m_e)
873  {
874  found = true;
875  compTag = tmp.first;
876  break;
877  }
878  }
879 
880  // If no pairs were found, then this condition contains
881  // multiple element types (i.e. both triangles and
882  // quads). Create another composite for the new shape type
883  // and insert into the map.
884  if (!found)
885  {
886  it2->second.push_back(pair<int,LibUtilities::ShapeType>(
887  nComposite,surfEl->GetConf().m_e));
888  compTag = nComposite;
889  m_mesh->m_condition[it->first]->m_composite.push_back(compTag);
890  nComposite++;
891  }
892 
893  conditionId = it->first;
894  }
895 
896  // Insert composite tag into element and insert element into
897  // mesh.
898  vector<int> existingTags = surfEl->GetTagList();
899 
900  existingTags.insert(existingTags.begin(), compTag);
901  surfEl->SetTagList (existingTags);
902  surfEl->SetId (nSurfaces);
903 
904  m_mesh->m_element[surfEl->GetDim()].push_back(surfEl);
905  nSurfaces++;
906  }
907 
908  m_mshFile.close();
909 
910  // -- Process rest of mesh.
911  ProcessEdges ();
912  ProcessFaces ();
913  ProcessElements ();
915  }
916 
917  /**
918  * Load high order surface information from hsf file.
919  */
921  {
922  map<string, pair<NekCurve, string> >::iterator it;
923  int nodeId = m_mesh->GetNumEntities();
924 
925  for (it = curveTags.begin(); it != curveTags.end(); ++it)
926  {
927  ifstream hsf;
928  string line, fileName = it->second.second;
929  size_t pos;
930  int N, Nface, dot;
931 
932  if (it->second.first != eFile)
933  {
934  continue;
935  }
936 
937  // Replace fro extension with hsf.
938  dot = fileName.find_last_of('.');
939  fileName = fileName.substr(0,dot);
940  fileName += ".hsf";
941 
942  // Open hsf file.
943  hsf.open(fileName.c_str());
944  if (!hsf.is_open())
945  {
946  cerr << "Could not open surface file " << fileName << endl;
947  abort();
948  }
949 
950  // Read in header line; determine element order, number of faces
951  // from this line.
952  getline(hsf, line);
953  pos = line.find("=");
954  if (pos == string::npos)
955  {
956  cerr << "hsf header error: cannot read number of "
957  << "nodal points." << endl;
958  abort();
959  }
960  line = line.substr(pos+1);
961  stringstream ss(line);
962  ss >> N;
963 
964  pos = line.find("=");
965  if (pos == string::npos)
966  {
967  cerr << "hsf header error: cannot read number of "
968  << "faces." << endl;
969  abort();
970  }
971  line = line.substr(pos+1);
972  ss.clear(); ss.str(line);
973  ss >> Nface;
974 
975  int Ntot = N*(N+1)/2;
976 
977  // Skip a line, then read in r,s positions inside the next
978  // comments.
979  Array<OneD, NekDouble> r(Ntot), s(Ntot);
980  getline(hsf, line);
981 
982  for (int i = 0; i < 2; ++i)
983  {
984  string word;
985 
986  getline(hsf, line);
987  ss.clear(); ss.str(line);
988  ss >> word;
989 
990  if (word != "#")
991  {
992  cerr << "hsf header error: cannot read in "
993  << "r/s points" << endl;
994  abort();
995  }
996 
997  for (int j = 0; j < Ntot; ++j)
998  {
999  ss >> (i == 0 ? r[j] : s[j]);
1000  }
1001  }
1002 
1003  // Generate electrostatic points so that re-mapping array can
1004  // be constructed.
1005  Array<OneD, NekDouble> rp(Ntot), sp(Ntot);
1007  LibUtilities::PointsManager()[elec]->GetPoints(rp,sp);
1008 
1009  // Expensively construct remapping array nodemap. This will
1010  // map nodal ordering from hsf order to Nektar++ ordering
1011  // (i.e. vertices followed by edges followed by interior
1012  // points.)
1013  for (int i = 0; i < Ntot; ++i)
1014  {
1015  for (int j = 0; j < Ntot; ++j)
1016  {
1017  if (fabs(r[i]-rp[j]) < 1e-5 && fabs(s[i]-sp[j]) < 1e-5)
1018  {
1019  hoMap[i] = j;
1020  break;
1021  }
1022  }
1023  }
1024 
1025  // Skip variables line
1026  getline(hsf, line);
1027 
1028  // Read in nodal points for each face.
1029  map<unsigned int, vector<NodeSharedPtr> > faceMap;
1030  for (int i = 0; i < Nface; ++i)
1031  {
1032  getline(hsf, line);
1033  vector<NodeSharedPtr> faceNodes(Ntot);
1034  for (int j = 0; j < Ntot; ++j, ++nodeId)
1035  {
1036  double x, y, z;
1037  getline(hsf, line);
1038  ss.clear(); ss.str(line);
1039  ss >> x >> y >> z;
1040  faceNodes[j] = NodeSharedPtr(new Node(nodeId, x, y, z));
1041  }
1042  // Skip over tecplot connectivity information.
1043  for (int j = 0; j < (N-1)*(N-1); ++j)
1044  {
1045  getline(hsf, line);
1046  }
1047  faceMap[i] = faceNodes;
1048  }
1049 
1050  // Finally, read in connectivity information to set up after
1051  // reading rea file.
1052  getline(hsf, line);
1053  for (int i = 0; i < Nface; ++i)
1054  {
1055  string tmp;
1056  int fid;
1057  vector<unsigned int> nodeIds(3);
1058 
1059  getline(hsf, line);
1060  ss.clear(); ss.str(line);
1061  ss >> tmp >> fid >> nodeIds[0] >> nodeIds[1] >> nodeIds[2];
1062 
1063  if (tmp != "#")
1064  {
1065  cerr << "Unable to read hsf connectivity information."
1066  << endl;
1067  abort();
1068  }
1069 
1070  hoData[it->first].insert(
1071  HOSurfSharedPtr(new HOSurf(nodeIds, faceMap[i])));
1072  }
1073 
1074  hsf.close();
1075  }
1076  }
1077 
1078  /**
1079  * This routine aids the reading of Nektar files only; it returns the
1080  * number of nodes for a given entity typw.
1081  */
1083  {
1084  int nNodes = 0;
1085 
1086  switch(InputNekEntity)
1087  {
1088  case LibUtilities::ePoint: nNodes = 1; break;
1089  case LibUtilities::eSegment: nNodes = 2; break;
1090  case LibUtilities::eTriangle: nNodes = 3; break;
1091  case LibUtilities::eQuadrilateral: nNodes = 4; break;
1092  case LibUtilities::eTetrahedron: nNodes = 4; break;
1093  case LibUtilities::ePrism: nNodes = 6; break;
1094  case LibUtilities::eHexahedron: nNodes = 8; break;
1095  default:
1096  cerr << "unknown Nektar element type" << endl;
1097  }
1098 
1099  return nNodes;
1100  }
1101 
1102  /**
1103  * @brief Compares two %HOSurf objects referred to as shared pointers.
1104  *
1105  * Two %HOSurf objects are defined to be equal if they contain identical
1106  * vertex ids contained in HOSurf::vertId.
1107  */
1108  bool operator==(HOSurfSharedPtr const &p1, HOSurfSharedPtr const &p2)
1109  {
1110  if (p1->vertId.size() != p2->vertId.size())
1111  {
1112  return false;
1113  }
1114 
1115  vector<unsigned int> ids1 = p1->vertId;
1116  vector<unsigned int> ids2 = p2->vertId;
1117  sort(ids1.begin(), ids1.end());
1118  sort(ids2.begin(), ids2.end());
1119 
1120  for (int i = 0; i < ids1.size(); ++i)
1121  {
1122  if (ids1[i] != ids2[i])
1123  return false;
1124  }
1125 
1126  return true;
1127  }
1128 
1129  /**
1130  * Rotates the triangle of data points inside #surfVerts
1131  * counter-clockwise nrot times.
1132  *
1133  * @param nrot Number of times to rotate triangle.
1134  */
1135  void HOSurf::Rotate(int nrot)
1136  {
1137  int n, i, j, cnt;
1138  int np = ((int)sqrt(8.0*surfVerts.size()+1.0)-1)/2;
1139  NodeSharedPtr* tmp = new NodeSharedPtr[np*np];
1140  //NodeSharedPtr tmp[np][np];
1141 
1142  for (n = 0; n < nrot; ++n)
1143  {
1144  for (cnt = i = 0; i < np; ++i)
1145  {
1146  for (j = 0; j < np-i; ++j, cnt++)
1147  {
1148  tmp[i*np+j] = surfVerts[cnt];
1149  }
1150  }
1151  for (cnt = i = 0; i < np; ++i)
1152  {
1153  for (j = 0; j < np-i; ++j,cnt++)
1154  {
1155  surfVerts[cnt] = tmp[(np-1-i-j)*np+i];
1156  }
1157  }
1158  }
1159 
1160  delete[] tmp;
1161  }
1162 
1164  {
1165  int i, j, cnt;
1166  int np = ((int)sqrt(8.0*surfVerts.size()+1.0)-1)/2;
1167  NodeSharedPtr* tmp = new NodeSharedPtr[np*np];
1168 
1169  for (cnt = i = 0; i < np; ++i)
1170  {
1171  for (j = 0; j < np-i; ++j,cnt++)
1172  {
1173  tmp[i*np+np-i-1-j] = surfVerts[cnt];
1174  }
1175  }
1176 
1177  for(cnt = i = 0; i < np; ++i)
1178  {
1179  for(j = 0; j < np-i; ++j,cnt++)
1180  {
1181  surfVerts[cnt] = tmp[i*np+j];
1182  }
1183  }
1184 
1185  delete[] tmp;
1186  }
1187  }
1188 }