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