Nektar++
OutputGmsh.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: OutputGmsh.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: Gmsh file format output.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
38 
39 #include "OutputGmsh.h"
40 #include "../InputModules/InputGmsh.h"
41 
42 using namespace std;
43 using namespace Nektar::NekMeshUtils;
44 
45 namespace Nektar
46 {
47 namespace Utilities
48 {
49 
50 ModuleKey OutputGmsh::className =
52  OutputGmsh::create,
53  "Writes Gmsh msh file.");
54 
55 OutputGmsh::OutputGmsh(MeshSharedPtr m) : OutputModule(m)
56 {
57  // Populate #InputGmsh::elmMap and use this to construct an
58  // inverse mapping from %ElmtConfig to Gmsh ID.
59  for (auto &it : InputGmsh::GenElmMap())
60  {
61  elmMap[it.second] = it.first;
62  }
63 
64  m_config["order"] = ConfigOption(false, "-1", "Enforce a polynomial order");
65 }
66 
68 {
69 }
70 
71 /**
72  * @brief Process a mesh to output to Gmsh MSH format.
73  *
74  * Gmsh output is fairly straightforward. The file first contains a
75  * list of nodes, followed by a list of elements. Since
76  * Mesh::vertexSet only contains vertices of the linear elements, we
77  * first loop over the elements so that any high-order vertices can be
78  * enumerated and then added to the node list. We then print out the
79  * list of nodes and finally print the element list.
80  */
82 {
83  if (m_mesh->m_verbose)
84  {
85  cout << "OutputGmsh: Writing file..." << endl;
86  }
87 
88  std::unordered_map<int, vector<int> > orderingMap;
89 
90  // Open the file stream.
91  OpenStream();
92 
93  // Write MSH header
94  m_mshFile << "$MeshFormat" << endl
95  << "2.2 0 8" << endl
96  << "$EndMeshFormat" << endl;
97 
98  int id = m_mesh->m_vertexSet.size();
99  vector<ElementSharedPtr> toComplete;
100 
101  int order = m_config["order"].as<int>();
102 
103  if (order != -1)
104  {
105  if (m_mesh->m_verbose)
106  {
107  cout << "Making mesh of order " << order << endl;
108  }
109  }
110  else
111  {
112  // Do first pass over elements of expansion dimension to determine
113  // which elements need completion.
114  for (int i = 0; i < m_mesh->m_element[m_mesh->m_expDim].size(); ++i)
115  {
116  ElementSharedPtr e = m_mesh->m_element[m_mesh->m_expDim][i];
117  if (e->GetMaxOrder() > order)
118  {
119  order = e->GetMaxOrder();
120  }
121  }
122  }
123 
124  // Convert this mesh into a high-order mesh of uniform order.
125  if (m_mesh->m_verbose)
126  {
127  cout << "Mesh order of " << order << " detected" << endl;
128  }
129 
130  m_mesh->MakeOrder(order, LibUtilities::ePolyEvenlySpaced);
131 
132  // Add edge- and face-interior nodes to vertex set.
133  for (auto &eIt : m_mesh->m_edgeSet)
134  {
135  m_mesh->m_vertexSet.insert(eIt->m_edgeNodes.begin(),
136  eIt->m_edgeNodes.end());
137  }
138 
139  for (auto &fIt : m_mesh->m_faceSet)
140  {
141  m_mesh->m_vertexSet.insert(fIt->m_faceNodes.begin(),
142  fIt->m_faceNodes.end());
143  }
144 
145  // Do second pass over elements for volume nodes.
146  for (int d = 1; d <= 3; ++d)
147  {
148  for (int i = 0; i < m_mesh->m_element[d].size(); ++i)
149  {
150  ElementSharedPtr e = m_mesh->m_element[d][i];
151  vector<NodeSharedPtr> volList = e->GetVolumeNodes();
152  m_mesh->m_vertexSet.insert(volList.begin(), volList.end());
153  }
154  }
155 
156  // Create ordered set of nodes - not required but looks nicer.
157  map<int, NodeSharedPtr> tmp;
158  for (const auto &it : m_mesh->m_vertexSet)
159  {
160  tmp[it->GetID() + 1] = it;
161  }
162 
163  // Write out nodes section.
164  m_mshFile << "$Nodes" << endl << m_mesh->m_vertexSet.size() << endl;
165 
166  for (auto &it : tmp)
167  {
168  m_mshFile << it.first << " " << scientific << setprecision(10)
169  << it.second->m_x << " " << it.second->m_y << " "
170  << it.second->m_z << endl;
171  }
172 
173  m_mshFile << "$EndNodes" << endl;
174 
175  // Write elements section. All other sections are not currently
176  // supported (physical names etc).
177  m_mshFile << "$Elements" << endl;
178  m_mshFile << m_mesh->GetNumEntities() << endl;
179 
180  id = 1;
181 
182  for (int d = 1; d <= 3; ++d)
183  {
184  for (int i = 0; i < m_mesh->m_element[d].size(); ++i, ++id)
185  {
186  ElementSharedPtr e = m_mesh->m_element[d][i];
187 
188  // First output element ID and type.
189  int elmtType = elmMap[e->GetConf()];
190  m_mshFile << id << " " << elmtType << " ";
191 
192  // Write out number of element tags and then the tags
193  // themselves.
194  vector<int> tags = e->GetTagList();
195 
196  if (tags.size() == 1)
197  {
198  tags.push_back(tags[0]);
199  tags.push_back(0);
200  }
201 
202  m_mshFile << tags.size() << " ";
203 
204  for (int j = 0; j < tags.size(); ++j)
205  {
206  m_mshFile << tags[j] << " ";
207  }
208 
209  // Finally write out node list. First write vertices, then
210  // internal edge nodes, then face nodes.
211  vector<NodeSharedPtr> nodeList = e->GetVertexList();
212  vector<EdgeSharedPtr> edgeList = e->GetEdgeList();
213  vector<FaceSharedPtr> faceList = e->GetFaceList();
214  vector<NodeSharedPtr> volList = e->GetVolumeNodes();
215 
216  tags.clear();
217 
218  for (int j = 0; j < nodeList.size(); ++j)
219  {
220  tags.push_back(nodeList[j]->m_id);
221  }
222 
223  // Process edge-interior points
224  for (int j = 0; j < edgeList.size(); ++j)
225  {
226  nodeList = edgeList[j]->m_edgeNodes;
227 
228  if (e->GetEdgeOrient(j, edgeList[j]) == StdRegions::eForwards)
229  {
230  for (int k = 0; k < nodeList.size(); ++k)
231  {
232  tags.push_back(nodeList[k]->m_id);
233  }
234  }
235  else
236  {
237  for (int k = nodeList.size() - 1; k >= 0; --k)
238  {
239  tags.push_back(nodeList[k]->m_id);
240  }
241  }
242  }
243 
244  // Process face-interior points
245  for (int j = 0; j < faceList.size(); ++j)
246  {
247  nodeList = faceList[j]->m_faceNodes;
248  int nFaceVerts = faceList[j]->m_vertexList.size();
249  vector<int> faceIds(nFaceVerts), volFaceIds(nFaceVerts);
250 
251  for (int k = 0; k < nFaceVerts; ++k)
252  {
253  faceIds [k] = faceList[j]->m_vertexList[k]->m_id;
254  volFaceIds[k] =
255  e->GetVertexList()[e->GetFaceVertex(j, k)]->m_id;
256  }
257 
258  if (nFaceVerts == 3)
259  {
260  HOTriangle<NodeSharedPtr> hoTri(faceIds, nodeList);
261  hoTri.Align(volFaceIds);
262  for (int k = 0; k < hoTri.surfVerts.size(); ++k)
263  {
264  tags.push_back(hoTri.surfVerts[k]->m_id);
265  }
266  }
267  else
268  {
269  HOQuadrilateral<NodeSharedPtr> hoQuad(faceIds, nodeList);
270  hoQuad.Align(volFaceIds);
271 
272  for (int k = 0; k < hoQuad.surfVerts.size(); ++k)
273  {
274  tags.push_back(hoQuad.surfVerts[k]->m_id);
275  }
276  }
277  }
278 
279  // Process volume nodes
280  for (int j = 0; j < volList.size(); ++j)
281  {
282  tags.push_back(volList[j]->m_id);
283  }
284 
285  // Construct inverse of input reordering. First try to find it in
286  // our cache.
287  auto oIt = orderingMap.find(elmtType);
288 
289  // If it's not created, then create it.
290  if (oIt == orderingMap.end())
291  {
292  vector<int> reordering = InputGmsh::CreateReordering(elmtType);
293  vector<int> inv(tags.size());
294 
295  ASSERTL1(tags.size() == reordering.size(),
296  "Reordering map size not equal to element tags 1.");
297 
298  for (int j = 0; j < tags.size(); ++j)
299  {
300  inv[reordering[j]] = j;
301  }
302 
303  oIt = orderingMap.insert(make_pair(elmtType, inv)).first;
304  }
305 
306  ASSERTL1(tags.size() == oIt->second.size(),
307  "Reordering map size not equal to element tags 2.");
308 
309  // Finally write element nodes.
310  for (int j = 0; j < tags.size(); ++j)
311  {
312  m_mshFile << tags[oIt->second[j]] + 1 << " ";
313  }
314 
315  m_mshFile << endl;
316  }
317  }
318  m_mshFile << "$EndElements" << endl;
319 }
320 }
321 }
io::filtering_ostream m_mshFile
Output stream.
void Align(std::vector< int > vertId)
Align this surface to a given vertex ID.
Definition: HOAlignment.h:134
NEKMESHUTILS_EXPORT void OpenStream()
Open a file for output.
std::vector< T > surfVerts
The quadrilateral surface vertices – templated so that this can either be nodes or IDs...
Definition: HOAlignment.h:224
Abstract base class for output modules.
STL namespace.
std::vector< T > surfVerts
The triangle surface vertices – templated so that this can either be nodes or IDs.
Definition: HOAlignment.h:64
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
1D Evenly-spaced points using Lagrange polynomial
Definition: PointsType.h:64
std::pair< ModuleType, std::string > ModuleKey
std::unordered_map< NekMeshUtils::ElmtConfig, unsigned int, ElmtConfigHash > elmMap
Definition: OutputGmsh.h:82
static std::vector< int > CreateReordering(unsigned int InputGmshEntity)
Create a reordering map for a given element.
Definition: InputGmsh.cpp:1218
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
Represents a command-line configuration option.
std::map< std::string, ConfigOption > m_config
List of configuration values.
void Align(std::vector< int > vertId)
Align this surface to a given vertex ID.
Definition: HOAlignment.h:270
A lightweight struct for dealing with high-order triangle alignment.
Definition: HOAlignment.h:49
A lightweight struct for dealing with high-order quadrilateral alignment.
Definition: HOAlignment.h:208
virtual void Process()
Write mesh to output file.
Definition: OutputGmsh.cpp:81
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199
std::pair< ModuleType, std::string > ModuleKey
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
static std::map< unsigned int, NekMeshUtils::ElmtConfig > GenElmMap()
Definition: InputGmsh.cpp:1890
ModuleFactory & GetModuleFactory()