6#ifndef DUNE_GRID_IO_FILE_GMSH_GMSH2PARSER_HH
7#define DUNE_GRID_IO_FILE_GMSH_GMSH2PARSER_HH
18#include <dune/common/exceptions.hh>
19#include <dune/common/fvector.hh>
21#include <dune/geometry/type.hh>
26namespace Dune::Impl::Gmsh
29 template<
int dimension,
int dimWorld = dimension >
30 class GmshReaderQuadraticBoundarySegment
34 static void registerFactory() {}
49 template<
int dimWorld >
50 struct GmshReaderQuadraticBoundarySegment< 2, dimWorld >
51 :
public Dune::BoundarySegment< 2, dimWorld >
53 typedef GmshReaderQuadraticBoundarySegment< 2, dimWorld > ThisType;
54 typedef typename Dune::BoundarySegment< 2, dimWorld > :: ObjectStreamType ObjectStreamType;
55 typedef Dune::FieldVector< double, dimWorld >
GlobalVector;
57 GmshReaderQuadraticBoundarySegment (
const GlobalVector &p0_,
const GlobalVector &p1_,
const GlobalVector &p2_)
58 : p0(p0_), p1(p1_), p2(p2_)
63 GmshReaderQuadraticBoundarySegment( ObjectStreamType& in )
66 const int bytes =
sizeof(double)*dimWorld;
67 in.read( (
char *) &p0[ 0 ], bytes );
68 in.read( (
char *) &p1[ 0 ], bytes );
69 in.read( (
char *) &p2[ 0 ], bytes );
73 static void registerFactory()
77 key() = Dune::BoundarySegment< 2, dimWorld >::template registerFactory< ThisType >();
81 virtual GlobalVector operator() (
const Dune::FieldVector<double,1> &local )
const
85 y.axpy((local[0]-alpha)*(local[0]-1.0)/alpha,p0);
86 y.axpy(local[0]*(local[0]-1.0)/(alpha*(alpha-1.0)),p1);
87 y.axpy(local[0]*(local[0]-alpha)/(1.0-alpha),p2);
91 void backup( ObjectStreamType& out )
const
94 out.write( (
const char *) &key(),
sizeof(
int ) );
96 const int bytes =
sizeof(double)*dimWorld;
97 out.write( (
const char*) &p0[ 0 ], bytes );
98 out.write( (
const char*) &p1[ 0 ], bytes );
99 out.write( (
const char*) &p2[ 0 ], bytes );
110 alpha=d1.two_norm()/(d1.two_norm()+d2.two_norm());
111 if (alpha<1E-6 || alpha>1-1E-6)
112 DUNE_THROW(Dune::IOError,
"ration in quadratic boundary segment bad");
150 class GmshReaderQuadraticBoundarySegment< 3, 3 >
151 :
public Dune::BoundarySegment< 3 >
153 typedef GmshReaderQuadraticBoundarySegment< 3, 3 > ThisType;
154 typedef typename Dune::BoundarySegment< 3 > :: ObjectStreamType ObjectStreamType;
156 GmshReaderQuadraticBoundarySegment (Dune::FieldVector<double,3> p0_, Dune::FieldVector<double,3> p1_,
157 Dune::FieldVector<double,3> p2_, Dune::FieldVector<double,3> p3_,
158 Dune::FieldVector<double,3> p4_, Dune::FieldVector<double,3> p5_)
159 : p0(p0_), p1(p1_), p2(p2_), p3(p3_), p4(p4_), p5(p5_)
164 GmshReaderQuadraticBoundarySegment( ObjectStreamType& in )
166 const int bytes =
sizeof(double)*3;
167 in.read( (
char *) &p0[ 0 ], bytes );
168 in.read( (
char *) &p1[ 0 ], bytes );
169 in.read( (
char *) &p2[ 0 ], bytes );
170 in.read( (
char *) &p3[ 0 ], bytes );
171 in.read( (
char *) &p4[ 0 ], bytes );
172 in.read( (
char *) &p5[ 0 ], bytes );
176 static void registerFactory()
180 key() = Dune::BoundarySegment< 3 >::template registerFactory< ThisType >();
184 virtual Dune::FieldVector<double,3> operator() (
const Dune::FieldVector<double,2>& local)
const
186 Dune::FieldVector<double,3> y;
188 y.axpy(phi0(local),p0);
189 y.axpy(phi1(local),p1);
190 y.axpy(phi2(local),p2);
191 y.axpy(phi3(local),p3);
192 y.axpy(phi4(local),p4);
193 y.axpy(phi5(local),p5);
197 void backup( ObjectStreamType& out )
const
200 out.write( (
const char*) &key(),
sizeof(
int ) );
202 const int bytes =
sizeof(double)*3;
203 out.write( (
const char*) &p0[ 0 ], bytes );
204 out.write( (
const char*) &p1[ 0 ], bytes );
205 out.write( (
const char*) &p2[ 0 ], bytes );
206 out.write( (
const char*) &p3[ 0 ], bytes );
207 out.write( (
const char*) &p4[ 0 ], bytes );
208 out.write( (
const char*) &p5[ 0 ], bytes );
216 Dune::FieldVector<double,3> d1,d2;
220 alpha=d1.two_norm()/(d1.two_norm()+d2.two_norm());
221 if (alpha<1E-6 || alpha>1-1E-6)
222 DUNE_THROW(Dune::IOError,
"alpha in quadratic boundary segment bad");
226 beta=d1.two_norm()/(d1.two_norm()+d2.two_norm());
227 if (beta<1E-6 || beta>1-1E-6)
228 DUNE_THROW(Dune::IOError,
"beta in quadratic boundary segment bad");
232 gamma=sqrt2*(d1.two_norm()/(d1.two_norm()+d2.two_norm()));
233 if (gamma<1E-6 || gamma>1-1E-6)
234 DUNE_THROW(Dune::IOError,
"gamma in quadratic boundary segment bad");
246 double phi0 (
const Dune::FieldVector<double,2>& local)
const
248 return (alpha*beta-beta*local[0]-alpha*local[1])*(1-local[0]-local[1])/(alpha*beta);
250 double phi3 (
const Dune::FieldVector<double,2>& local)
const
252 return local[0]*(1-local[0]-local[1])/(alpha*(1-alpha));
254 double phi1 (
const Dune::FieldVector<double,2>& local)
const
256 return local[0]*(gamma*local[0]-(sqrt2-gamma-sqrt2*alpha)*local[1]-alpha*gamma)/(gamma*(1-alpha));
258 double phi5 (
const Dune::FieldVector<double,2>& local)
const
260 return local[1]*(1-local[0]-local[1])/(beta*(1-beta));
262 double phi4 (
const Dune::FieldVector<double,2>& local)
const
264 return local[0]*local[1]/((1-gamma/sqrt2)*gamma/sqrt2);
266 double phi2 (
const Dune::FieldVector<double,2>& local)
const
268 return local[1]*(beta*(1-gamma/sqrt2)-local[0]*(beta-gamma/sqrt2)-local[1]*(1-gamma/sqrt2))/((1-gamma/sqrt2)*(beta-1));
271 Dune::FieldVector<double,3> p0,p1,p2,p3,p4,p5;
272 double alpha,beta,gamma,sqrt2;
278 template<
typename Gr
idType>
283 Dune::GridFactory<GridType>& factory;
285 bool insert_boundary_segments;
286 unsigned int number_of_real_vertices;
287 int boundary_element_count;
291 std::string fileName;
293 std::vector<int> boundary_id_to_physical_entity;
294 std::vector<int> element_index_to_physical_entity;
295 std::vector<std::string> physical_entity_names;
298 static const int dim = GridType::dimension;
299 static const int dimWorld = GridType::dimensionworld;
300 static_assert( (dimWorld <= 3),
"GmshReader requires dimWorld <= 3." );
303 typedef FieldVector< double, dimWorld > GlobalVector;
309 void readfile(FILE * file,
int cnt,
const char * format, ...)
311 __attribute__((format(scanf, 4, 5)))
315 va_start(ap, format);
316 auto pos = std::ftell(file);
317 int c = std::vfscanf(file, format, ap);
320 DUNE_THROW(Dune::IOError,
"Error parsing " << fileName <<
" "
322 <<
": Expected '" << format <<
"', only read " << c <<
" entries instead of " << cnt <<
".");
326 void skipline(FILE * file)
330 c = std::fgetc(file);
331 }
while(c !=
'\n' && c != EOF);
336 Gmsh2Parser(Dune::GridFactory<GridType>& _factory,
bool v,
bool i) :
337 factory(_factory), verbose(v), insert_boundary_segments(i) {}
339 std::vector<int> & boundaryIdMap()
341 return boundary_id_to_physical_entity;
345 std::vector<int> & elementIndexMap()
347 return element_index_to_physical_entity;
351 std::vector<std::string> & physicalEntityNames()
353 return physical_entity_names;
356 void read (
const std::string& f)
358 if (verbose) std::cout <<
"Reading " << dim <<
"d Gmsh grid..." << std::endl;
362 FILE* file = fopen(fileName.c_str(),
"rb");
364 DUNE_THROW(Dune::IOError,
"Could not open " << fileName);
371 number_of_real_vertices = 0;
372 boundary_element_count = 0;
376 double version_number;
377 int file_type, data_size;
379 readfile(file,1,
"%s\n",buf);
380 if (strcmp(buf,
"$MeshFormat")!=0)
381 DUNE_THROW(Dune::IOError,
"expected $MeshFormat in first line");
382 readfile(file,3,
"%lg %d %d\n",&version_number,&file_type,&data_size);
385 if( (version_number < 2.0) || (version_number >= 2.20001) )
386 DUNE_THROW(Dune::IOError,
"can only read Gmsh version 2 files");
387 if (verbose) std::cout <<
"version " << version_number <<
" Gmsh file detected" << std::endl;
388 readfile(file,1,
"%s\n",buf);
389 if (strcmp(buf,
"$EndMeshFormat")!=0)
390 DUNE_THROW(Dune::IOError,
"expected $EndMeshFormat");
393 physical_entity_names.clear();
394 readfile(file,1,
"%s\n",buf);
395 if (strcmp(buf,
"$PhysicalNames")==0) {
397 readfile(file,1,
"%d\n",&number_of_names);
398 if (verbose) std::cout <<
"file contains " << number_of_names <<
" physical entities" << std::endl;
399 physical_entity_names.resize(number_of_names);
400 std::string buf_name;
401 for(
int i = 0; i < number_of_names; ++i ) {
403 readfile(file,3,
"%d %d %s\n", &edim, &
id, buf);
404 buf_name.assign(buf);
405 auto begin = buf_name.find_first_of(
'\"') + 1;
406 auto end = buf_name.find_last_of(
'\"') - begin;
407 physical_entity_names[
id-1].assign(buf_name.substr(begin, end));
409 readfile(file,1,
"%s\n",buf);
410 if (strcmp(buf,
"$EndPhysicalNames")!=0)
411 DUNE_THROW(Dune::IOError,
"expected $EndPhysicalNames");
412 readfile(file,1,
"%s\n",buf);
418 if (strcmp(buf,
"$Nodes")!=0)
419 DUNE_THROW(Dune::IOError,
"expected $Nodes");
420 readfile(file,1,
"%d\n",&number_of_nodes);
421 if (verbose) std::cout <<
"file contains " << number_of_nodes <<
" nodes" << std::endl;
425 std::vector< GlobalVector > nodes( number_of_nodes+1 );
429 for(
int i = 1; i <= number_of_nodes; ++i )
431 readfile(file,4,
"%d %lg %lg %lg\n", &
id, &x[ 0 ], &x[ 1 ], &x[ 2 ] );
433 if (
id > number_of_nodes) {
434 DUNE_THROW(Dune::IOError,
435 "Only dense sequences of node indices are currently supported (node index "
436 <<
id <<
" is invalid).");
440 for(
int j = 0; j < dimWorld; ++j )
441 nodes[
id ][ j ] = x[ j ];
443 readfile(file,1,
"%s\n",buf);
444 if (strcmp(buf,
"$EndNodes")!=0)
445 DUNE_THROW(Dune::IOError,
"expected $EndNodes");
449 readfile(file,1,
"%s\n",buf);
450 if (strcmp(buf,
"$Elements")!=0)
451 DUNE_THROW(Dune::IOError,
"expected $Elements");
452 int number_of_elements;
453 readfile(file,1,
"%d\n",&number_of_elements);
454 if (verbose) std::cout <<
"file contains " << number_of_elements <<
" elements" << std::endl;
461 auto section_element_offset = std::ftell(file);
462 std::map<int,unsigned int>
renumber;
463 for (
int i=1; i<=number_of_elements; i++)
465 int id, elm_type, number_of_tags;
466 readfile(file,3,
"%d %d %d ",&
id,&elm_type,&number_of_tags);
467 for (
int k=1; k<=number_of_tags; k++)
470 readfile(file,1,
"%d ",&blub);
479 pass1HandleElement(file, elm_type, renumber, nodes);
481 if (verbose) std::cout <<
"number of real vertices = " << number_of_real_vertices << std::endl;
482 if (verbose) std::cout <<
"number of boundary elements = " << boundary_element_count << std::endl;
483 if (verbose) std::cout <<
"number of elements = " << element_count << std::endl;
484 readfile(file,1,
"%s\n",buf);
485 if (strcmp(buf,
"$EndElements")!=0)
486 DUNE_THROW(Dune::IOError,
"expected $EndElements");
487 boundary_id_to_physical_entity.resize(boundary_element_count);
488 element_index_to_physical_entity.resize(element_count);
494 std::fseek(file, section_element_offset, SEEK_SET);
495 boundary_element_count = 0;
497 for (
int i=1; i<=number_of_elements; i++)
499 int id, elm_type, number_of_tags;
500 readfile(file,3,
"%d %d %d ",&
id,&elm_type,&number_of_tags);
501 int physical_entity = -1;
503 for (
int k=1; k<=number_of_tags; k++)
506 readfile(file,1,
"%d ",&blub);
507 if (k==1) physical_entity = blub;
509 pass2HandleElement(file, elm_type, renumber, nodes, physical_entity);
511 readfile(file,1,
"%s\n",buf);
512 if (strcmp(buf,
"$EndElements")!=0)
513 DUNE_THROW(Dune::IOError,
"expected $EndElements");
523 void pass1HandleElement(FILE* file,
const int elm_type,
524 std::map<int,unsigned int> & renumber,
525 const std::vector< GlobalVector > & nodes)
528 const int nDofs[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 3, 6, -1, 10, -1, -1, -1, 1};
529 const int nVertices[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 2, 3, -1, 4, -1, -1, -1, 1};
530 const int elementDim[16] = {-1, 1, 2, 2, 3, 3, 3, 3, 1, 2, -1, 3, -1, -1, -1, 0};
533 if ( not (elm_type > 0 && elm_type <= 15
534 && (elementDim[elm_type] == dim || elementDim[elm_type] == (dim-1) ) ) )
541 std::string formatString =
"%d";
542 for (
int i=1; i<nDofs[elm_type]; i++)
543 formatString +=
" %d";
544 formatString +=
"\n";
547 std::vector<int> elementDofs(10);
549 readfile(file,nDofs[elm_type], formatString.c_str(),
550 &(elementDofs[0]),&(elementDofs[1]),&(elementDofs[2]),
551 &(elementDofs[3]),&(elementDofs[4]),&(elementDofs[5]),
552 &(elementDofs[6]),&(elementDofs[7]),&(elementDofs[8]),
556 for (
int i=0; i<nVertices[elm_type]; i++)
559 renumber[elementDofs[i]] = number_of_real_vertices++;
560 factory.insertVertex(nodes[elementDofs[i]]);
564 if (elementDim[elm_type] == dim)
567 boundary_element_count++;
574 template <
class E,
class V,
class V2>
575 void boundarysegment_insert(
581 DUNE_THROW(Dune::IOError,
"tried to create a 3D boundary segment in a non-3D Grid");
585 template <
class E,
class V>
586 void boundarysegment_insert(
587 const std::vector<FieldVector<double, 3> >& nodes,
588 const E& elementDofs,
592 std::array<FieldVector<double,dimWorld>, 6> v;
593 for (
int i=0; i<6; i++)
594 for (
int j=0; j<dimWorld; j++)
595 v[i][j] = nodes[elementDofs[i]][j];
597 BoundarySegment<dim,dimWorld>* newBoundarySegment
598 = (BoundarySegment<dim,dimWorld>*)
new GmshReaderQuadraticBoundarySegment< 3, 3 >( v[0], v[1], v[2],
601 factory.insertBoundarySegment(
vertices,
602 std::shared_ptr<BoundarySegment<dim,dimWorld> >(newBoundarySegment) );
611 virtual void pass2HandleElement(FILE* file,
const int elm_type,
612 std::map<int,unsigned int> & renumber,
613 const std::vector< GlobalVector > & nodes,
614 const int physical_entity)
617 const int nDofs[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 3, 6, -1, 10, -1, -1, -1, 1};
618 const int nVertices[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 2, 3, -1, 4, -1, -1, -1, 1};
619 const int elementDim[16] = {-1, 1, 2, 2, 3, 3, 3, 3, 1, 2, -1, 3, -1, -1, -1, 0};
622 if ( not (elm_type > 0 && elm_type <= 15
623 && (elementDim[elm_type] == dim || elementDim[elm_type] == (dim-1) ) ) )
630 std::string formatString =
"%d";
631 for (
int i=1; i<nDofs[elm_type]; i++)
632 formatString +=
" %d";
633 formatString +=
"\n";
636 std::vector<int> elementDofs(10);
638 readfile(file,nDofs[elm_type], formatString.c_str(),
639 &(elementDofs[0]),&(elementDofs[1]),&(elementDofs[2]),
640 &(elementDofs[3]),&(elementDofs[4]),&(elementDofs[5]),
641 &(elementDofs[6]),&(elementDofs[7]),&(elementDofs[8]),
648 std::swap(elementDofs[2],elementDofs[3]);
651 std::swap(elementDofs[2],elementDofs[3]);
652 std::swap(elementDofs[6],elementDofs[7]);
655 std::swap(elementDofs[2],elementDofs[3]);
661 std::vector<unsigned int>
vertices(nVertices[elm_type]);
663 for (
int i=0; i<nVertices[elm_type]; i++)
664 vertices[i] = renumber[elementDofs[i]];
667 if (elementDim[elm_type] == dim) {
672 factory.insertElement(Dune::GeometryTypes::line,
vertices);
675 factory.insertElement(Dune::GeometryTypes::triangle,
vertices);
678 factory.insertElement(Dune::GeometryTypes::quadrilateral,
vertices);
681 factory.insertElement(Dune::GeometryTypes::tetrahedron,
vertices);
684 factory.insertElement(Dune::GeometryTypes::hexahedron,
vertices);
687 factory.insertElement(Dune::GeometryTypes::prism,
vertices);
690 factory.insertElement(Dune::GeometryTypes::pyramid,
vertices);
693 factory.insertElement(Dune::GeometryTypes::triangle,
vertices);
696 factory.insertElement(Dune::GeometryTypes::tetrahedron,
vertices);
702 if (insert_boundary_segments) {
707 factory.insertBoundarySegment(
vertices);
711 factory.insertBoundarySegment(
vertices);
715 factory.insertBoundarySegment(
vertices);
719 factory.insertBoundarySegment(
vertices);
723 std::array<FieldVector<double,dimWorld>, 3> v;
724 for (
int i=0; i<dimWorld; i++) {
725 v[0][i] = nodes[elementDofs[0]][i];
726 v[1][i] = nodes[elementDofs[2]][i];
727 v[2][i] = nodes[elementDofs[1]][i];
729 BoundarySegment<dim,dimWorld>* newBoundarySegment
730 = (BoundarySegment<dim,dimWorld>*)
new GmshReaderQuadraticBoundarySegment< 2, dimWorld >(v[0], v[1], v[2]);
731 factory.insertBoundarySegment(
vertices,
732 std::shared_ptr<BoundarySegment<dim,dimWorld> >(newBoundarySegment));
736 boundarysegment_insert(nodes, elementDofs,
vertices);
740 DUNE_THROW(Dune::IOError,
"GmshReader does not support using element-type " << elm_type <<
" for boundary segments");
750 if (elementDim[elm_type] == dim) {
751 element_index_to_physical_entity[element_count] = physical_entity;
754 boundary_id_to_physical_entity[boundary_element_count] = physical_entity;
755 boundary_element_count++;
Base class for grid boundary segments of arbitrary geometry.
IteratorRange<... > vertices(const GV &gv)
Iterates over all vertices (entities with dimension 0) of a GridView.
void swap(Dune::PersistentContainer< G, T > &a, Dune::PersistentContainer< G, T > &b)
Definition utility/persistentcontainer.hh:83
ALBERTA REAL_D GlobalVector
Definition misc.hh:50
int renumber(const Dune::GeometryType &t, int i)
renumber VTK <-> Dune
Definition common.hh:186
Provide a generic factory class for unstructured grids.