KASKADE 7 development version
ansysmeshreader.hh
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the library KASKADE 7 */
4/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
5/* */
6/* Copyright (C) 2012-2015 Zuse Institute Berlin */
7/* */
8/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
9/* see $KASKADE/academic.txt */
10/* */
11/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
12
13#ifndef ANSYS_MESH_READER_HH
14#define ANSYS_MESH_READER_HH
15
16#include <algorithm>
17#include <cstdlib>
18#include <cmath>
19#include <fstream>
20#include <iostream>
21#include <iterator>
22#include <memory>
23#include <string>
24#include <utility>
25#include <vector>
26#include <limits>
27
28#include <boost/lexical_cast.hpp>
29
30#include <dune/common/fvector.hh>
31#include "dune/grid/config.h"
32
33
34#if HAVE_UG
35#include <dune/grid/uggrid/uggridfactory.hh>
36#endif
37
38#if HAVE_ALBERTA
39#include <dune/grid/albertagrid/gridfactory.hh>
40#endif
41
42#if ENABLE_ALUGRID
43#include <dune/grid/alugrid/3d/alu3dgridfactory.hh>
44#endif
45
46#include "fem/lagrangespace.hh"
47#include "io/ioTools.hh"
48// #include "io/vtk.hh"
50#include "utilities/power.hh"
51
52namespace Kaskade
53{
59 {
60 public:
66 explicit AnsysMeshReader(double scale_=1.0, int verbose_=0) : scale(scale_), verbose(verbose_)
67 {}
68
74 template <class Grid, class Scalar>
75 std::unique_ptr<Grid> readGrid(std::string const& fileName, int initialGridSize = 1000)
76 {
77 constexpr int dim = Grid::dimension;
78 std::ifstream file(fileName);
79 currentLine = 0;
80
81 if(!(bool)file) throw IOException(std::string("Could not read file ") + fileName, __FILE__, __LINE__);
82 else if(verbose>=1) std::cout << "Reading " << fileName << std::endl;
83
84 BoundingBox<Scalar,dim> boundingBox;
85 std::vector<Dune::FieldVector<Scalar,dim> > vertices;
86 std::vector<std::vector<unsigned int> > cubes;
87 std::vector<std::pair<unsigned int,unsigned int> > offsets(1,std::make_pair(0,0));
88
89 auto NOT_FOUND = std::string::npos;
90 std::string buffer;
91
92 // First line should contain "*HEADING". Check if this is the case.
93 getline(file,buffer);
94 if(buffer.find("*HEADING") == NOT_FOUND)
95 throw IOException(std::string("Error reading file ") + fileName + "at line " + std::to_string(currentLine),__FILE__,__LINE__);
96 getline(file,buffer);
97 short elementSetId = 0;
98
99 while(file.good())
100 {
101
102 if(buffer.empty())
103 {
104 getline(file,buffer);
105 continue;
106 }
107
108 if(verbose >= 1) std::cout << buffer << std::endl;
109 if(buffer[0] != '*') throw IOException(std::string("Expected comment at line " + std::to_string(currentLine) + "."),__FILE__,__LINE__);
110 if(buffer.find("**") != NOT_FOUND)
111 {
112 if(buffer.find("Materialdaten") != NOT_FOUND) break;
113 if(verbose >= 1) std::cout << "End of section. Starting new one." << std::endl;
114 getline(file,buffer);
115 continue;
116 }
117
118 // read vertices
119 if(buffer.find("*NODE") != NOT_FOUND)
120 {
121 if(verbose >= 1) std::cout << "Reading vertices...";
122 readVertices<double>(file, buffer, vertices, offsets);
123 if(verbose >= 1) std::cout << "done: " << vertices.size() << " entries.\n" << std::endl;
124 continue;
125 }
126
127 // read elements
128 if(buffer.find("*ELEMENT") != NOT_FOUND)
129 {
130 if(buffer.find("TYPE=C3D8") != NOT_FOUND) // hexahedral element section found
131 {
132 std::string::size_type pos = buffer.find("ELSET=");
133 if(pos == NOT_FOUND) throw IOException(std::string("Could not determine element set."),__FILE__,__LINE__);
134
135
136 if (verbose >= 1) std::cout << "Reading elements..." << std::flush;
137 readElements(file, buffer, cubes, offsets);
138 if (verbose >= 1) std::cout << "done: " << cubes.size() << " entries.\n" << std::endl;
139 continue;
140 }
141
142 if(buffer.find("TYPE=C3D4") != NOT_FOUND) // tetrahedral element section found
143 {
144 std::string::size_type pos = buffer.find("ELSET=");
145 if(pos == NOT_FOUND) throw IOException(std::string("Could not determine element set."),__FILE__,__LINE__);
146
147 if (verbose >= 1) std::cout << "Reading tetrahedra..." << std::flush;
148 readTetrahedra(file, buffer, cubes, offsets, elementSetId++);
149 if (verbose >= 1) std::cout << "done: " << cubes.size() << " entries.\n" << std::endl;
150 continue;
151 }
152
153 throw IOException(std::string("For Ansys meshes currently only supported for cubic and tetrahedral geometries."),__FILE__,__LINE__);
154 }
155 }
156
157 // create factory
158 Dune::GridFactory<Grid> factory = IOTools::FactoryGenerator<Grid>::createFactory(initialGridSize);
159 /****************************************/
160 if (verbose >= 1) std::cout << "inserting vertices...";
161 for(auto const& vertex : vertices) factory.insertVertex(vertex);
162 if (verbose >= 1) std::cout << "done." << std::endl;
163
164 /****************************************/
165 if (verbose >= 1) std::cout << "inserting elements...";
166
167 for (auto const& vertexIds: cubes) {
168 // include each vertex into the bounding box
169 if (verbose >= 2)
170 for (auto vertexId: vertexIds)
171 boundingBox.update(vertices[vertexId]);
172
173 // create the cell. TODO: is this restricted to simplicial cells? what about hexahedral ones?
174 factory.insertElement(Dune::GeometryType(Dune::GeometryType::simplex,dim),vertexIds);
175 }
176 if (verbose >= 1) std::cout << "done." << std::endl;
177
178 if (verbose >= 2) boundingBox.print();
179
180 if (verbose >= 1) std::cout << "grid creation finished\n\n";
181
182 return std::unique_ptr<Grid>(factory.createGrid());
183 }
184
185
189 template <class FSElement>
190 void readElementSetIds(FSElement& element) const
191 {
192 assert(element.coefficients().N() == elementSetIds.size());
193 for(size_t i=0; i<elementSetIds.size(); ++i)
194 element.coefficients()[i][0] = static_cast<typename FSElement::Scalar>(elementSetIds[i]);
195 }
196
197
198 private:
199 template <class Scalar, int dim>
200 struct BoundingBox
201 {
202 BoundingBox() : max(-1.0*std::numeric_limits<Scalar>::max()), min(std::numeric_limits<Scalar>::max())
203 {}
204
205 explicit BoundingBox(Dune::FieldVector<Scalar,dim> const& v) : max(v), min(v)
206 {}
207
208 void update(Dune::FieldVector<Scalar,dim> const& v)
209 {
210// if(v[1] > 0) return; // ???
211 for(int i=0; i<dim; ++i)
212 {
213 min[i] = std::min(min[i],v[i]);
214 max[i] = std::max(max[i],v[i]);
215 }
216 }
217
218 bool isInside(Dune::FieldVector<Scalar,dim> const& v) const
219 {
220 for(int i=0; i<dim; ++i)
221 if ((min[i] > v[i]) || (max[i] < v[i])) // outside
222 return false;
223 return true;
224 }
225
226 void print() const
227 {
228 std::cout << "Bounding Box" << std::endl;
229 for(int i=0; i<dim; ++i) std::cout << i << ": [" << min[i] << ", " << max[i] << "]" << std::endl;
230 std::cout << std::endl;
231 }
232
234 };
235
236 static const char delimiter = ',';
237
239
244 void sortElements(std::vector<std::vector<unsigned int> >& elements) const;
245
247
252 void adjustElement(std::vector<unsigned int>& element, std::vector<std::pair<unsigned int,unsigned int> > const& offsets);
253
254 inline void removeLeadingWhiteSpaces(std::string& buffer)
255 {
256 buffer.erase(0,buffer.find_first_not_of(' '));
257 }
258
259 template <class Type>
260 inline Type readEntry(std::ifstream& file, std::string& buffer)
261 {
262 getline(file,buffer,delimiter);
263 removeLeadingWhiteSpaces(buffer);
264 return boost::lexical_cast<Type>(buffer);
265 }
266
267 template <class Scalar, int dim>
268 void readVertices(std::ifstream& file, std::string& buffer, std::vector<Dune::FieldVector<Scalar,dim> >& vertices,
269 std::vector<std::pair<unsigned int,unsigned int> >& offsets)
270 {
272
273 unsigned int currentIndex = 1, givenIndex;
274 char tmp;
275
276 getline(file,buffer,delimiter);
277 removeLeadingWhiteSpaces(buffer);
278
279 while(file.good())
280 {
281 givenIndex = boost::lexical_cast<unsigned int>(buffer);
282
283 // throw if no ordering exists in file
284 if(currentIndex+offsets.back().second > givenIndex)
285 {
286 std::cerr << vertices.size() << ", " << currentIndex << ", " << offsets.back().second << ", " << givenIndex << std::endl;
287 throw IOException(std::string("currentIndex > givenIndex in line ") + std::to_string(currentLine),__FILE__,__LINE__);
288 }
289 // store offsets
290 if(currentIndex + offsets.back().second < givenIndex)
291 offsets.push_back(std::make_pair(givenIndex-1, givenIndex - currentIndex));
292 ++currentIndex;
293
294 // read data
295 vertex[0] = readEntry<Scalar>(file,buffer);
296 vertex[1] = readEntry<Scalar>(file,buffer);
297 file >> vertex[2];
298
299 // scale the position as requested
300 vertex *= scale;
301
302 vertices.push_back(vertex);
303
304 getline(file,buffer);
305 file >> tmp;
306 file.unget();
307 if(tmp=='*')
308 {
309 getline(file,buffer);
310 return;
311 }
312 getline(file,buffer,delimiter);
313 removeLeadingWhiteSpaces(buffer);
314 }
315 }
316
317 void readElements(std::ifstream& file, std::string& buffer, std::vector<std::vector<unsigned int> >& elements,
318 std::vector<std::pair<unsigned int,unsigned int> > const& offsets);
319
320
321 void readTetrahedra(std::ifstream& file, std::string& buffer, std::vector<std::vector<unsigned int> >& elements,
322 const std::vector<std::pair<unsigned int,unsigned int> >& offsets, short elementSetId);
323
324 template <class Scalar, int dim>
325 inline bool equal(Dune::FieldVector<Scalar,dim> const& v0, Dune::FieldVector<Scalar,dim> const& v1)
326 {
327 return (v0-v1).two_norm2() <= power<2>(100*std::numeric_limits<Scalar>::epsilon()) * (v0.two_norm2() + v1.two_norm2());
328 }
329
330 template <class Scalar, int dim>
331 inline unsigned int getIndex(Dune::FieldVector<Scalar,dim> const& vertex, std::vector<Dune::FieldVector<Scalar,dim> > const& vertices)
332 {
333 for(size_t i=0; i<vertices.size(); ++i)
334 if(equal(vertex,vertices[i]))
335 return i;
336 return vertices.size();
337 }
338
339
340 template <class Scalar, int dim>
341 void getElementsVertices(std::vector<Dune::FieldVector<Scalar,dim> > const& vertices, std::vector<Dune::FieldVector<Scalar,dim> >& elementVertices,
342 std::vector<unsigned int> const& element, std::vector<unsigned int>& newElement, unsigned int index)
343 {
344 for(size_t i=0; i<element.size(); ++i)
345 {
346 unsigned int index = getIndex(vertices[element[i]], elementVertices);
347 if(index==elementVertices.size())
348 {
349 newElement[i] = elementVertices.size();
350 elementVertices.push_back(vertices[element[i]]);
351 }
352 else
353 newElement[i] = index;
354 }
355 }
356
357 // Read a line from the file, advancing the currentLine counter appropriately.
358 void getline(std::ifstream& file, std::string& line, char const delim='\n');
359
360 std::vector<short> elementSetIds;
361 double scale;
362 int verbose;
363 size_t currentLine; // storing the line number on reading
364 };
365} // namespace Kaskade
366#endif
Reader for Ansys *.inp grid files.
void readElementSetIds(FSElement &element) const
Extracts the element set id of each cell and stores it in the coefficient of a discontinuous P0 FE fu...
std::unique_ptr< Grid > readGrid(std::string const &fileName, int initialGridSize=1000)
Reads an Ansys file and creates a corresponding grid.
AnsysMeshReader(double scale_=1.0, int verbose_=0)
Constructor.
An exception class for IO errors.
std::pair< Dune::FieldVector< typename GridView::ctype, GridView::dimensionworld >, Dune::FieldVector< typename GridView::ctype, GridView::dimensionworld > > boundingBox(GridView const &gv)
Computes a the bounding box of the given grid view.
Definition: gridCover.hh:35
Dune::FieldVector< T, n > max(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise maximum.
Definition: fixdune.hh:110
Dune::FieldVector< T, n > min(Dune::FieldVector< T, n > x, Dune::FieldVector< T, n > const &y)
Componentwise minimum.
Definition: fixdune.hh:122
Lagrange Finite Elements.