Nektar++
MeshConvert/Module.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Module.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: Abstract input/output modules.
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
36 #include <string>
37 #include "Module.h"
38 
39 using namespace std;
40 
41 namespace Nektar
42 {
43  namespace Utilities
44  {
45  /**
46  * Returns an instance of the module factory, held as a singleton.
47  */
49  {
50  typedef Loki::SingletonHolder<ModuleFactory,
51  Loki::CreateUsingNew,
52  Loki::NoDestroy,
53  Loki::SingleThreaded> Type;
54  return Type::Instance();
55  }
56 
57  /**
58  * Prints a given module key to a stream.
59  */
60  std::ostream& operator<<(std::ostream& os, const ModuleKey& rhs)
61  {
62  return os << ModuleTypeMap[rhs.first] << ": " << rhs.second;
63  }
64 
65  InputModule::InputModule(MeshSharedPtr m) : Module(m)
66  {
67  m_config["infile"] = ConfigOption(false, "", "Input filename.");
68  }
69 
71  {
72  m_config["outfile"] = ConfigOption(false, "", "Output filename.");
73  }
74 
75  /**
76  * @brief Open a file for input.
77  */
79  {
80  string fname = m_config["infile"].as<string>();
81  m_mshFile.open(fname.c_str());
82  if (!m_mshFile.good())
83  {
84  cerr << "Error opening file: " << fname << endl;
85  abort();
86  }
87  }
88 
89  /**
90  * @brief Open a file for output.
91  */
93  {
94  string fname = m_config["outfile"].as<string>();
95  m_mshFile.open(fname.c_str());
96  if (!m_mshFile.good())
97  {
98  cerr << "Error opening file: " << fname << endl;
99  abort();
100  }
101  }
102 
103  /**
104  * @brief Create a unique set of mesh vertices from elements stored in
105  * Mesh::element.
106  *
107  * Each element is processed in turn and the vertices extracted and
108  * inserted into #m_vertexSet, which at the end of the routine
109  * contains all unique vertices in the mesh.
110  */
112  {
113  vector<ElementSharedPtr> &elmt = m_mesh->m_element[m_mesh->m_expDim];
114 
115  m_mesh->m_vertexSet.clear();
116 
117  for (int i = 0, vid = 0; i < elmt.size(); ++i)
118  {
119  for (int j = 0; j < elmt[i]->GetVertexCount(); ++j)
120  {
121  pair<NodeSet::iterator,bool> testIns =
122  m_mesh->m_vertexSet.insert(elmt[i]->GetVertex(j));
123 
124  if (testIns.second)
125  {
126  (*(testIns.first))->m_id = vid++;
127  }
128  else
129  {
130  elmt[i]->SetVertex(j,*testIns.first);
131  }
132  }
133  }
134  }
135 
136  /**
137  * @brief Create a unique set of mesh edges from elements stored in
138  * Mesh::element.
139  *
140  * All elements are first scanned and a list of unique, enumerated
141  * edges produced in #m_edgeSet. Since each element generated its
142  * edges independently, we must now ensure that each element only uses
143  * edge objects from the #m_edgeSet set This ensures there are no
144  * duplicate edge objects. Finally, we scan the list of elements for
145  * 1-D boundary elements which correspond to an edge in
146  * #m_edgeSet. For such elements, we set its edgeLink to reference the
147  * corresponding edge in #m_edgeSet.
148  *
149  * This routine only proceeds if the expansion dimension is 2 or 3.
150  */
151  void Module::ProcessEdges(bool ReprocessEdges)
152  {
153  if (m_mesh->m_expDim < 2) return;
154 
155  if(ReprocessEdges)
156  {
157  vector<ElementSharedPtr> &elmt = m_mesh->m_element[m_mesh->m_expDim];
158 
159  m_mesh->m_edgeSet.clear();
160 
161  // Scan all elements and generate list of unique edges
162  for (int i = 0, eid = 0; i < elmt.size(); ++i)
163  {
164  for (int j = 0; j < elmt[i]->GetEdgeCount(); ++j)
165  {
166  pair<EdgeSet::iterator,bool> testIns;
167  EdgeSharedPtr ed = elmt[i]->GetEdge(j);
168  testIns = m_mesh->m_edgeSet.insert(ed);
169 
170  if (testIns.second)
171  {
172  (*(testIns.first))->m_id = eid++;
173  }
174  else
175  {
176  EdgeSharedPtr e2 = *(testIns.first);
177  elmt[i]->SetEdge(j, e2);
178  if (e2->m_edgeNodes.size() == 0 &&
179  ed->m_edgeNodes.size() > 0)
180  {
181  e2->m_curveType = ed->m_curveType;
182  e2->m_edgeNodes = ed->m_edgeNodes;
183 
184  // Reverse nodes if appropriate.
185  if (e2->m_n1->m_id != ed->m_n1->m_id)
186  {
187  reverse(e2->m_edgeNodes.begin(),
188  e2->m_edgeNodes.end());
189  }
190  }
191 
192  // Update edge to element map.
193  (*(testIns.first))->m_elLink.push_back(
194  pair<ElementSharedPtr,int>(elmt[i],j));
195  }
196  }
197  }
198  }
199 
200  // Create links for 1D elements
201  for (int i = 0; i < m_mesh->m_element[1].size(); ++i)
202  {
203  NodeSharedPtr v0 = m_mesh->m_element[1][i]->GetVertex(0);
204  NodeSharedPtr v1 = m_mesh->m_element[1][i]->GetVertex(1);
205  vector<NodeSharedPtr> edgeNodes;
206  EdgeSharedPtr E = boost::shared_ptr<Edge>(
207  new Edge(v0, v1, edgeNodes,
208  m_mesh->m_element[1][i]->GetConf().m_edgeCurveType));
209  EdgeSet::iterator it = m_mesh->m_edgeSet.find(E);
210  if (it == m_mesh->m_edgeSet.end())
211  {
212  cerr << "Cannot find corresponding element edge for "
213  << "1D element " << i << endl;
214  abort();
215  }
216  m_mesh->m_element[1][i]->SetEdgeLink(*it);
217 
218  // Update 2D element boundary map.
219  ASSERTL0((*it)->m_elLink.size() != 0,
220  "Empty boundary map!");
221  ASSERTL0((*it)->m_elLink.size() == 1,
222  "Too many elements in boundary map!");
223  pair<ElementSharedPtr, int> eMap = (*it)->m_elLink.at(0);
224  eMap.first->SetBoundaryLink(eMap.second, i);
225 
226  // Copy curvature to edge.
227  if ((*it)->m_edgeNodes.size() > 0)
228  {
229  ElementSharedPtr edge = m_mesh->m_element[1][i];
230  if (edge->GetVertex(0) == (*it)->m_n1)
231  {
232  edge->SetVolumeNodes((*it)->m_edgeNodes);
233  }
234  }
235  }
236  }
237 
238 
239  /**
240  * @brief Create a unique set of mesh faces from elements stored in
241  * Mesh::element.
242  *
243  * All elements are scanned and a unique list of enumerated faces is
244  * produced in #m_faceSet. Since elements created their own faces
245  * independently, we examine each element only uses face objects from
246  * #m_faceSet. Duplicate faces of those in #m_face are replaced with
247  * the corresponding entry in #m_faceSet. Finally, we scan the list of
248  * elements for 2-D boundary faces which correspond to faces in
249  * #m_faceSet. For such elements, we set its faceLink to reference the
250  * corresponding face in #m_faceSet.
251  *
252  * This routine only proceeds if the expansion dimension is 3.
253  */
254  void Module::ProcessFaces(bool ReprocessFaces)
255  {
256  if (m_mesh->m_expDim < 3) return;
257 
258  if(ReprocessFaces)
259  {
260  vector<ElementSharedPtr> &elmt = m_mesh->m_element[m_mesh->m_expDim];
261 
262  m_mesh->m_faceSet.clear();
263 
264  // Scan all elements and generate list of unique faces
265  for (int i = 0, fid = 0; i < elmt.size(); ++i)
266  {
267  for (int j = 0; j < elmt[i]->GetFaceCount(); ++j)
268  {
269  pair<FaceSet::iterator,bool> testIns;
270  testIns = m_mesh->m_faceSet.insert(elmt[i]->GetFace(j));
271 
272  if (testIns.second)
273  {
274  (*(testIns.first))->m_id = fid++;
275  }
276  else
277  {
278  elmt[i]->SetFace(j,*testIns.first);
279  // Update face to element map.
280  (*(testIns.first))->m_elLink.push_back(
281  pair<ElementSharedPtr,int>(elmt[i],j));
282  }
283  }
284  }
285  }
286 
287  // Create links for 2D elements
288  for (int i = 0; i < m_mesh->m_element[2].size(); ++i)
289  {
290  vector<NodeSharedPtr> vertices = m_mesh->m_element[2][i]->GetVertexList();
291  vector<NodeSharedPtr> faceNodes;
292  vector<EdgeSharedPtr> edgeList = m_mesh->m_element[2][i]->GetEdgeList();
293  FaceSharedPtr F = boost::shared_ptr<Face>(
294  new Face(vertices, faceNodes, edgeList,
295  m_mesh->m_element[2][i]->GetConf().m_faceCurveType));
296  FaceSet::iterator it = m_mesh->m_faceSet.find(F);
297  if (it == m_mesh->m_faceSet.end())
298  {
299  cout << "Cannot find corresponding element face for 2D "
300  << "element " << i << endl;
301  abort();
302  }
303  m_mesh->m_element[2][i]->SetFaceLink(*it);
304 
305  // Update 3D element boundary map.
306  ASSERTL0((*it)->m_elLink.size() != 0,
307  "Empty element link map!");
308  ASSERTL0((*it)->m_elLink.size() == 1,
309  "Too many elements in element link map!");
310  pair<ElementSharedPtr, int> eMap = (*it)->m_elLink.at(0);
311  eMap.first->SetBoundaryLink(eMap.second, i);
312  }
313  }
314 
315  /**
316  * @brief Enumerate elements stored in Mesh::element.
317  *
318  * For all elements of equal dimension to the mesh dimension, we
319  * enumerate sequentially. All other elements in the list should be of
320  * lower dimension and have ID set by a corresponding edgeLink or
321  * faceLink (as set in #ProcessEdges or #ProcessFaces).
322  */
324  {
325  int cnt = 0;
326  for (int i = 0; i < m_mesh->m_element[m_mesh->m_expDim].size(); ++i)
327  {
328  m_mesh->m_element[m_mesh->m_expDim][i]->SetId(cnt++);
329  }
330  }
331 
332  /**
333  * @brief Generate a list of composites (groups of elements) from tag
334  * IDs stored in mesh vertices/edges/faces/elements.
335  *
336  * Each element is assigned to a composite ID by an input module. First
337  * we scan the element list and generate a list of composite IDs. We
338  * then generate the composite objects and populate them with a second
339  * scan through the element list.
340  */
342  {
343  m_mesh->m_composite.clear();
344 
345  // For each element, check to see if a composite has been
346  // created. If not, create a new composite. Otherwise, add the
347  // element to the composite.
348  for (int d = 0; d <= m_mesh->m_expDim; ++d)
349  {
350  vector<ElementSharedPtr> &elmt = m_mesh->m_element[d];
351 
352  for (int i = 0; i < elmt.size(); ++i)
353  {
355  unsigned int tagid = elmt[i]->GetTagList()[0];
356 
357  it = m_mesh->m_composite.find(tagid);
358 
359  if (it == m_mesh->m_composite.end())
360  {
361  CompositeSharedPtr tmp = boost::shared_ptr<Composite>(
362  new Composite());
363  pair<CompositeMap::iterator, bool> testIns;
364  tmp->m_id = tagid;
365  tmp->m_tag = elmt[i]->GetTag();
366  if(m_mesh->m_faceLabels.count(tmp->m_id) != 0)
367  {
368  tmp->m_label = m_mesh->m_faceLabels[tmp->m_id];
369  }
370 
371  testIns = m_mesh->m_composite.insert(
372  pair<unsigned int, CompositeSharedPtr>(tagid,tmp));
373  it = testIns.first;
374  }
375 
376  if (elmt[i]->GetTag() != it->second->m_tag)
377  {
378  cout << "Different types of elements in same composite!" << endl;
379  cout << " -> Composite uses " << it->second->m_tag << endl;
380  cout << " -> Element uses " << elmt[i]->GetTag() << endl;
381  cout << "Have you specified physical volumes and surfaces?" << endl;
382  }
383  it->second->m_items.push_back(elmt[i]);
384  }
385  }
386  }
387 
388  /**
389  * @brief Reorder node IDs so that prisms and tetrahedra are aligned
390  * correctly.
391  *
392  * Orientation of prism lines (i.e. a large prism which has been split
393  * into subprisms) cannot be guaranteed when elements are created
394  * one-by-one, or when periodic boundary conditions are used. This
395  * routine uses the following strategy:
396  *
397  * - Destroy the existing node numbering.
398  * - Detect a line of prisms using the PrismLines routine.
399  * - For each line, renumber node IDs consistently so that highest ID
400  * per-element corresponds to the line of collapsed coordinate
401  * points.
402  * - Recreate each prism in the line using the new ordering, and apply
403  * the existing OrientPrism routine to orient nodes accordingly.
404  * - When all prism lines are processed, recreate all tetrahedra using
405  * the existing orientation code.
406  * - Finally renumber any other nodes (i.e. those belonging to
407  * hexahedra).
408  *
409  * The last step is to eliminate duplicate edges/faces and reenumerate.
410  *
411  * NOTE: This routine does not copy face-interior high-order information
412  * yet!
413  */
415  {
416  // Loop over elements and extract any that are prisms.
417  int i, j, k;
418 
419  if (m_mesh->m_expDim < 3)
420  {
421  return;
422  }
423 
424  map<int, int> lines;
425  set<int> prismsDone, tetsDone;
426  PerMap::iterator pIt;
427 
428  // Compile list of prisms and tets.
429  for (i = 0; i < m_mesh->m_element[3].size(); ++i)
430  {
431  ElementSharedPtr el = m_mesh->m_element[3][i];
432 
433  if (el->GetConf().m_e == LibUtilities::ePrism)
434  {
435  prismsDone.insert(i);
436  }
437  else if (el->GetConf().m_e == LibUtilities::eTetrahedron)
438  {
439  tetsDone.insert(i);
440  }
441  }
442 
443  // Destroy existing node numbering.
445  for (it = m_mesh->m_vertexSet.begin(); it != m_mesh->m_vertexSet.end(); ++it)
446  {
447  (*it)->m_id = -1;
448  }
449 
450  // Counter for new node IDs.
451  int nodeId = 0;
452  int prismTris[2][3] = {{0,1,4}, {3,2,5}};
453 
454  // Warning flag for high-order curvature information.
455  bool warnCurvature = false;
456 
457  // facesDone tracks face IDs inside prisms which have already been
458  // aligned.
459  boost::unordered_set<int> facesDone;
461 
462  // Loop over prisms until we've found all lines of prisms.
463  while (prismsDone.size() > 0)
464  {
465  vector<ElementSharedPtr> line;
466 
467  // Call PrismLines to identify all prisms connected to
468  // prismDone.begin() and place them in line[].
469  PrismLines(*prismsDone.begin(), perFaces, prismsDone, line);
470 
471  // Loop over each prism, figure out which line of vertices
472  // contains the vertex with highest ID.
473  for (i = 0; i < line.size(); ++i)
474  {
475  // Copy tags and nodes from existing element.
476  vector<int> tags = line[i]->GetTagList();
477  vector<NodeSharedPtr> nodes = line[i]->GetVertexList();
478 
479  // See if either face of this prism has been renumbered
480  // already.
481  FaceSharedPtr f[2] = {
482  line[i]->GetFace(1), line[i]->GetFace(3)
483  };
484 
485  fIt[0] = facesDone.find(f[0]->m_id);
486  fIt[1] = facesDone.find(f[1]->m_id);
487 
488  // See if either of these faces is periodic. If it is, then
489  // assign ids accordingly.
490  for (j = 0; j < 2; ++j)
491  {
492  pIt = perFaces.find(f[j]->m_id);
493 
494  if (pIt == perFaces.end())
495  {
496  continue;
497  }
498 
499  fIt2 = facesDone.find(pIt->second.first->m_id);
500 
501  if (fIt[j] == facesDone.end() &&
502  fIt2 != facesDone.end())
503  {
504  fIt[j] = fIt2;
505  }
506  }
507 
508  if (fIt[0] != facesDone.end() &&
509  fIt[1] != facesDone.end())
510  {
511  // Should not be the case that both faces have already
512  // been renumbered.
513  ASSERTL0(false, "Renumbering error!");
514  }
515  else if (fIt[0] == facesDone.end() &&
516  fIt[1] == facesDone.end())
517  {
518  // Renumber both faces.
519  for (j = 0; j < 2; ++j)
520  {
521  for (k = 0; k < 3; ++k)
522  {
523  NodeSharedPtr n = nodes[prismTris[j][k]];
524  if (n->m_id == -1)
525  {
526  n->m_id = nodeId++;
527  }
528  }
529  }
530 
531  facesDone.insert(f[0]->m_id);
532  facesDone.insert(f[1]->m_id);
533  }
534  else
535  {
536  // Renumber face. t identifies the face not yet
537  // numbered, o identifies the other face.
538  int t = fIt[0] == facesDone.end() ? 0 : 1;
539  int o = (t+1) % 2;
540  ASSERTL1(fIt[o] != facesDone.end(),"Renumbering error");
541 
542  // Determine which of the three vertices on the 'other'
543  // face corresponds to the highest ID - this signifies
544  // the singular point of the line of prisms.
545  int tmp1[3] = {
546  nodes[prismTris[o][0]]->m_id,
547  nodes[prismTris[o][1]]->m_id,
548  nodes[prismTris[o][2]]->m_id
549  };
550  int tmp2[3] = {0,1,2};
551 
552  if (tmp1[0] > tmp1[1])
553  {
554  swap(tmp1[0], tmp1[1]);
555  swap(tmp2[0], tmp2[1]);
556  }
557 
558  if (tmp1[1] > tmp1[2])
559  {
560  swap(tmp1[1], tmp1[2]);
561  swap(tmp2[1], tmp2[2]);
562  }
563 
564  if (tmp1[0] > tmp1[2])
565  {
566  swap(tmp1[0], tmp1[2]);
567  swap(tmp2[0], tmp2[2]);
568  }
569 
570  // Renumber this face so that highest ID matches.
571  for (j = 0; j < 3; ++j)
572  {
573  NodeSharedPtr n = nodes[prismTris[t][tmp2[j]]];
574  if (n->m_id == -1)
575  {
576  n->m_id = nodeId++;
577  }
578  }
579 
580  facesDone.insert(f[t]->m_id);
581  }
582 
583  for (j = 0; j < 6; ++j)
584  {
585  ASSERTL1(nodes[j]->m_id != -1, "Renumbering error");
586  }
587 
588  // Recreate prism with the new ordering.
589  ElmtConfig conf(LibUtilities::ePrism, 1, false, false, true);
591  LibUtilities::ePrism, conf, nodes, tags);
592 
593  // Now transfer high-order information back into
594  // place. TODO: Face curvature.
595  for (j = 0; j < 9; ++j)
596  {
597  EdgeSharedPtr e1 = line[i]->GetEdge(j);
598  for (k = 0; k < 9; ++k)
599  {
600  EdgeSharedPtr e2 = el->GetEdge(k);
601  if (e1->m_n1 == e2->m_n1 && e1->m_n2 == e2->m_n2)
602  {
603  e2->m_edgeNodes = e1->m_edgeNodes;
604  }
605  else if (e1->m_n1 == e2->m_n1 && e1->m_n2 == e2->m_n2)
606  {
607  e2->m_edgeNodes = e1->m_edgeNodes;
608  std::reverse(e2->m_edgeNodes.begin(),
609  e2->m_edgeNodes.end());
610  }
611  }
612  }
613 
614  // Warn users that we're throwing away face curvature
615  if (!warnCurvature)
616  {
617  for (j = 0; j < 5; ++j)
618  {
619  if (line[i]->GetFace(j)->m_faceNodes.size() > 0)
620  {
621  warnCurvature = true;
622  break;
623  }
624  }
625  }
626 
627  // Replace old prism.
628  m_mesh->m_element[3][line[i]->GetId()] = el;
629  }
630  }
631 
632  if (warnCurvature)
633  {
634  cerr << "[ReorderPrisms] WARNING: Face curvature detected in "
635  << "some prisms; this will be ignored in further module "
636  << "evaluations."
637  << endl;
638  }
639 
640  // Loop over periodic faces, enumerate vertices.
641  for (pIt = perFaces.begin(); pIt != perFaces.end(); ++pIt)
642  {
643  FaceSharedPtr f2 = pIt->second.first;
644  FaceSharedPtr f1 = perFaces[f2->m_id].first;
645  vector<int> perVerts = pIt->second.second;
646  int nVerts = perVerts.size();
647 
648  // Number periodic vertices first.
649  for (j = 0; j < nVerts; ++j)
650  {
651  NodeSharedPtr n1 = f1->m_vertexList[j];
652  NodeSharedPtr n2 = f2->m_vertexList[perVerts[j]];
653 
654  if (n1->m_id == -1 && n2->m_id == -1)
655  {
656  n1->m_id = nodeId++;
657  n2->m_id = nodeId++;
658  }
659  else if (n1->m_id != -1 && n2->m_id != -1)
660  {
661  continue;
662  }
663  else
664  {
665  ASSERTL0(false, "Periodic face renumbering error");
666  }
667  }
668  }
669 
670  // Recreate tets.
671  set<int>::iterator it2;
672  for (it2 = tetsDone.begin(); it2 != tetsDone.end(); ++it2)
673  {
674  ElementSharedPtr el = m_mesh->m_element[3][*it2];
675  vector<NodeSharedPtr> nodes = el->GetVertexList();
676  vector<int> tags = el->GetTagList();
677 
678  for (i = 0; i < 4; ++i)
679  {
680  if (nodes[i]->m_id == -1)
681  {
682  nodes[i]->m_id = nodeId++;
683  }
684  }
685 
686  // Recreate tet.
687  ElmtConfig conf(LibUtilities::eTetrahedron, 1, false, false, true);
688  m_mesh->m_element[3][*it2] = GetElementFactory().CreateInstance(
689  LibUtilities::eTetrahedron, conf, nodes, tags);
690  }
691 
692  // Enumerate rest of vertices.
693  for (it = m_mesh->m_vertexSet.begin(); it != m_mesh->m_vertexSet.end(); ++it)
694  {
695  if ((*it)->m_id == -1)
696  {
697  (*it)->m_id = nodeId++;
698  }
699  }
700 
701  ProcessEdges ();
702  ProcessFaces ();
703  ProcessElements();
704  }
705 
706  void Module::PrismLines(int prism,
707  PerMap &perFaces,
708  set<int> &prismsDone,
709  vector<ElementSharedPtr> &line)
710  {
711  int i;
712  set<int>::iterator it = prismsDone.find(prism);
713  PerMap::iterator it2;
714 
715  if (it == prismsDone.end())
716  {
717  return;
718  }
719 
720  // Remove this prism from the list.
721  prismsDone.erase(it);
722  line.push_back(m_mesh->m_element[3][prism]);
723 
724  // Now find prisms connected to this one through a triangular face.
725  for (i = 1; i <= 3; i += 2)
726  {
727  FaceSharedPtr f = m_mesh->m_element[3][prism]->GetFace(i);
728  int nextId;
729 
730  // See if this face is periodic.
731  it2 = perFaces.find(f->m_id);
732 
733  if (it2 != perFaces.end())
734  {
735  int id2 = it2->second.first->m_id;
736  nextId = it2->second.first->m_elLink[0].first->GetId();
737  perFaces.erase(it2);
738  perFaces.erase(id2);
739  PrismLines(nextId, perFaces, prismsDone, line);
740  }
741 
742  // Nothing else connected to this face.
743  if (f->m_elLink.size() == 1)
744  {
745  continue;
746  }
747 
748  nextId = f->m_elLink[0].first->GetId();
749  if (nextId == m_mesh->m_element[3][prism]->GetId())
750  {
751  nextId = f->m_elLink[1].first->GetId();
752  }
753 
754  PrismLines(nextId, perFaces, prismsDone, line);
755  }
756  }
757 
758  /**
759  * @brief Register a configuration option with a module.
760  */
761  void Module::RegisterConfig(string key, string val)
762  {
764  if (it == m_config.end())
765  {
766  cerr << "WARNING: Unrecognised config option " << key
767  << ", proceeding anyway." << endl;
768  }
769 
770  it->second.beenSet = true;
771 
772  if (it->second.isBool)
773  {
774  it->second.value = "1";
775  }
776  else
777  {
778  it->second.value = val;
779  }
780  }
781 
782  /**
783  * @brief Print out all configuration options for a module.
784  */
785  void Module::PrintConfig()
786  {
788 
789  if (m_config.size() == 0)
790  {
791  cerr << "No configuration options for this module." << endl;
792  return;
793  }
794 
795  for (it = m_config.begin(); it != m_config.end(); ++it)
796  {
797  cerr << setw(10) << it->first << ": " << it->second.desc
798  << endl;
799  }
800  }
801 
802  /**
803  * @brief Sets default configuration options for those which have not
804  * been set.
805  */
806  void Module::SetDefaults()
807  {
809 
810  for (it = m_config.begin(); it != m_config.end(); ++it)
811  {
812  if (!it->second.beenSet)
813  {
814  it->second.value = it->second.defValue;
815  }
816  }
817  }
818 
819  /**
820  * @brief Print a brief summary of information.
821  */
823  {
824  // Compute the number of full-dimensional elements and boundary
825  // elements.
826  cerr << "Expansion dimension is " << m_mesh->m_expDim << endl;
827  cerr << "Space dimension is " << m_mesh->m_spaceDim << endl;
828  cerr << "Read " << m_mesh->m_node.size() << " nodes" << endl;
829  cerr << "Read " << m_mesh->GetNumElements() << " "
830  << m_mesh->m_expDim << "-D elements" << endl;
831  cerr << "Read " << m_mesh->GetNumBndryElements()
832  << " boundary elements" << endl;
833  }
834  }
835 }
LibUtilities::NekFactory< ModuleKey, Module, FieldSharedPtr > ModuleFactory
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:135
std::ifstream m_mshFile
Input stream.
pair< ModuleType, string > ModuleKey
tBaseSharedPtr CreateInstance(tKey idKey BOOST_PP_COMMA_IF(MAX_PARAM) BOOST_PP_ENUM_BINARY_PARAMS(MAX_PARAM, tParam, x))
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:162
Represents an edge which joins two points.
Definition: MeshElements.h:227
boost::shared_ptr< Edge > EdgeSharedPtr
Shared pointer to an edge.
Definition: MeshElements.h:318
map< string, ConfigOption > m_config
List of configuration values.
STL namespace.
MeshSharedPtr m_mesh
Mesh object.
boost::shared_ptr< Face > FaceSharedPtr
Shared pointer to a face.
Definition: MeshElements.h:550
void RegisterConfig(string key, string value)
Register a configuration option with a module.
boost::shared_ptr< Node > NodeSharedPtr
Shared pointer to a Node.
Definition: MeshElements.h:195
boost::shared_ptr< Composite > CompositeSharedPtr
Shared pointer to a composite.
virtual void ProcessEdges(bool ReprocessEdges=true)
Extract element edges.
boost::shared_ptr< Element > ElementSharedPtr
Shared pointer to an element.
Definition: MeshElements.h:63
std::ostream & operator<<(std::ostream &os, const BasisKey &rhs)
Definition: Basis.cpp:85
virtual void ProcessVertices()
Extract element vertices.
virtual void ProcessElements()
Generate element IDs.
map< int, pair< FaceSharedPtr, vector< int > > > PerMap
boost::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
void PrismLines(int prism, PerMap &perFaces, set< int > &prismsDone, vector< ElementSharedPtr > &line)
Basic information about an element.
Definition: MeshElements.h:583
virtual void ProcessComposites()
Generate composites.
boost::shared_ptr< GeometryVector > Composite
Definition: MeshGraph.h:111
void PrintSummary()
Print summary of elements.
void PrintConfig()
Print out all configuration options for a module.
Represents a command-line configuration option.
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator
virtual void ProcessFaces(bool ReprocessFaces=true)
Extract element faces.
void ReorderPrisms(PerMap &perFaces)
Reorder node IDs so that prisms and tetrahedra are aligned correctly.
std::ofstream m_mshFile
Output stream.
Represents a face comprised of three or more edges.
Definition: MeshElements.h:352
void OpenStream()
Open a file for output.
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:165
void SetDefaults()
Sets default configuration options for those which have not been set.
void OpenStream()
Open a file for input.
ElementFactory & GetElementFactory()
ModuleFactory & GetModuleFactory()
const char *const ModuleTypeMap[]