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  pair<ElementSharedPtr, int> eMap = (*it)->m_elLink.at(0);
220  eMap.first->SetBoundaryLink(eMap.second, i);
221 
222  // Copy curvature to edge.
223  if ((*it)->m_edgeNodes.size() > 0)
224  {
225  ElementSharedPtr edge = m_mesh->m_element[1][i];
226  if (edge->GetVertex(0) == (*it)->m_n1)
227  {
228  edge->SetVolumeNodes((*it)->m_edgeNodes);
229  }
230  }
231  }
232  }
233 
234 
235  /**
236  * @brief Create a unique set of mesh faces from elements stored in
237  * Mesh::element.
238  *
239  * All elements are scanned and a unique list of enumerated faces is
240  * produced in #m_faceSet. Since elements created their own faces
241  * independently, we examine each element only uses face objects from
242  * #m_faceSet. Duplicate faces of those in #m_face are replaced with
243  * the corresponding entry in #m_faceSet. Finally, we scan the list of
244  * elements for 2-D boundary faces which correspond to faces in
245  * #m_faceSet. For such elements, we set its faceLink to reference the
246  * corresponding face in #m_faceSet.
247  *
248  * This routine only proceeds if the expansion dimension is 3.
249  */
250  void Module::ProcessFaces(bool ReprocessFaces)
251  {
252  if (m_mesh->m_expDim < 3) return;
253 
254  if(ReprocessFaces)
255  {
256  vector<ElementSharedPtr> &elmt = m_mesh->m_element[m_mesh->m_expDim];
257 
258  m_mesh->m_faceSet.clear();
259 
260  // Scan all elements and generate list of unique faces
261  for (int i = 0, fid = 0; i < elmt.size(); ++i)
262  {
263  for (int j = 0; j < elmt[i]->GetFaceCount(); ++j)
264  {
265  pair<FaceSet::iterator,bool> testIns;
266  testIns = m_mesh->m_faceSet.insert(elmt[i]->GetFace(j));
267 
268  if (testIns.second)
269  {
270  (*(testIns.first))->m_id = fid++;
271  }
272  else
273  {
274  elmt[i]->SetFace(j,*testIns.first);
275  // Update face to element map.
276  (*(testIns.first))->m_elLink.push_back(
277  pair<ElementSharedPtr,int>(elmt[i],j));
278  }
279  }
280  }
281  }
282 
283  // Create links for 2D elements
284  for (int i = 0; i < m_mesh->m_element[2].size(); ++i)
285  {
286  vector<NodeSharedPtr> vertices = m_mesh->m_element[2][i]->GetVertexList();
287  vector<NodeSharedPtr> faceNodes;
288  vector<EdgeSharedPtr> edgeList = m_mesh->m_element[2][i]->GetEdgeList();
289  FaceSharedPtr F = boost::shared_ptr<Face>(
290  new Face(vertices, faceNodes, edgeList,
291  m_mesh->m_element[2][i]->GetConf().m_faceCurveType));
292  FaceSet::iterator it = m_mesh->m_faceSet.find(F);
293  if (it == m_mesh->m_faceSet.end())
294  {
295  cout << "Cannot find corresponding element face for 2D "
296  << "element " << i << endl;
297  abort();
298  }
299  m_mesh->m_element[2][i]->SetFaceLink(*it);
300 
301  // Update 3D element boundary map.
302  pair<ElementSharedPtr, int> eMap = (*it)->m_elLink.at(0);
303  eMap.first->SetBoundaryLink(eMap.second, i);
304  }
305  }
306 
307  /**
308  * @brief Enumerate elements stored in Mesh::element.
309  *
310  * For all elements of equal dimension to the mesh dimension, we
311  * enumerate sequentially. All other elements in the list should be of
312  * lower dimension and have ID set by a corresponding edgeLink or
313  * faceLink (as set in #ProcessEdges or #ProcessFaces).
314  */
316  {
317  int cnt = 0;
318  for (int i = 0; i < m_mesh->m_element[m_mesh->m_expDim].size(); ++i)
319  {
320  m_mesh->m_element[m_mesh->m_expDim][i]->SetId(cnt++);
321  }
322  }
323 
324  /**
325  * @brief Generate a list of composites (groups of elements) from tag
326  * IDs stored in mesh vertices/edges/faces/elements.
327  *
328  * Each element is assigned to a composite ID by an input module. First
329  * we scan the element list and generate a list of composite IDs. We
330  * then generate the composite objects and populate them with a second
331  * scan through the element list.
332  */
334  {
335  m_mesh->m_composite.clear();
336 
337  // For each element, check to see if a composite has been
338  // created. If not, create a new composite. Otherwise, add the
339  // element to the composite.
340  for (int d = 0; d <= m_mesh->m_expDim; ++d)
341  {
342  vector<ElementSharedPtr> &elmt = m_mesh->m_element[d];
343 
344  for (int i = 0; i < elmt.size(); ++i)
345  {
347  unsigned int tagid = elmt[i]->GetTagList()[0];
348 
349  it = m_mesh->m_composite.find(tagid);
350 
351  if (it == m_mesh->m_composite.end())
352  {
353  CompositeSharedPtr tmp = boost::shared_ptr<Composite>(
354  new Composite());
355  pair<CompositeMap::iterator, bool> testIns;
356  tmp->m_id = tagid;
357  tmp->m_tag = elmt[i]->GetTag();
358  if(m_mesh->m_faceLabels.count(tmp->m_id) != 0)
359  {
360  tmp->m_label = m_mesh->m_faceLabels[tmp->m_id];
361  }
362 
363  testIns = m_mesh->m_composite.insert(
364  pair<unsigned int, CompositeSharedPtr>(tagid,tmp));
365  it = testIns.first;
366  }
367 
368  if (elmt[i]->GetTag() != it->second->m_tag)
369  {
370  cout << "Different types of elements in same composite!" << endl;
371  cout << " -> Composite uses " << it->second->m_tag << endl;
372  cout << " -> Element uses " << elmt[i]->GetTag() << endl;
373  cout << "Have you specified physical volumes and surfaces?" << endl;
374  }
375  it->second->m_items.push_back(elmt[i]);
376  }
377  }
378  }
379 
380  /**
381  * @brief Reorder node IDs so that prisms and tetrahedra are aligned
382  * correctly.
383  *
384  * Orientation of prism lines (i.e. a large prism which has been split
385  * into subprisms) cannot be guaranteed when elements are created
386  * one-by-one, or when periodic boundary conditions are used. This
387  * routine uses the following strategy:
388  *
389  * - Destroy the existing node numbering.
390  * - Detect a line of prisms using the PrismLines routine.
391  * - For each line, renumber node IDs consistently so that highest ID
392  * per-element corresponds to the line of collapsed coordinate
393  * points.
394  * - Recreate each prism in the line using the new ordering, and apply
395  * the existing OrientPrism routine to orient nodes accordingly.
396  * - When all prism lines are processed, recreate all tetrahedra using
397  * the existing orientation code.
398  * - Finally renumber any other nodes (i.e. those belonging to
399  * hexahedra).
400  *
401  * The last step is to eliminate duplicate edges/faces and reenumerate.
402  *
403  * NOTE: This routine does not copy face-interior high-order information
404  * yet!
405  */
407  {
408  // Loop over elements and extract any that are prisms.
409  int i, j, k;
410 
411  if (m_mesh->m_expDim < 3)
412  {
413  return;
414  }
415 
416  map<int, int> lines;
417  set<int> prismsDone, tetsDone;
418  PerMap::iterator pIt;
419 
420  // Compile list of prisms and tets.
421  for (i = 0; i < m_mesh->m_element[3].size(); ++i)
422  {
423  ElementSharedPtr el = m_mesh->m_element[3][i];
424 
425  if (el->GetConf().m_e == LibUtilities::ePrism)
426  {
427  prismsDone.insert(i);
428  }
429  else if (el->GetConf().m_e == LibUtilities::eTetrahedron)
430  {
431  tetsDone.insert(i);
432  }
433  }
434 
435  // Destroy existing node numbering.
437  for (it = m_mesh->m_vertexSet.begin(); it != m_mesh->m_vertexSet.end(); ++it)
438  {
439  (*it)->m_id = -1;
440  }
441 
442  // Counter for new node IDs.
443  int nodeId = 0;
444  int prismTris[2][3] = {{0,1,4}, {3,2,5}};
445 
446  // Warning flag for high-order curvature information.
447  bool warnCurvature = false;
448 
449  // facesDone tracks face IDs inside prisms which have already been
450  // aligned.
451  boost::unordered_set<int> facesDone;
453 
454  // Loop over prisms until we've found all lines of prisms.
455  while (prismsDone.size() > 0)
456  {
457  vector<ElementSharedPtr> line;
458 
459  // Call PrismLines to identify all prisms connected to
460  // prismDone.begin() and place them in line[].
461  PrismLines(*prismsDone.begin(), perFaces, prismsDone, line);
462 
463  // Loop over each prism, figure out which line of vertices
464  // contains the vertex with highest ID.
465  for (i = 0; i < line.size(); ++i)
466  {
467  // Copy tags and nodes from existing element.
468  vector<int> tags = line[i]->GetTagList();
469  vector<NodeSharedPtr> nodes = line[i]->GetVertexList();
470 
471  // See if either face of this prism has been renumbered
472  // already.
473  FaceSharedPtr f[2] = {
474  line[i]->GetFace(1), line[i]->GetFace(3)
475  };
476 
477  fIt[0] = facesDone.find(f[0]->m_id);
478  fIt[1] = facesDone.find(f[1]->m_id);
479 
480  // See if either of these faces is periodic. If it is, then
481  // assign ids accordingly.
482  for (j = 0; j < 2; ++j)
483  {
484  pIt = perFaces.find(f[j]->m_id);
485 
486  if (pIt == perFaces.end())
487  {
488  continue;
489  }
490 
491  fIt2 = facesDone.find(pIt->second.first->m_id);
492 
493  if (fIt[j] == facesDone.end() &&
494  fIt2 != facesDone.end())
495  {
496  fIt[j] = fIt2;
497  }
498  }
499 
500  if (fIt[0] != facesDone.end() &&
501  fIt[1] != facesDone.end())
502  {
503  // Should not be the case that both faces have already
504  // been renumbered.
505  ASSERTL0(false, "Renumbering error!");
506  }
507  else if (fIt[0] == facesDone.end() &&
508  fIt[1] == facesDone.end())
509  {
510  // Renumber both faces.
511  for (j = 0; j < 2; ++j)
512  {
513  for (k = 0; k < 3; ++k)
514  {
515  NodeSharedPtr n = nodes[prismTris[j][k]];
516  if (n->m_id == -1)
517  {
518  n->m_id = nodeId++;
519  }
520  }
521  }
522 
523  facesDone.insert(f[0]->m_id);
524  facesDone.insert(f[1]->m_id);
525  }
526  else
527  {
528  // Renumber face. t identifies the face not yet
529  // numbered, o identifies the other face.
530  int t = fIt[0] == facesDone.end() ? 0 : 1;
531  int o = (t+1) % 2;
532  ASSERTL1(fIt[o] != facesDone.end(),"Renumbering error");
533 
534  // Determine which of the three vertices on the 'other'
535  // face corresponds to the highest ID - this signifies
536  // the singular point of the line of prisms.
537  int tmp1[3] = {
538  nodes[prismTris[o][0]]->m_id,
539  nodes[prismTris[o][1]]->m_id,
540  nodes[prismTris[o][2]]->m_id
541  };
542  int tmp2[3] = {0,1,2};
543 
544  if (tmp1[0] > tmp1[1])
545  {
546  swap(tmp1[0], tmp1[1]);
547  swap(tmp2[0], tmp2[1]);
548  }
549 
550  if (tmp1[1] > tmp1[2])
551  {
552  swap(tmp1[1], tmp1[2]);
553  swap(tmp2[1], tmp2[2]);
554  }
555 
556  if (tmp1[0] > tmp1[2])
557  {
558  swap(tmp1[0], tmp1[2]);
559  swap(tmp2[0], tmp2[2]);
560  }
561 
562  // Renumber this face so that highest ID matches.
563  for (j = 0; j < 3; ++j)
564  {
565  NodeSharedPtr n = nodes[prismTris[t][tmp2[j]]];
566  if (n->m_id == -1)
567  {
568  n->m_id = nodeId++;
569  }
570  }
571 
572  facesDone.insert(f[t]->m_id);
573  }
574 
575  for (j = 0; j < 6; ++j)
576  {
577  ASSERTL1(nodes[j]->m_id != -1, "Renumbering error");
578  }
579 
580  // Recreate prism with the new ordering.
581  ElmtConfig conf(LibUtilities::ePrism, 1, false, false, true);
583  LibUtilities::ePrism, conf, nodes, tags);
584 
585  // Now transfer high-order information back into
586  // place. TODO: Face curvature.
587  for (j = 0; j < 9; ++j)
588  {
589  EdgeSharedPtr e1 = line[i]->GetEdge(j);
590  for (k = 0; k < 9; ++k)
591  {
592  EdgeSharedPtr e2 = el->GetEdge(k);
593  if (e1->m_n1 == e2->m_n1 && e1->m_n2 == e2->m_n2)
594  {
595  e2->m_edgeNodes = e1->m_edgeNodes;
596  }
597  else if (e1->m_n1 == e2->m_n1 && e1->m_n2 == e2->m_n2)
598  {
599  e2->m_edgeNodes = e1->m_edgeNodes;
600  std::reverse(e2->m_edgeNodes.begin(),
601  e2->m_edgeNodes.end());
602  }
603  }
604  }
605 
606  // Warn users that we're throwing away face curvature
607  if (!warnCurvature)
608  {
609  for (j = 0; j < 5; ++j)
610  {
611  if (line[i]->GetFace(j)->m_faceNodes.size() > 0)
612  {
613  warnCurvature = true;
614  break;
615  }
616  }
617  }
618 
619  // Replace old prism.
620  m_mesh->m_element[3][line[i]->GetId()] = el;
621  }
622  }
623 
624  if (warnCurvature)
625  {
626  cerr << "[ReorderPrisms] WARNING: Face curvature detected in "
627  << "some prisms; this will be ignored in further module "
628  << "evaluations."
629  << endl;
630  }
631 
632  // Loop over periodic faces, enumerate vertices.
633  for (pIt = perFaces.begin(); pIt != perFaces.end(); ++pIt)
634  {
635  FaceSharedPtr f2 = pIt->second.first;
636  FaceSharedPtr f1 = perFaces[f2->m_id].first;
637  vector<int> perVerts = pIt->second.second;
638  int nVerts = perVerts.size();
639 
640  // Number periodic vertices first.
641  for (j = 0; j < nVerts; ++j)
642  {
643  NodeSharedPtr n1 = f1->m_vertexList[j];
644  NodeSharedPtr n2 = f2->m_vertexList[perVerts[j]];
645 
646  if (n1->m_id == -1 && n2->m_id == -1)
647  {
648  n1->m_id = nodeId++;
649  n2->m_id = nodeId++;
650  }
651  else if (n1->m_id != -1 && n2->m_id != -1)
652  {
653  continue;
654  }
655  else
656  {
657  ASSERTL0(false, "Periodic face renumbering error");
658  }
659  }
660  }
661 
662  // Recreate tets.
663  set<int>::iterator it2;
664  for (it2 = tetsDone.begin(); it2 != tetsDone.end(); ++it2)
665  {
666  ElementSharedPtr el = m_mesh->m_element[3][*it2];
667  vector<NodeSharedPtr> nodes = el->GetVertexList();
668  vector<int> tags = el->GetTagList();
669 
670  for (i = 0; i < 4; ++i)
671  {
672  if (nodes[i]->m_id == -1)
673  {
674  nodes[i]->m_id = nodeId++;
675  }
676  }
677 
678  // Recreate tet.
679  ElmtConfig conf(LibUtilities::eTetrahedron, 1, false, false, true);
680  m_mesh->m_element[3][*it2] = GetElementFactory().CreateInstance(
681  LibUtilities::eTetrahedron, conf, nodes, tags);
682  }
683 
684  // Enumerate rest of vertices.
685  for (it = m_mesh->m_vertexSet.begin(); it != m_mesh->m_vertexSet.end(); ++it)
686  {
687  if ((*it)->m_id == -1)
688  {
689  (*it)->m_id = nodeId++;
690  }
691  }
692 
693  ProcessEdges ();
694  ProcessFaces ();
695  ProcessElements();
696  }
697 
698  void Module::PrismLines(int prism,
699  PerMap &perFaces,
700  set<int> &prismsDone,
701  vector<ElementSharedPtr> &line)
702  {
703  int i;
704  set<int>::iterator it = prismsDone.find(prism);
705  PerMap::iterator it2;
706 
707  if (it == prismsDone.end())
708  {
709  return;
710  }
711 
712  // Remove this prism from the list.
713  prismsDone.erase(it);
714  line.push_back(m_mesh->m_element[3][prism]);
715 
716  // Now find prisms connected to this one through a triangular face.
717  for (i = 1; i <= 3; i += 2)
718  {
719  FaceSharedPtr f = m_mesh->m_element[3][prism]->GetFace(i);
720  int nextId;
721 
722  // See if this face is periodic.
723  it2 = perFaces.find(f->m_id);
724 
725  if (it2 != perFaces.end())
726  {
727  int id2 = it2->second.first->m_id;
728  nextId = it2->second.first->m_elLink[0].first->GetId();
729  perFaces.erase(it2);
730  perFaces.erase(id2);
731  PrismLines(nextId, perFaces, prismsDone, line);
732  }
733 
734  // Nothing else connected to this face.
735  if (f->m_elLink.size() == 1)
736  {
737  continue;
738  }
739 
740  nextId = f->m_elLink[0].first->GetId();
741  if (nextId == m_mesh->m_element[3][prism]->GetId())
742  {
743  nextId = f->m_elLink[1].first->GetId();
744  }
745 
746  PrismLines(nextId, perFaces, prismsDone, line);
747  }
748  }
749 
750  /**
751  * @brief Register a configuration option with a module.
752  */
753  void Module::RegisterConfig(string key, string val)
754  {
756  if (it == m_config.end())
757  {
758  cerr << "WARNING: Unrecognised config option " << key
759  << ", proceeding anyway." << endl;
760  }
761 
762  it->second.beenSet = true;
763 
764  if (it->second.isBool)
765  {
766  it->second.value = "1";
767  }
768  else
769  {
770  it->second.value = val;
771  }
772  }
773 
774  /**
775  * @brief Print out all configuration options for a module.
776  */
777  void Module::PrintConfig()
778  {
780 
781  if (m_config.size() == 0)
782  {
783  cerr << "No configuration options for this module." << endl;
784  return;
785  }
786 
787  for (it = m_config.begin(); it != m_config.end(); ++it)
788  {
789  cerr << setw(10) << it->first << ": " << it->second.desc
790  << endl;
791  }
792  }
793 
794  /**
795  * @brief Sets default configuration options for those which have not
796  * been set.
797  */
798  void Module::SetDefaults()
799  {
801 
802  for (it = m_config.begin(); it != m_config.end(); ++it)
803  {
804  if (!it->second.beenSet)
805  {
806  it->second.value = it->second.defValue;
807  }
808  }
809  }
810 
811  /**
812  * @brief Print a brief summary of information.
813  */
815  {
816  // Compute the number of full-dimensional elements and boundary
817  // elements.
818  cerr << "Expansion dimension is " << m_mesh->m_expDim << endl;
819  cerr << "Space dimension is " << m_mesh->m_spaceDim << endl;
820  cerr << "Read " << m_mesh->m_node.size() << " nodes" << endl;
821  cerr << "Read " << m_mesh->GetNumElements() << " "
822  << m_mesh->m_expDim << "-D elements" << endl;
823  cerr << "Read " << m_mesh->GetNumBndryElements()
824  << " boundary elements" << endl;
825  }
826  }
827 }
LibUtilities::NekFactory< ModuleKey, Module, FieldSharedPtr > ModuleFactory
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:161
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:191
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[]