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