Nektar++
InputStarTec.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: InputStarTec.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: Tecplot file converter.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <boost/core/ignore_unused.hpp>
36 #include <boost/algorithm/string.hpp>
37 
40 
41 #include "InputStarTec.h"
42 
43 using namespace std;
44 using namespace Nektar::NekMeshUtils;
45 
46 namespace Nektar
47 {
48 namespace Utilities
49 {
50 
51 ModuleKey InputTec::className = GetModuleFactory().RegisterCreatorFunction(
52  ModuleKey(eInputModule, "dat"),
53  InputTec::create,
54  "Reads Tecplot polyhedron ascii format converted from Star CCM (.dat).");
55 
56 InputTec::InputTec(MeshSharedPtr m) : InputModule(m)
57 {
58 }
59 
61 {
62 }
63 
64 /**
65  * Tecplot file Polyhedron format contains a list of nodes, a
66  * node count per face, the node ids, Element ids that are on
67  * the left of each face and Element ids which are on the
68  * right of each face. There are then a series of zone of each
69  * surface. In the case of a surface the number of nodes is
70  * not provided indicating it is a 2D zone
71  *
72  * @param pFilename Filename of Tecplot file to read.
73  */
75 {
76  m_mesh->m_expDim = 3;
77  m_mesh->m_spaceDim = 3;
78 
79  if (m_mesh->m_verbose)
80  {
81  cout << "InputStarTec: Start reading file..." << endl;
82  }
83 
84  string line, word;
85 
86  // Open the file stream.
87  OpenStream();
88 
89  int nComposite = 0;
90 
91  // read first zone (Hopefully 3D)
92  while (!m_mshFile.eof())
93  {
94  getline(m_mshFile, line);
95  if (line.find("ZONE") != string::npos)
96  {
97  ReadZone(nComposite);
98  break;
99  }
100  }
101 
102  // read remaining 2D zones
103  while (!m_mshFile.eof())
104  {
105  if (line.find("ZONE") != string::npos)
106  {
107  ReadZone(nComposite);
108  }
109  }
110 
111  PrintSummary();
112  m_mshFile.reset();
113 
114  ProcessEdges();
115  ProcessFaces();
116  ProcessElements();
118 }
119 
120 void InputTec::ReadZone(int &nComposite)
121 {
122  int i;
123  string line, tag;
124  int nfaces, nnodes, nelements;
125  int start, end;
126  stringstream s;
127  NekDouble value;
128  static int zcnt = 1;
129 
130  // Read Zone Header
131  nnodes = nfaces = nelements = 0;
132  while (!m_mshFile.eof())
133  {
134  getline(m_mshFile, line);
135 
136  boost::to_upper(line);
137 
138  // cehck to see if readable data.
139  if (sscanf(line.c_str(), "%lf", &value) == 1)
140  {
141  break;
142  }
143 
144  if ((line.find("NODES") != string::npos) &&
145  (line.find("TOTALNUMFACENODES") == string::npos))
146  {
147  s.clear();
148  s.str(line);
149 
150  tag = s.str();
151  start = tag.find("NODES=");
152  end = tag.find_first_of(',', start);
153  nnodes = atoi(tag.substr(start + 6, end).c_str());
154  }
155 
156  if ((line.find("FACES") != string::npos) &&
157  (line.find("NUMCONNECTEDBOUNDARYFACES") == string::npos))
158  {
159  s.clear();
160  s.str(line);
161 
162  tag = s.str();
163  start = tag.find("FACES=");
164  end = tag.find_first_of(',', start);
165  nfaces = atoi(tag.substr(start + 6, end).c_str());
166  }
167 
168  if (line.find("ELEMENTS") != string::npos)
169  {
170  s.clear();
171  s.str(line);
172 
173  tag = s.str();
174  start = tag.find("ELEMENTS=");
175  end = tag.find_first_of(',', start);
176  nelements = atoi(tag.substr(start + 9, end).c_str());
177  }
178 
179  if (line.find("ZONETYPE") != string::npos)
180  {
181  s.clear();
182  s.str(line);
183 
184  if ((line.find("FEPOLYGON") == string::npos) &&
185  (line.find("FEPOLYHEDRON") == string::npos))
186  {
187  ASSERTL0(false,
188  "Routine only set up for FEPolygon or FEPolyhedron");
189  }
190  }
191  }
192  if (!nnodes) // No zone found
193  {
194  return;
195  }
196 
197  cout << "Setting up zone " << zcnt++;
198 
199  int nodeCount = 3 * nnodes;
200  vector<NekDouble> nodeLocs;
201 
202  while (nodeCount > 0 && !m_mshFile.eof())
203  {
204  s.clear();
205  s.str(line);
206  while (s >> value)
207  {
208  nodeLocs.push_back(value);
209  nodeCount--;
210  }
211  if (nodeCount > 0)
212  {
213  getline(m_mshFile, line);
214  }
215  }
216 
217  ASSERTL0(nodeLocs.size() == 3*nnodes, "Unable to read correct number of "
218  "nodes from Tecplot file");
219 
220  std::vector<NodeSharedPtr> Nodes;
221  for (i = 0; i < nnodes; ++i)
222  {
223  Nodes.push_back(
224  std::shared_ptr<Node>(
225  new Node(i, nodeLocs[i], nodeLocs[i+nnodes],
226  nodeLocs[i+2*nnodes])));
227  }
228 
229  // Read Node count per face
230  getline(m_mshFile, line);
231  if (line.find("node count per face") == string::npos)
232  {
233  if (line.find("face nodes") == string::npos)
234  {
235  getline(m_mshFile, line);
236  }
237  }
238 
239  s.clear();
240  s.str(line);
241 
242  vector<int> Nodes_per_face;
243  if (line.find("node count per face") != string::npos)
244  {
245  int nodes;
246  for (i = 0; i < nfaces; ++i)
247  {
248  m_mshFile >> nodes;
249  ASSERTL0(nodes <= 4,
250  "Can only handle meshes with "
251  "up to four nodes per face");
252  Nodes_per_face.push_back(nodes);
253  }
254  // Read next line
255  getline(m_mshFile, line);
256  }
257 
258  // Read face nodes;
259  if (line.find("face nodes") == string::npos)
260  {
261  getline(m_mshFile, line);
262  }
263  s.clear();
264  s.str(line);
265 
266  vector<vector<int> > FaceNodes;
267 
268  if (line.find("face nodes") != string::npos)
269  {
270 
271  for (i = 0; i < nfaces; ++i)
272  {
273  // check to see if Nodes_per_face is defined and
274  // if not assume 2 nodes for 2D case
275  int nodes = (Nodes_per_face.size()) ? Nodes_per_face[i] : 2;
276 
277  int nodeID;
278  vector<int> Fnodes;
279  for (int j = 0; j < nodes; ++j)
280  {
281 
282  m_mshFile >> nodeID;
283 
284  Fnodes.push_back(nodeID - 1);
285  }
286 
287  FaceNodes.push_back(Fnodes);
288  }
289  }
290  else
291  {
292  ASSERTL0(false, "Failed to find face node section");
293  }
294 
295  // Read left elements
296  Array<OneD, vector<int> > ElementFaces(nelements);
297 
298  // check to see if next line contains left elements
299  getline(m_mshFile, line);
300  if (line.find("left elements") == string::npos)
301  {
302  getline(m_mshFile, line);
303  }
304 
305  if (line.find("left elements") != string::npos)
306  {
307  int elmtID;
308 
309  for (i = 0; i < nfaces; ++i)
310  {
311  m_mshFile >> elmtID;
312 
313  if (elmtID > 0)
314  {
315  ElementFaces[elmtID - 1].push_back(i);
316  }
317  }
318  }
319  else
320  {
321  ASSERTL0(false, "Left element not found");
322  }
323 
324  // check to see if next line contains right elements
325  getline(m_mshFile, line);
326  if (line.find("right elements") == string::npos)
327  {
328  getline(m_mshFile, line);
329  }
330 
331  if (line.find("right elements") != string::npos)
332 
333  {
334  int elmtID;
335 
336  for (i = 0; i < nfaces; ++i)
337  {
338  m_mshFile >> elmtID;
339 
340  if (elmtID > 0)
341  {
342  ElementFaces[elmtID - 1].push_back(i);
343  }
344  }
345 
346  // read to end of line
347  getline(m_mshFile, line);
348  }
349  else
350  {
351  ASSERTL0(false, "Left element not found");
352  }
353 
354  if (Nodes_per_face.size()) // 3D Zone
355  {
356  cout << " (3D) " << endl;
357 
358  // Reset node ordering so that all prism faces have
359  // consistent numbering for singular vertex re-ordering
360  ResetNodes(Nodes, ElementFaces, FaceNodes);
361 
362  m_mesh->m_node = Nodes;
363 
364  // create Prisms/Pyramids first
365  for (i = 0; i < nelements; ++i)
366  {
367  if (ElementFaces[i].size() > 4)
368  {
369  GenElement3D(
370  Nodes, i, ElementFaces[i], FaceNodes, nComposite, true);
371  }
372  }
373 
374  nComposite++;
375 
376  // create Tets second
377  for (i = 0; i < nelements; ++i)
378  {
379  if (ElementFaces[i].size() == 4)
380  {
381  GenElement3D(
382  Nodes, i, ElementFaces[i], FaceNodes, nComposite, true);
383  }
384  }
385  nComposite++;
386 
387  ProcessVertices();
388  }
389  else // 2D Zone
390  {
391  cout << " (2D)" << endl;
392 
393  // find ids of VertNodes from m_mesh->m_vertexSet so that we can
394  // identify
395  for (i = 0; i < Nodes.size(); ++i)
396  {
397  auto it = m_mesh->m_vertexSet.find(Nodes[i]);
398 
399  if (it == m_mesh->m_vertexSet.end())
400  {
401  ASSERTL0(false, "Failed to find face vertex in 3D list");
402  }
403  else
404  {
405  Nodes[i] = *it;
406  }
407  }
408 
409  for (i = 0; i < nelements; ++i)
410  {
411  GenElement2D(Nodes, i, ElementFaces[i], FaceNodes, nComposite);
412  }
413 
414  nComposite++;
415  }
416 }
417 
418 static void PrismLineFaces(int prismid,
419  map<int, int> &facelist,
420  vector<vector<int> > &FacesToPrisms,
421  vector<vector<int> > &PrismsToFaces,
422  vector<bool> &PrismDone);
423 
424 void InputTec::ResetNodes(vector<NodeSharedPtr> &Vnodes,
425  Array<OneD, vector<int> > &ElementFaces,
426  vector<vector<int> > &FaceNodes)
427 {
428  int i, j;
429  Array<OneD, int> NodeReordering(Vnodes.size(), -1);
430  int face1_map[3] = {0, 1, 4};
431  int face3_map[3] = {3, 2, 5};
432  int nodeid = 0;
433  map<int, bool> FacesRenumbered;
434 
435  // Determine Prism triangular face connectivity.
436  vector<vector<int> > FaceToPrisms(FaceNodes.size());
437  vector<vector<int> > PrismToFaces(ElementFaces.num_elements());
438  map<int, int> Prisms;
439 
440  // generate map of prism-faces to prisms and prism to
441  // triangular-faces as well as ids of each prism.
442  for (i = 0; i < ElementFaces.num_elements(); ++i)
443  {
444  // Find Prism (and pyramids!).
445  if (ElementFaces[i].size() == 5)
446  {
447  vector<int> LocTriFaces;
448  // Find triangular faces
449  for (j = 0; j < ElementFaces[i].size(); ++j)
450  {
451  if (FaceNodes[ElementFaces[i][j]].size() == 3)
452  {
453  LocTriFaces.push_back(j);
454  }
455  }
456 
457  if (LocTriFaces.size() == 2) // prism otherwise a pyramid
458  {
459  Prisms[i] = i;
460 
461  PrismToFaces[i].push_back(ElementFaces[i][LocTriFaces[0]]);
462  PrismToFaces[i].push_back(ElementFaces[i][LocTriFaces[1]]);
463 
464  FaceToPrisms[ElementFaces[i][LocTriFaces[0]]].push_back(i);
465  FaceToPrisms[ElementFaces[i][LocTriFaces[1]]].push_back(i);
466  }
467  }
468  }
469 
470  vector<bool> FacesDone(FaceNodes.size(), false);
471  vector<bool> PrismDone(ElementFaces.num_elements(), false);
472 
473  // For every prism find the list of prismatic elements
474  // that represent an aligned block of cells. Then renumber
475  // these blocks consecutativiesly
476  for (auto &PrismIt : Prisms)
477  {
478  int elmtid = PrismIt.first;
479  map<int, int> facelist;
480 
481  if (PrismDone[elmtid])
482  {
483  continue;
484  }
485  else
486  {
487  // Generate list of faces in list
489  elmtid, facelist, FaceToPrisms, PrismToFaces, PrismDone);
490 
491  // loop over faces and number vertices of associated prisms.
492  for (auto &faceIt : facelist)
493  {
494  int faceid = faceIt.second;
495 
496  for (i = 0; i < FaceToPrisms[faceid].size(); ++i)
497  {
498  int prismid = FaceToPrisms[faceid][i];
499 
500  if ((FacesDone[PrismToFaces[prismid][0]] == true) &&
501  (FacesDone[PrismToFaces[prismid][1]] == true))
502  {
503  continue;
504  }
505 
506  Array<OneD, int> Nodes =
507  SortFaceNodes(Vnodes, ElementFaces[prismid], FaceNodes);
508 
509  if ((FacesDone[PrismToFaces[prismid][0]] == false) &&
510  (FacesDone[PrismToFaces[prismid][1]] == false))
511  {
512  // number all nodes consecutive since
513  // already correctly re-arranged.
514  for (i = 0; i < 3; ++i)
515  {
516  if (NodeReordering[Nodes[face1_map[i]]] == -1)
517  {
518  NodeReordering[Nodes[face1_map[i]]] = nodeid++;
519  }
520  }
521 
522  for (i = 0; i < 3; ++i)
523  {
524  if (NodeReordering[Nodes[face3_map[i]]] == -1)
525  {
526  NodeReordering[Nodes[face3_map[i]]] = nodeid++;
527  }
528  }
529  }
530  else if ((FacesDone[PrismToFaces[prismid][0]] == false) &&
531  (FacesDone[PrismToFaces[prismid][1]] == true))
532  {
533  // find node of highest id
534  int max_id1, max_id2;
535 
536  max_id1 = (NodeReordering[Nodes[face3_map[0]]] <
537  NodeReordering[Nodes[face3_map[1]]])
538  ? 1
539  : 0;
540  max_id2 = (NodeReordering[Nodes[face3_map[max_id1]]] <
541  NodeReordering[Nodes[face3_map[2]]])
542  ? 2
543  : max_id1;
544 
545  // add numbering according to order of
546  int id0 = (max_id1 == 1) ? 0 : 1;
547 
548  if (NodeReordering[Nodes[face1_map[id0]]] == -1)
549  {
550  NodeReordering[Nodes[face1_map[id0]]] = nodeid++;
551  }
552 
553  if (NodeReordering[Nodes[face1_map[max_id1]]] == -1)
554  {
555  NodeReordering[Nodes[face1_map[max_id1]]] =
556  nodeid++;
557  }
558 
559  if (NodeReordering[Nodes[face1_map[max_id2]]] == -1)
560  {
561  NodeReordering[Nodes[face1_map[max_id2]]] =
562  nodeid++;
563  }
564  }
565  else if ((FacesDone[PrismToFaces[prismid][0]] == true) &&
566  (FacesDone[PrismToFaces[prismid][1]] == false))
567  {
568  // find node of highest id
569  int max_id1, max_id2;
570 
571  max_id1 = (NodeReordering[Nodes[face1_map[0]]] <
572  NodeReordering[Nodes[face1_map[1]]])
573  ? 1
574  : 0;
575  max_id2 = (NodeReordering[Nodes[face1_map[max_id1]]] <
576  NodeReordering[Nodes[face1_map[2]]])
577  ? 2
578  : max_id1;
579 
580  // add numbering according to order of
581  int id0 = (max_id1 == 1) ? 0 : 1;
582 
583  if (NodeReordering[Nodes[face3_map[id0]]] == -1)
584  {
585  NodeReordering[Nodes[face3_map[id0]]] = nodeid++;
586  }
587 
588  if (NodeReordering[Nodes[face3_map[max_id1]]] == -1)
589  {
590  NodeReordering[Nodes[face3_map[max_id1]]] =
591  nodeid++;
592  }
593 
594  if (NodeReordering[Nodes[face3_map[max_id2]]] == -1)
595  {
596  NodeReordering[Nodes[face3_map[max_id2]]] =
597  nodeid++;
598  }
599  }
600  }
601  }
602  }
603  }
604 
605  // fill in any unset nodes at from other shapes
606  for (i = 0; i < NodeReordering.num_elements(); ++i)
607  {
608  if (NodeReordering[i] == -1)
609  {
610  NodeReordering[i] = nodeid++;
611  }
612  }
613 
614  ASSERTL1(nodeid == NodeReordering.num_elements(),
615  "Have not renumbered all nodes");
616 
617  // Renumbering successfull so resort nodes and faceNodes;
618  for (i = 0; i < FaceNodes.size(); ++i)
619  {
620  for (j = 0; j < FaceNodes[i].size(); ++j)
621  {
622  FaceNodes[i][j] = NodeReordering[FaceNodes[i][j]];
623  }
624  }
625 
626  vector<NodeSharedPtr> save(Vnodes);
627  for (i = 0; i < Vnodes.size(); ++i)
628  {
629  Vnodes[NodeReordering[i]] = save[i];
630  Vnodes[NodeReordering[i]]->SetID(NodeReordering[i]);
631  }
632 }
633 
634 static void PrismLineFaces(int prismid,
635  map<int, int> &facelist,
636  vector<vector<int> > &FaceToPrisms,
637  vector<vector<int> > &PrismToFaces,
638  vector<bool> &PrismDone)
639 {
640  if (PrismDone[prismid] == false)
641  {
642  PrismDone[prismid] = true;
643 
644  // Add faces0
645  int face = PrismToFaces[prismid][0];
646  facelist[face] = face;
647  for (int i = 0; i < FaceToPrisms[face].size(); ++i)
648  {
649  PrismLineFaces(FaceToPrisms[face][i],
650  facelist,
651  FaceToPrisms,
652  PrismToFaces,
653  PrismDone);
654  }
655 
656  // Add faces1
657  face = PrismToFaces[prismid][1];
658  facelist[face] = face;
659  for (int i = 0; i < FaceToPrisms[face].size(); ++i)
660  {
661  PrismLineFaces(FaceToPrisms[face][i],
662  facelist,
663  FaceToPrisms,
664  PrismToFaces,
665  PrismDone);
666  }
667  }
668 }
669 
670 void InputTec::GenElement2D(vector<NodeSharedPtr> &VertNodes,
671  int i,
672  vector<int> &ElementFaces,
673  vector<vector<int> > &FaceNodes,
674  int nComposite)
675 {
676  boost::ignore_unused(i);
677 
679  // set up Node list
680 
681  if (ElementFaces.size() == 3)
682  {
683  elType = LibUtilities::eTriangle;
684  }
685  else if (ElementFaces.size() == 4)
686  {
688  }
689  else
690  {
692  "Not set up for elements which are not Tris or Quads");
693  }
694 
695  // Create element tags
696  vector<int> tags;
697  tags.push_back(nComposite);
698 
699  // make unique node list
700  vector<NodeSharedPtr> nodeList;
701  Array<OneD, int> Nodes = SortEdgeNodes(VertNodes, ElementFaces, FaceNodes);
702  for (int j = 0; j < Nodes.num_elements(); ++j)
703  {
704  nodeList.push_back(VertNodes[Nodes[j]]);
705  }
706 
707  // Create element
708  ElmtConfig conf(elType, 1, true, true);
709  ElementSharedPtr E =
710  GetElementFactory().CreateInstance(elType, conf, nodeList, tags);
711 
712  m_mesh->m_element[E->GetDim()].push_back(E);
713 }
714 
715 void InputTec::GenElement3D(vector<NodeSharedPtr> &VertNodes,
716  int i,
717  vector<int> &ElementFaces,
718  vector<vector<int> > &FaceNodes,
719  int nComposite,
720  bool DoOrient)
721 {
722  boost::ignore_unused(i);
723 
725  // set up Node list
726  Array<OneD, int> Nodes = SortFaceNodes(VertNodes, ElementFaces, FaceNodes);
727  int nnodes = Nodes.num_elements();
728  map<LibUtilities::ShapeType, int> domainComposite;
729 
730  // Set Nodes -- Not sure we need this so could
731  // m_mesh->m_node = VertNodes;
732 
733  // element type
734  if (nnodes == 4)
735  {
737  }
738  else if (nnodes == 5)
739  {
740  elType = LibUtilities::ePyramid;
741  }
742  else if (nnodes == 6)
743  {
744  elType = LibUtilities::ePrism;
745  }
746  else
747  {
749  "Not set up for elements which are not Tets, "
750  "Prisms or Pyramids.");
751  }
752 
753  // Create element tags
754  vector<int> tags;
755  tags.push_back(nComposite);
756 
757  // make unique node list
758  vector<NodeSharedPtr> nodeList;
759  for (int j = 0; j < Nodes.num_elements(); ++j)
760  {
761  nodeList.push_back(VertNodes[Nodes[j]]);
762  }
763 
764  // Create element
765  if (elType != LibUtilities::ePyramid)
766  {
767  ElmtConfig conf(elType, 1, true, true, DoOrient);
768  ElementSharedPtr E =
769  GetElementFactory().CreateInstance(elType, conf, nodeList, tags);
770 
771  m_mesh->m_element[E->GetDim()].push_back(E);
772  }
773  else
774  {
775  cout << "Warning: Pyramid detected " << endl;
776  }
777 }
778 
779 Array<OneD, int> InputTec::SortEdgeNodes(vector<NodeSharedPtr> &Vnodes,
780  vector<int> &ElementFaces,
781  vector<vector<int> > &FaceNodes)
782 {
783  int i, j;
784  Array<OneD, int> returnval;
785 
786  if (ElementFaces.size() == 3) // Triangle
787  {
788  returnval = Array<OneD, int>(3);
789 
790  returnval[0] = FaceNodes[ElementFaces[0]][0];
791  returnval[1] = FaceNodes[ElementFaces[0]][1];
792 
793  // Find third node index;
794  for (i = 0; i < 2; ++i)
795  {
796  if ((FaceNodes[ElementFaces[1]][i] != returnval[0]) &&
797  (FaceNodes[ElementFaces[1]][i] != returnval[1]))
798  {
799  returnval[2] = FaceNodes[ElementFaces[1]][i];
800  break;
801  }
802  }
803  }
804  else if (ElementFaces.size() == 4) // quadrilateral
805  {
806  returnval = Array<OneD, int>(4);
807 
808  int indx0 = FaceNodes[ElementFaces[0]][0];
809  int indx1 = FaceNodes[ElementFaces[0]][1];
810  int indx2, indx3;
811 
812  indx2 = indx3 = -1;
813  // Find third, fourth node index;
814  for (j = 1; j < 4; ++j)
815  {
816  for (i = 0; i < 2; ++i)
817  {
818  if ((FaceNodes[ElementFaces[j]][i] != indx0) &&
819  (FaceNodes[ElementFaces[j]][i] != indx1))
820  {
821  if (indx2 == -1)
822  {
823  indx2 = FaceNodes[ElementFaces[j]][i];
824  }
825  else if (indx2 != -1)
826  {
827  if (FaceNodes[ElementFaces[j]][i] != indx2)
828  {
829  indx3 = FaceNodes[ElementFaces[j]][i];
830  }
831  }
832  }
833  }
834  }
835 
836  ASSERTL1((indx2 != -1) && (indx3 != -1),
837  "Failed to find vertex 3 or 4");
838 
839  // calculate 0-1,
840  Node a = *(Vnodes[indx1]) - *(Vnodes[indx0]);
841  // calculate 0-2,
842  Node b = *(Vnodes[indx2]) - *(Vnodes[indx0]);
843  Node acurlb = a.curl(b);
844 
845  // calculate 2-1,
846  Node c = *(Vnodes[indx1]) - *(Vnodes[indx2]);
847  // calculate 3-2,
848  Node d = *(Vnodes[indx3]) - *(Vnodes[indx2]);
849  Node acurld = a.curl(d);
850 
851  NekDouble acurlb_dot_acurld = acurlb.dot(acurld);
852  if (acurlb_dot_acurld > 0.0)
853  {
854  returnval[0] = indx0;
855  returnval[1] = indx1;
856  returnval[2] = indx2;
857  returnval[3] = indx3;
858  }
859  else
860  {
861  returnval[0] = indx0;
862  returnval[1] = indx1;
863  returnval[2] = indx3;
864  returnval[3] = indx2;
865  }
866  }
867 
868  return returnval;
869 }
870 
871 Array<OneD, int> InputTec::SortFaceNodes(vector<NodeSharedPtr> &Vnodes,
872  vector<int> &ElementFaces,
873  vector<vector<int> > &FaceNodes)
874 {
875 
876  int i, j;
877  Array<OneD, int> returnval;
878 
879  if (ElementFaces.size() == 4) // Tetrahedron
880  {
881  ASSERTL1(FaceNodes[ElementFaces[0]].size() == 3,
882  "Face is not triangular");
883 
884  returnval = Array<OneD, int>(4);
885 
886  int indx0 = FaceNodes[ElementFaces[0]][0];
887  int indx1 = FaceNodes[ElementFaces[0]][1];
888  int indx2 = FaceNodes[ElementFaces[0]][2];
889  int indx3 = -1;
890 
891  // calculate 0-1,
892  Node a = *(Vnodes[indx1]) - *(Vnodes[indx0]);
893  // calculate 0-2,
894  Node b = *(Vnodes[indx2]) - *(Vnodes[indx0]);
895 
896  // Find fourth node index;
897  ASSERTL1(FaceNodes[ElementFaces[1]].size() == 3,
898  "Face is not triangular");
899  for (i = 0; i < 3; ++i)
900  {
901 
902  if ((FaceNodes[ElementFaces[1]][i] != indx0) &&
903  (FaceNodes[ElementFaces[1]][i] != indx1) &&
904  (FaceNodes[ElementFaces[1]][i] != indx2))
905  {
906  indx3 = FaceNodes[ElementFaces[1]][i];
907  break;
908  }
909  }
910 
911  // calculate 0-3,
912  Node c = *(Vnodes[indx3]) - *(Vnodes[indx0]);
913  Node acurlb = a.curl(b);
914 
915  NekDouble acurlb_dotc = acurlb.dot(c);
916  if (acurlb_dotc < 0.0)
917  {
918  returnval[0] = indx0;
919  returnval[1] = indx1;
920  returnval[2] = indx2;
921  returnval[3] = indx3;
922  }
923  else
924  {
925  returnval[0] = indx1;
926  returnval[1] = indx0;
927  returnval[2] = indx2;
928  returnval[3] = indx3;
929  }
930  }
931  else if (ElementFaces.size() == 5) // prism or pyramid
932  {
933  int triface0, triface1;
934  int quadface0, quadface1, quadface2;
935  bool isPrism = true;
936 
937  // find ids of tri faces and first quad face
938  triface0 = triface1 = -1;
939  quadface0 = quadface1 = quadface2 = -1;
940  for (i = 0; i < 5; ++i)
941  {
942  if (FaceNodes[ElementFaces[i]].size() == 3)
943  {
944  if (triface0 == -1)
945  {
946  triface0 = i;
947  }
948  else if (triface1 == -1)
949  {
950  triface1 = i;
951  }
952  else
953  {
954  isPrism = false;
955  }
956  }
957 
958  if (FaceNodes[ElementFaces[i]].size() == 4)
959  {
960  if (quadface0 == -1)
961  {
962  quadface0 = i;
963  }
964  else if (quadface1 == -1)
965  {
966  quadface1 = i;
967  }
968  else if (quadface2 == -1)
969  {
970  quadface2 = i;
971  }
972  }
973  }
974 
975  if (isPrism) // Prism
976  {
977  returnval = Array<OneD, int>(6);
978  }
979  else // Pyramid
980  {
981  returnval = Array<OneD, int>(5);
982  }
983 
984  // find matching nodes between triface0 and triquad0
985  int indx0, indx1, indx2, indx3, indx4;
986 
987  indx0 = indx1 = indx2 = indx3 = indx4 = -1;
988  // Loop over all quad nodes and if they match any
989  // triangular nodes If they do set these to indx0 and
990  // indx1 and if not set it to indx2, indx3
991 
992  for (i = 0; i < 4; ++i)
993  {
994  for (j = 0; j < 3; ++j)
995  {
996  if (FaceNodes[ElementFaces[triface0]][j] ==
997  FaceNodes[ElementFaces[quadface0]][i])
998  {
999  break; // same node break
1000  }
1001  }
1002 
1003  if (j == 3) // Vertex not in quad face
1004  {
1005  if (indx2 == -1)
1006  {
1007  indx2 = FaceNodes[ElementFaces[quadface0]][i];
1008  }
1009  else if (indx3 == -1)
1010  {
1011  indx3 = FaceNodes[ElementFaces[quadface0]][i];
1012  }
1013  else
1014  {
1015  ASSERTL0(
1016  false,
1017  "More than two vertices do not match triangular face");
1018  }
1019  }
1020  else // if found match then set indx0,indx1;
1021  {
1022  if (indx0 == -1)
1023  {
1024  indx0 = FaceNodes[ElementFaces[quadface0]][i];
1025  }
1026  else
1027  {
1028  indx1 = FaceNodes[ElementFaces[quadface0]][i];
1029  }
1030  }
1031  }
1032 
1033  // Finally check for top vertex
1034  for (int i = 0; i < 3; ++i)
1035  {
1036  if ((FaceNodes[ElementFaces[triface0]][i] != indx0) &&
1037  (FaceNodes[ElementFaces[triface0]][i] != indx1) &&
1038  (FaceNodes[ElementFaces[triface0]][i] != indx2))
1039  {
1040  indx4 = FaceNodes[ElementFaces[triface0]][i];
1041  break;
1042  }
1043  }
1044 
1045  // calculate 0-1,
1046  Node a = *(Vnodes[indx1]) - *(Vnodes[indx0]);
1047  // calculate 0-4,
1048  Node b = *(Vnodes[indx4]) - *(Vnodes[indx0]);
1049  // calculate 0-2,
1050  Node c = *(Vnodes[indx2]) - *(Vnodes[indx0]);
1051  Node acurlb = a.curl(b);
1052 
1053  NekDouble acurlb_dotc = acurlb.dot(c);
1054  if (acurlb_dotc < 0.0)
1055  {
1056  returnval[0] = indx0;
1057  returnval[1] = indx1;
1058  returnval[4] = indx4;
1059  }
1060  else
1061  {
1062  returnval[0] = indx1;
1063  returnval[1] = indx0;
1064  returnval[4] = indx4;
1065  }
1066 
1067  // check to see if two vertices are shared between one of the other
1068  // faces
1069  // to define which is indx2 and indx3
1070 
1071  int cnt = 0;
1072  for (int i = 0; i < 4; ++i)
1073  {
1074  if ((FaceNodes[ElementFaces[quadface1]][i] == returnval[1]) ||
1075  (FaceNodes[ElementFaces[quadface1]][i] == indx2))
1076  {
1077  cnt++;
1078  }
1079  }
1080 
1081  if (cnt == 2) // have two matching vertices
1082  {
1083  returnval[2] = indx2;
1084  returnval[3] = indx3;
1085  }
1086  else
1087  {
1088  cnt = 0;
1089  for (int i = 0; i < 4; ++i)
1090  {
1091  if ((FaceNodes[ElementFaces[quadface2]][i] == returnval[1]) ||
1092  (FaceNodes[ElementFaces[quadface2]][i] == indx2))
1093  {
1094  cnt++;
1095  }
1096  }
1097 
1098  if (cnt != 2) // neither of the other faces has two matching nodes
1099  // so reverse
1100  {
1101  returnval[2] = indx3;
1102  returnval[3] = indx2;
1103  }
1104  else // have two matching vertices
1105  {
1106  returnval[2] = indx2;
1107  returnval[3] = indx3;
1108  }
1109  }
1110 
1111  if (isPrism == true)
1112  {
1113  // finally need to find last vertex from second triangular face.
1114  for (int i = 0; i < 3; ++i)
1115  {
1116  if ((FaceNodes[ElementFaces[triface1]][i] != indx2) &&
1117  (FaceNodes[ElementFaces[triface1]][i] != indx3) &&
1118  (FaceNodes[ElementFaces[triface1]][i] != indx3))
1119  {
1120  returnval[5] = FaceNodes[ElementFaces[triface1]][i];
1121  break;
1122  }
1123  }
1124  }
1125  }
1126  else
1127  {
1128  ASSERTL0(false, "SortFaceNodes not set up for this number of faces");
1129  }
1130 
1131  return returnval;
1132 }
1133 }
1134 }
void GenElement3D(std::vector< NekMeshUtils::NodeSharedPtr > &Nodes, int i, std::vector< int > &ElementFaces, std::vector< std::vector< int > > &FaceNodes, int ncomposite, bool DoOrient)
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Basic information about an element.
Definition: ElementConfig.h:49
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mod...
Definition: ErrorUtil.hpp:209
io::filtering_istream m_mshFile
Input stream.
STL namespace.
NEKMESHUTILS_EXPORT NekDouble dot(const Node &pSrc) const
Definition: Node.h:161
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
Array< OneD, int > SortFaceNodes(std::vector< NekMeshUtils::NodeSharedPtr > &Nodes, std::vector< int > &ElementFaces, std::vector< std::vector< int > > &FaceNodes)
Represents a point in the domain.
Definition: Node.h:62
virtual void Process()
Populate and validate required data structures.
NEKMESHUTILS_EXPORT void PrintSummary()
Print summary of elements.
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::pair< ModuleType, std::string > ModuleKey
virtual NEKMESHUTILS_EXPORT void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
Array< OneD, int > SortEdgeNodes(std::vector< NekMeshUtils::NodeSharedPtr > &Nodes, std::vector< int > &ElementFaces, std::vector< std::vector< int > > &FaceNodes)
virtual NEKMESHUTILS_EXPORT void ProcessElements()
Generate element IDs.
double NekDouble
void ReadZone(int &nComposite)
NEKMESHUTILS_EXPORT Node curl(const Node &pSrc) const
Definition: Node.h:166
Abstract base class for input modules.
static void PrismLineFaces(int prismid, map< int, int > &facelist, vector< vector< int > > &FacesToPrisms, vector< vector< int > > &PrismsToFaces, vector< bool > &PrismDone)
Definition: InputStar.cpp:420
virtual NEKMESHUTILS_EXPORT void ProcessVertices()
Extract element vertices.
void GenElement2D(std::vector< NekMeshUtils::NodeSharedPtr > &Nodes, int i, std::vector< int > &ElementFaces, std::vector< std::vector< int > > &FaceNodes, int ncomposite)
virtual NEKMESHUTILS_EXPORT void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
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
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
virtual NEKMESHUTILS_EXPORT void ProcessComposites()
Generate composites.
void ResetNodes(std::vector< NekMeshUtils::NodeSharedPtr > &Nodes, Array< OneD, std::vector< int > > &ElementFaces, std::vector< std::vector< int > > &FaceNodes)
ModuleFactory & GetModuleFactory()