DUNE PDELab (unstable)

gmshreader.hh
1// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file LICENSE.md in module root
2// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
3// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4// vi: set et ts=4 sw=2 sts=2:
5
6#ifndef DUNE_GMSHREADER_HH
7#define DUNE_GMSHREADER_HH
8
9#include <cstdarg>
10#include <cstdio>
11#include <cstring>
12#include <fstream>
13#include <iostream>
14#include <map>
15#include <memory>
16#include <string>
17#include <tuple>
18#include <vector>
19#include <utility>
20
23
24#include <dune/geometry/type.hh>
25
28
29namespace Dune
30{
31
42 struct [[deprecated]] GmshReaderOptions
43 {
48 secondOrder
49 };
50 };
51
52 namespace {
53
54 // arbitrary dimension, implementation is in specialization
55 template< int dimension, int dimWorld = dimension >
56 class GmshReaderQuadraticBoundarySegment
57 {
58 public:
59 // empty function since this class does not implement anything
60 static void registerFactory() {}
61 };
62
63 // quadratic boundary segments in 1d
64 /*
65 Note the points
66
67 (0) (alpha) (1)
68
69 are mapped to the points in global coordinates
70
71 p0 p2 p1
72
73 alpha is determined automatically from the given points.
74 */
75 template< int dimWorld >
76 struct GmshReaderQuadraticBoundarySegment< 2, dimWorld >
77 : public Dune::BoundarySegment< 2, dimWorld >
78 {
79 typedef GmshReaderQuadraticBoundarySegment< 2, dimWorld > ThisType;
80 typedef typename Dune::BoundarySegment< 2, dimWorld > :: ObjectStreamType ObjectStreamType;
81 typedef Dune::FieldVector< double, dimWorld > GlobalVector;
82
83 GmshReaderQuadraticBoundarySegment ( const GlobalVector &p0_, const GlobalVector &p1_, const GlobalVector &p2_)
84 : p0(p0_), p1(p1_), p2(p2_)
85 {
86 init();
87 }
88
89 GmshReaderQuadraticBoundarySegment( ObjectStreamType& in )
90 {
91 // key is read before by the factory
92 const int bytes = sizeof(double)*dimWorld;
93 in.read( (char *) &p0[ 0 ], bytes );
94 in.read( (char *) &p1[ 0 ], bytes );
95 in.read( (char *) &p2[ 0 ], bytes );
96 init();
97 }
98
99 static void registerFactory()
100 {
101 if( key() < 0 )
102 {
103 key() = Dune::BoundarySegment< 2, dimWorld >::template registerFactory< ThisType >();
104 }
105 }
106
107 virtual GlobalVector operator() ( const Dune::FieldVector<double,1> &local ) const
108 {
109 GlobalVector y;
110 y = 0.0;
111 y.axpy((local[0]-alpha)*(local[0]-1.0)/alpha,p0);
112 y.axpy(local[0]*(local[0]-1.0)/(alpha*(alpha-1.0)),p1);
113 y.axpy(local[0]*(local[0]-alpha)/(1.0-alpha),p2);
114 return y;
115 }
116
117 void backup( ObjectStreamType& out ) const
118 {
119 // backup key to identify object
120 out.write( (const char *) &key(), sizeof( int ) );
121 // backup data
122 const int bytes = sizeof(double)*dimWorld;
123 out.write( (const char*) &p0[ 0 ], bytes );
124 out.write( (const char*) &p1[ 0 ], bytes );
125 out.write( (const char*) &p2[ 0 ], bytes );
126 }
127
128 protected:
129 void init()
130 {
131 GlobalVector d1 = p1;
132 d1 -= p0;
133 GlobalVector d2 = p2;
134 d2 -= p1;
135
136 alpha=d1.two_norm()/(d1.two_norm()+d2.two_norm());
137 if (alpha<1E-6 || alpha>1-1E-6)
138 DUNE_THROW(Dune::IOError, "ration in quadratic boundary segment bad");
139 }
140
141 static int& key() {
142 static int k = -1;
143 return k;
144 }
145
146 private:
147 GlobalVector p0,p1,p2;
148 double alpha;
149 };
150
151
152 // quadratic boundary segments in 2d
153 /* numbering of points corresponding to gmsh:
154
155 2
156
157 5 4
158
159 0 3 1
160
161 Note: The vertices 3, 4, 5 are not necessarily at the edge midpoints but can
162 be placed with parameters alpha, beta , gamma at the following positions
163 in local coordinates:
164
165
166 2 = (0,1)
167
168 5 = (0,beta) 4 = (1-gamma/sqrt(2),gamma/sqrt(2))
169
170 0 = (0,0) 3 = (alpha,0) 1 = (1,0)
171
172 The parameters alpha, beta, gamma are determined from the given vertices in
173 global coordinates.
174 */
175 template<>
176 class GmshReaderQuadraticBoundarySegment< 3, 3 >
177 : public Dune::BoundarySegment< 3 >
178 {
179 typedef GmshReaderQuadraticBoundarySegment< 3, 3 > ThisType;
180 typedef typename Dune::BoundarySegment< 3 > :: ObjectStreamType ObjectStreamType;
181 public:
182 GmshReaderQuadraticBoundarySegment (Dune::FieldVector<double,3> p0_, Dune::FieldVector<double,3> p1_,
185 : p0(p0_), p1(p1_), p2(p2_), p3(p3_), p4(p4_), p5(p5_)
186 {
187 init();
188 }
189
190 GmshReaderQuadraticBoundarySegment( ObjectStreamType& in )
191 {
192 const int bytes = sizeof(double)*3;
193 in.read( (char *) &p0[ 0 ], bytes );
194 in.read( (char *) &p1[ 0 ], bytes );
195 in.read( (char *) &p2[ 0 ], bytes );
196 in.read( (char *) &p3[ 0 ], bytes );
197 in.read( (char *) &p4[ 0 ], bytes );
198 in.read( (char *) &p5[ 0 ], bytes );
199 init();
200 }
201
202 static void registerFactory()
203 {
204 if( key() < 0 )
205 {
206 key() = Dune::BoundarySegment< 3 >::template registerFactory< ThisType >();
207 }
208 }
209
210 virtual Dune::FieldVector<double,3> operator() (const Dune::FieldVector<double,2>& local) const
211 {
213 y = 0.0;
214 y.axpy(phi0(local),p0);
215 y.axpy(phi1(local),p1);
216 y.axpy(phi2(local),p2);
217 y.axpy(phi3(local),p3);
218 y.axpy(phi4(local),p4);
219 y.axpy(phi5(local),p5);
220 return y;
221 }
222
223 void backup( ObjectStreamType& out ) const
224 {
225 // backup key to identify object in factory
226 out.write( (const char*) &key(), sizeof( int ) );
227 // backup data
228 const int bytes = sizeof(double)*3;
229 out.write( (const char*) &p0[ 0 ], bytes );
230 out.write( (const char*) &p1[ 0 ], bytes );
231 out.write( (const char*) &p2[ 0 ], bytes );
232 out.write( (const char*) &p3[ 0 ], bytes );
233 out.write( (const char*) &p4[ 0 ], bytes );
234 out.write( (const char*) &p5[ 0 ], bytes );
235 }
236
237 protected:
238 void init()
239 {
240 using std::sqrt;
241 sqrt2 = sqrt(2.0);
243
244 d1 = p3; d1 -= p0;
245 d2 = p1; d2 -= p3;
246 alpha=d1.two_norm()/(d1.two_norm()+d2.two_norm());
247 if (alpha<1E-6 || alpha>1-1E-6)
248 DUNE_THROW(Dune::IOError, "alpha in quadratic boundary segment bad");
249
250 d1 = p5; d1 -= p0;
251 d2 = p2; d2 -= p5;
252 beta=d1.two_norm()/(d1.two_norm()+d2.two_norm());
253 if (beta<1E-6 || beta>1-1E-6)
254 DUNE_THROW(Dune::IOError, "beta in quadratic boundary segment bad");
255
256 d1 = p4; d1 -= p1;
257 d2 = p2; d2 -= p4;
258 gamma=sqrt2*(d1.two_norm()/(d1.two_norm()+d2.two_norm()));
259 if (gamma<1E-6 || gamma>1-1E-6)
260 DUNE_THROW(Dune::IOError, "gamma in quadratic boundary segment bad");
261 }
262
263 static int& key() {
264 static int k = -1;
265 return k;
266 }
267
268 private:
269 // The six Lagrange basis function on the reference element
270 // for the points given above
271
272 double phi0 (const Dune::FieldVector<double,2>& local) const
273 {
274 return (alpha*beta-beta*local[0]-alpha*local[1])*(1-local[0]-local[1])/(alpha*beta);
275 }
276 double phi3 (const Dune::FieldVector<double,2>& local) const
277 {
278 return local[0]*(1-local[0]-local[1])/(alpha*(1-alpha));
279 }
280 double phi1 (const Dune::FieldVector<double,2>& local) const
281 {
282 return local[0]*(gamma*local[0]-(sqrt2-gamma-sqrt2*alpha)*local[1]-alpha*gamma)/(gamma*(1-alpha));
283 }
284 double phi5 (const Dune::FieldVector<double,2>& local) const
285 {
286 return local[1]*(1-local[0]-local[1])/(beta*(1-beta));
287 }
288 double phi4 (const Dune::FieldVector<double,2>& local) const
289 {
290 return local[0]*local[1]/((1-gamma/sqrt2)*gamma/sqrt2);
291 }
292 double phi2 (const Dune::FieldVector<double,2>& local) const
293 {
294 return local[1]*(beta*(1-gamma/sqrt2)-local[0]*(beta-gamma/sqrt2)-local[1]*(1-gamma/sqrt2))/((1-gamma/sqrt2)*(beta-1));
295 }
296
297 Dune::FieldVector<double,3> p0,p1,p2,p3,p4,p5;
298 double alpha,beta,gamma,sqrt2;
299 };
300
301 } // end empty namespace
302
304 template<typename GridType>
306 {
307 protected:
308 // private data
310 bool verbose;
311 bool insert_boundary_segments;
312 unsigned int number_of_real_vertices;
313 int boundary_element_count;
314 int element_count;
315 // read buffer
316 char buf[512];
317 std::string fileName;
318 // exported data
319 std::vector<int> boundary_id_to_physical_entity;
320 std::vector<int> element_index_to_physical_entity;
321 std::vector<std::string> physical_entity_names;
322
323 // static data
324 static const int dim = GridType::dimension;
325 static const int dimWorld = GridType::dimensionworld;
326 static_assert( (dimWorld <= 3), "GmshReader requires dimWorld <= 3." );
327
328 // typedefs
330
331 // don't use something like
332 // readfile(file, 1, "%s\n", buf);
333 // to skip the rest of of the line -- that will only skip the next
334 // whitespace-separated word! Use skipline() instead.
335 void readfile(FILE * file, int cnt, const char * format, ...)
336#ifdef __GNUC__
337 __attribute__((format(scanf, 4, 5)))
338#endif
339 {
340 std::va_list ap;
341 va_start(ap, format);
342 auto pos = std::ftell(file);
343 int c = std::vfscanf(file, format, ap);
344 va_end(ap);
345 if (c != cnt)
346 DUNE_THROW(Dune::IOError, "Error parsing " << fileName << " "
347 "file pos " << pos
348 << ": Expected '" << format << "', only read " << c << " entries instead of " << cnt << ".");
349 }
350
351 // skip over the rest of the line, including the terminating newline
352 void skipline(FILE * file)
353 {
354 int c;
355 do {
356 c = std::fgetc(file);
357 } while(c != '\n' && c != EOF);
358 }
359
360 public:
361
362 GmshReaderParser(Dune::GridFactory<GridType>& _factory, bool v, bool i) :
363 factory(_factory), verbose(v), insert_boundary_segments(i) {}
364
365 std::vector<int> & boundaryIdMap()
366 {
367 return boundary_id_to_physical_entity;
368 }
369
371 std::vector<int> & elementIndexMap()
372 {
373 return element_index_to_physical_entity;
374 }
375
377 std::vector<std::string> & physicalEntityNames()
378 {
379 return physical_entity_names;
380 }
381
382 void read (const std::string& f)
383 {
384 if (verbose) std::cout << "Reading " << dim << "d Gmsh grid..." << std::endl;
385
386 // open file name, we use C I/O
387 fileName = f;
388 FILE* file = fopen(fileName.c_str(),"rb");
389 if (file==0)
390 DUNE_THROW(Dune::IOError, "Could not open " << fileName);
391
392 //=========================================
393 // Header: Read vertices into vector
394 // Check vertices that are needed
395 //=========================================
396
397 number_of_real_vertices = 0;
398 boundary_element_count = 0;
399 element_count = 0;
400
401 // process header
402 double version_number;
403 int file_type, data_size;
404
405 readfile(file,1,"%s\n",buf);
406 if (strcmp(buf,"$MeshFormat")!=0)
407 DUNE_THROW(Dune::IOError, "expected $MeshFormat in first line");
408 readfile(file,3,"%lg %d %d\n",&version_number,&file_type,&data_size);
409 // 2.2 is not representable as float and leads to problems on i386
410 // Hence we use >= 2.00001.
411 if( (version_number < 2.0) || (version_number >= 2.20001) ) // 2.2 is not representable as float and leads to problems on i386
412 DUNE_THROW(Dune::IOError, "can only read Gmsh version 2 files");
413 if (verbose) std::cout << "version " << version_number << " Gmsh file detected" << std::endl;
414 readfile(file,1,"%s\n",buf);
415 if (strcmp(buf,"$EndMeshFormat")!=0)
416 DUNE_THROW(Dune::IOError, "expected $EndMeshFormat");
417
418 // physical name section
419 physical_entity_names.clear();
420 readfile(file,1,"%s\n",buf);
421 if (strcmp(buf,"$PhysicalNames")==0) {
422 int number_of_names;
423 readfile(file,1,"%d\n",&number_of_names);
424 if (verbose) std::cout << "file contains " << number_of_names << " physical entities" << std::endl;
425 physical_entity_names.resize(number_of_names);
426 std::string buf_name;
427 for( int i = 0; i < number_of_names; ++i ) {
428 int edim, id;
429 readfile(file,3, "%d %d %s\n", &edim, &id, buf);
430 buf_name.assign(buf);
431 auto begin = buf_name.find_first_of('\"') + 1;
432 auto end = buf_name.find_last_of('\"') - begin;
433 physical_entity_names[id-1].assign(buf_name.substr(begin, end));
434 }
435 readfile(file,1,"%s\n",buf);
436 if (strcmp(buf,"$EndPhysicalNames")!=0)
437 DUNE_THROW(Dune::IOError, "expected $EndPhysicalNames");
438 readfile(file,1,"%s\n",buf);
439 }
440
441 // node section
442 int number_of_nodes;
443
444 if (strcmp(buf,"$Nodes")!=0)
445 DUNE_THROW(Dune::IOError, "expected $Nodes");
446 readfile(file,1,"%d\n",&number_of_nodes);
447 if (verbose) std::cout << "file contains " << number_of_nodes << " nodes" << std::endl;
448
449 // read nodes
450 // The '+1' is due to the fact that gmsh numbers node starting from 1 rather than from 0
451 std::vector< GlobalVector > nodes( number_of_nodes+1 );
452 {
453 int id;
454 double x[ 3 ];
455 for( int i = 1; i <= number_of_nodes; ++i )
456 {
457 readfile(file,4, "%d %lg %lg %lg\n", &id, &x[ 0 ], &x[ 1 ], &x[ 2 ] );
458
459 if (id > number_of_nodes) {
461 "Only dense sequences of node indices are currently supported (node index "
462 << id << " is invalid).");
463 }
464
465 // just store node position
466 for( int j = 0; j < dimWorld; ++j )
467 nodes[ id ][ j ] = x[ j ];
468 }
469 readfile(file,1,"%s\n",buf);
470 if (strcmp(buf,"$EndNodes")!=0)
471 DUNE_THROW(Dune::IOError, "expected $EndNodes");
472 }
473
474 // element section
475 readfile(file,1,"%s\n",buf);
476 if (strcmp(buf,"$Elements")!=0)
477 DUNE_THROW(Dune::IOError, "expected $Elements");
478 int number_of_elements;
479 readfile(file,1,"%d\n",&number_of_elements);
480 if (verbose) std::cout << "file contains " << number_of_elements << " elements" << std::endl;
481
482 //=========================================
483 // Pass 1: Select and insert those vertices in the file that
484 // actually occur as corners of an element.
485 //=========================================
486
487 auto section_element_offset = std::ftell(file);
488 std::map<int,unsigned int> renumber;
489 for (int i=1; i<=number_of_elements; i++)
490 {
491 int id, elm_type, number_of_tags;
492 readfile(file,3,"%d %d %d ",&id,&elm_type,&number_of_tags);
493 for (int k=1; k<=number_of_tags; k++)
494 {
495 int blub;
496 readfile(file,1,"%d ",&blub);
497 // k == 1: physical entity
498 // k == 2: elementary entity (not used here)
499 // if version_number < 2.2:
500 // k == 3: mesh partition 0
501 // else
502 // k == 3: number of mesh partitions
503 // k => 4: mesh partition k-4
504 }
505 pass1HandleElement(file, elm_type, renumber, nodes);
506 }
507 if (verbose) std::cout << "number of real vertices = " << number_of_real_vertices << std::endl;
508 if (verbose) std::cout << "number of boundary elements = " << boundary_element_count << std::endl;
509 if (verbose) std::cout << "number of elements = " << element_count << std::endl;
510 readfile(file,1,"%s\n",buf);
511 if (strcmp(buf,"$EndElements")!=0)
512 DUNE_THROW(Dune::IOError, "expected $EndElements");
513 boundary_id_to_physical_entity.resize(boundary_element_count);
514 element_index_to_physical_entity.resize(element_count);
515
516 //==============================================
517 // Pass 2: Insert boundary segments and elements
518 //==============================================
519
520 std::fseek(file, section_element_offset, SEEK_SET);
521 boundary_element_count = 0;
522 element_count = 0;
523 for (int i=1; i<=number_of_elements; i++)
524 {
525 int id, elm_type, number_of_tags;
526 readfile(file,3,"%d %d %d ",&id,&elm_type,&number_of_tags);
527 int physical_entity = -1;
528
529 for (int k=1; k<=number_of_tags; k++)
530 {
531 int blub;
532 readfile(file,1,"%d ",&blub);
533 if (k==1) physical_entity = blub;
534 }
535 pass2HandleElement(file, elm_type, renumber, nodes, physical_entity);
536 }
537 readfile(file,1,"%s\n",buf);
538 if (strcmp(buf,"$EndElements")!=0)
539 DUNE_THROW(Dune::IOError, "expected $EndElements");
540
541 fclose(file);
542 }
543
549 void pass1HandleElement(FILE* file, const int elm_type,
550 std::map<int,unsigned int> & renumber,
551 const std::vector< GlobalVector > & nodes)
552 {
553 // some data about gmsh elements
554 const int nDofs[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 3, 6, -1, 10, -1, -1, -1, 1};
555 const int nVertices[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 2, 3, -1, 4, -1, -1, -1, 1};
556 const int elementDim[16] = {-1, 1, 2, 2, 3, 3, 3, 3, 1, 2, -1, 3, -1, -1, -1, 0};
557
558 // test whether we support the element type
559 if ( not (elm_type > 0 && elm_type <= 15 // index in suitable range?
560 && (elementDim[elm_type] == dim || elementDim[elm_type] == (dim-1) ) ) ) // real element or boundary element?
561 {
562 skipline(file); // skip rest of line if element is unknown
563 return;
564 }
565
566 // The format string for parsing is n times '%d' in a row
567 std::string formatString = "%d";
568 for (int i=1; i<nDofs[elm_type]; i++)
569 formatString += " %d";
570 formatString += "\n";
571
572 // '10' is the largest number of dofs we may encounter in a .msh file
573 std::vector<int> elementDofs(10);
574
575 readfile(file,nDofs[elm_type], formatString.c_str(),
576 &(elementDofs[0]),&(elementDofs[1]),&(elementDofs[2]),
577 &(elementDofs[3]),&(elementDofs[4]),&(elementDofs[5]),
578 &(elementDofs[6]),&(elementDofs[7]),&(elementDofs[8]),
579 &(elementDofs[9]));
580
581 // insert each vertex if it hasn't been inserted already
582 for (int i=0; i<nVertices[elm_type]; i++)
583 if (renumber.find(elementDofs[i])==renumber.end())
584 {
585 renumber[elementDofs[i]] = number_of_real_vertices++;
586 factory.insertVertex(nodes[elementDofs[i]]);
587 }
588
589 // count elements and boundary elements
590 if (elementDim[elm_type] == dim)
591 element_count++;
592 else
593 boundary_element_count++;
594
595 }
596
597
598
599 // generic-case: This is not supposed to be used at runtime.
600 template <class E, class V, class V2>
601 void boundarysegment_insert(
602 const V&,
603 const E&,
604 const V2&
605 )
606 {
607 DUNE_THROW(Dune::IOError, "tried to create a 3D boundary segment in a non-3D Grid");
608 }
609
610 // 3d-case:
611 template <class E, class V>
612 void boundarysegment_insert(
613 const std::vector<FieldVector<double, 3> >& nodes,
614 const E& elementDofs,
615 const V& vertices
616 )
617 {
618 std::array<FieldVector<double,dimWorld>, 6> v;
619 for (int i=0; i<6; i++)
620 for (int j=0; j<dimWorld; j++)
621 v[i][j] = nodes[elementDofs[i]][j];
622
623 BoundarySegment<dim,dimWorld>* newBoundarySegment
624 = (BoundarySegment<dim,dimWorld>*) new GmshReaderQuadraticBoundarySegment< 3, 3 >( v[0], v[1], v[2],
625 v[3], v[4], v[5] );
626
627 factory.insertBoundarySegment( vertices,
628 std::shared_ptr<BoundarySegment<dim,dimWorld> >(newBoundarySegment) );
629 }
630
631
632
637 virtual void pass2HandleElement(FILE* file, const int elm_type,
638 std::map<int,unsigned int> & renumber,
639 const std::vector< GlobalVector > & nodes,
640 const int physical_entity)
641 {
642 // some data about gmsh elements
643 const int nDofs[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 3, 6, -1, 10, -1, -1, -1, 1};
644 const int nVertices[16] = {-1, 2, 3, 4, 4, 8, 6, 5, 2, 3, -1, 4, -1, -1, -1, 1};
645 const int elementDim[16] = {-1, 1, 2, 2, 3, 3, 3, 3, 1, 2, -1, 3, -1, -1, -1, 0};
646
647 // test whether we support the element type
648 if ( not (elm_type > 0 && elm_type <= 15 // index in suitable range?
649 && (elementDim[elm_type] == dim || elementDim[elm_type] == (dim-1) ) ) ) // real element or boundary element?
650 {
651 skipline(file); // skip rest of line if element is unknown
652 return;
653 }
654
655 // The format string for parsing is n times '%d' in a row
656 std::string formatString = "%d";
657 for (int i=1; i<nDofs[elm_type]; i++)
658 formatString += " %d";
659 formatString += "\n";
660
661 // '10' is the largest number of dofs we may encounter in a .msh file
662 std::vector<int> elementDofs(10);
663
664 readfile(file,nDofs[elm_type], formatString.c_str(),
665 &(elementDofs[0]),&(elementDofs[1]),&(elementDofs[2]),
666 &(elementDofs[3]),&(elementDofs[4]),&(elementDofs[5]),
667 &(elementDofs[6]),&(elementDofs[7]),&(elementDofs[8]),
668 &(elementDofs[9]));
669
670 // correct differences between gmsh and Dune in the local vertex numbering
671 switch (elm_type)
672 {
673 case 3 : // 4-node quadrilateral
674 std::swap(elementDofs[2],elementDofs[3]);
675 break;
676 case 5 : // 8-node hexahedron
677 std::swap(elementDofs[2],elementDofs[3]);
678 std::swap(elementDofs[6],elementDofs[7]);
679 break;
680 case 7 : // 5-node pyramid
681 std::swap(elementDofs[2],elementDofs[3]);
682 break;
683 }
684
685 // renumber corners to account for the explicitly given vertex
686 // numbering in the file
687 std::vector<unsigned int> vertices(nVertices[elm_type]);
688
689 for (int i=0; i<nVertices[elm_type]; i++)
690 vertices[i] = renumber[elementDofs[i]];
691
692 // If it is an element, insert it as such
693 if (elementDim[elm_type] == dim) {
694
695 switch (elm_type)
696 {
697 case 1 : // 2-node line
699 break;
700 case 2 : // 3-node triangle
702 break;
703 case 3 : // 4-node quadrilateral
705 break;
706 case 4 : // 4-node tetrahedron
708 break;
709 case 5 : // 8-node hexahedron
711 break;
712 case 6 : // 6-node prism
714 break;
715 case 7 : // 5-node pyramid
717 break;
718 case 9 : // 6-node triangle
720 break;
721 case 11 : // 10-node tetrahedron
723 break;
724 }
725
726 } else {
727 // it must be a boundary segment then
728 if (insert_boundary_segments) {
729
730 switch (elm_type)
731 {
732 case 1 : // 2-node line
733 factory.insertBoundarySegment(vertices);
734 break;
735
736 case 2 : // 3-node triangle
737 factory.insertBoundarySegment(vertices);
738 break;
739
740 case 3 : // 4-node quadrilateral
741 factory.insertBoundarySegment(vertices);
742 break;
743
744 case 15 : // 1-node point
745 factory.insertBoundarySegment(vertices);
746 break;
747
748 case 8 : { // 3-node line
749 std::array<FieldVector<double,dimWorld>, 3> v;
750 for (int i=0; i<dimWorld; i++) {
751 v[0][i] = nodes[elementDofs[0]][i];
752 v[1][i] = nodes[elementDofs[2]][i]; // yes, the renumbering is intended!
753 v[2][i] = nodes[elementDofs[1]][i];
754 }
755 BoundarySegment<dim,dimWorld>* newBoundarySegment
756 = (BoundarySegment<dim,dimWorld>*) new GmshReaderQuadraticBoundarySegment< 2, dimWorld >(v[0], v[1], v[2]);
757 factory.insertBoundarySegment(vertices,
758 std::shared_ptr<BoundarySegment<dim,dimWorld> >(newBoundarySegment));
759 break;
760 }
761 case 9 : { // 6-node triangle
762 boundarysegment_insert(nodes, elementDofs, vertices);
763 break;
764 }
765 default: {
766 DUNE_THROW(Dune::IOError, "GmshReader does not support using element-type " << elm_type << " for boundary segments");
767 break;
768 }
769
770 }
771
772 }
773 }
774
775 // count elements and boundary elements
776 if (elementDim[elm_type] == dim) {
777 element_index_to_physical_entity[element_count] = physical_entity;
778 element_count++;
779 } else {
780 boundary_id_to_physical_entity[boundary_element_count] = physical_entity;
781 boundary_element_count++;
782 }
783
784 }
785
786 };
787
788 namespace Gmsh {
794 enum class ReaderOptions
795 {
796 verbose = 1,
797 insertBoundarySegments = 2,
798 readElementData = 4,
799 readBoundaryData = 8
800 };
801
803 constexpr ReaderOptions operator | (ReaderOptions a, ReaderOptions b)
804 {
805 return static_cast<ReaderOptions>(
806 static_cast<int>(a) | static_cast<int>(b)
807 );
808 }
809
811 constexpr bool operator & (ReaderOptions a, ReaderOptions b)
812 {
813 return static_cast<int>(a) & static_cast<int>(b);
814 }
815
816 } // end namespace Gmsh
817
842 template<typename GridType>
844 {
846
865 static void doRead(Dune::GridFactory<GridType> &factory,
866 const std::string &fileName,
867 std::vector<int>& boundarySegmentToPhysicalEntity,
868 std::vector<int>& elementToPhysicalEntity,
869 bool verbose, bool insertBoundarySegments)
870 {
871 // register boundary segment to boundary segment factory for possible load balancing
872 // this needs to be done on all cores since the type might not be known otherwise
873 GmshReaderQuadraticBoundarySegment< Grid::dimension, Grid::dimensionworld >::registerFactory();
874
875#ifndef NDEBUG
876 // check that this method is called on all cores
877 factory.comm().barrier();
878#endif
879
880 // create parse object and read grid on process 0
881 if (factory.comm().rank() == 0)
882 {
883 GmshReaderParser<Grid> parser(factory,verbose,insertBoundarySegments);
884 parser.read(fileName);
885
886 boundarySegmentToPhysicalEntity = std::move(parser.boundaryIdMap());
887 elementToPhysicalEntity = std::move(parser.elementIndexMap());
888 }
889 else
890 {
891 boundarySegmentToPhysicalEntity = {};
892 elementToPhysicalEntity = {};
893 }
894 }
895
897
916 template<class T>
917 static T &discarded(T &&value) { return static_cast<T&>(value); }
918
919 struct DataArg {
920 std::vector<int> *data_ = nullptr;
921 DataArg(std::vector<int> &data) : data_(&data) {}
922 DataArg(const decltype(std::ignore)&) {}
923 DataArg() = default;
924 };
925
926 struct DataFlagArg : DataArg {
927 bool flag_ = false;
928 using DataArg::DataArg;
929 DataFlagArg(bool flag) : flag_(flag) {}
930 };
931
932 public:
933 typedef GridType Grid;
934
937 static std::unique_ptr<Grid> read (const std::string& fileName, bool verbose = true, bool insertBoundarySegments=true)
938 {
939 // make a grid factory
941
942 read(factory, fileName, verbose, insertBoundarySegments);
943
944 return factory.createGrid();
945 }
946
966 static std::unique_ptr<Grid> read (const std::string& fileName,
967 std::vector<int>& boundarySegmentToPhysicalEntity,
968 std::vector<int>& elementToPhysicalEntity,
969 bool verbose = true, bool insertBoundarySegments=true)
970 {
971 // make a grid factory
973
974 doRead(
975 factory, fileName, boundarySegmentToPhysicalEntity,
976 elementToPhysicalEntity, verbose, insertBoundarySegments
977 );
978
979 return factory.createGrid();
980 }
981
983 static void read (Dune::GridFactory<Grid>& factory, const std::string& fileName,
984 bool verbose = true, bool insertBoundarySegments=true)
985 {
986 doRead(
987 factory, fileName, discarded(std::vector<int>{}),
988 discarded(std::vector<int>{}), verbose, insertBoundarySegments
989 );
990 }
991
993
1016 static void read (Dune::GridFactory<Grid> &factory,
1017 const std::string &fileName,
1018 DataFlagArg boundarySegmentData,
1019 DataArg elementData,
1020 bool verbose=true)
1021 {
1022 doRead(
1023 factory, fileName,
1024 boundarySegmentData.data_
1025 ? *boundarySegmentData.data_ : discarded(std::vector<int>{}),
1026 elementData.data_
1027 ? *elementData.data_ : discarded(std::vector<int>{}),
1028 verbose,
1029 boundarySegmentData.flag_ || boundarySegmentData.data_
1030 );
1031 }
1032
1053 static void read (Dune::GridFactory<Grid>& factory,
1054 const std::string& fileName,
1055 std::vector<int>& boundarySegmentToPhysicalEntity,
1056 std::vector<int>& elementToPhysicalEntity,
1057 bool verbose, bool insertBoundarySegments)
1058 {
1059 doRead(
1060 factory, fileName, boundarySegmentToPhysicalEntity,
1061 elementToPhysicalEntity, verbose, insertBoundarySegments
1062 );
1063 }
1064
1066 //\{
1067
1069
1070 static constexpr Opts defaultOpts =
1071 Opts::verbose | Opts::insertBoundarySegments | Opts::readElementData | Opts::readBoundaryData;
1072
1074
1097 GmshReader(const std::string& fileName,
1098 Gmsh::ReaderOptions options = defaultOpts)
1099 {
1100 gridFactory_ = std::make_unique<Dune::GridFactory<Grid>>();
1101 readGridFile(fileName, *gridFactory_, options);
1102 }
1103
1112 GmshReader(const std::string& fileName, GridFactory<Grid>& factory,
1113 Gmsh::ReaderOptions options = defaultOpts)
1114 {
1115 readGridFile(fileName, factory, options);
1116 }
1117
1119 const std::vector<int>& elementData () const
1120 {
1121 checkElementData();
1122 return elementIndexToGmshPhysicalEntity_;
1123 }
1124
1126 const std::vector<int>& boundaryData () const
1127 {
1128 checkBoundaryData();
1129 return boundarySegmentIndexToGmshPhysicalEntity_;
1130 }
1131
1136 bool hasElementData () const
1137 { return hasElementData_ && !extractedElementData_; }
1138
1143 bool hasBoundaryData () const
1144 { return hasBoundaryData_ && !extractedBoundaryData_; }
1145
1147 std::vector<int> extractElementData ()
1148 {
1149 checkElementData();
1150 extractedElementData_ = true;
1151 return std::move(elementIndexToGmshPhysicalEntity_);
1152 }
1153
1155 std::vector<int> extractBoundaryData ()
1156 {
1157 checkBoundaryData();
1158 extractedBoundaryData_ = true;
1159 return std::move(boundarySegmentIndexToGmshPhysicalEntity_);
1160 }
1161
1163 std::unique_ptr<Grid> createGrid ()
1164 {
1165 if (!gridFactory_)
1167 "This GmshReader has been constructed with a Dune::GridFactory. "
1168 << "This grid factory has been filled with all information to create a grid. "
1169 << "Please use this factory to create the grid by calling factory.createGrid(). "
1170 << "Alternatively use the constructor without passing the factory in combination with this member function."
1171 );
1172
1173 return gridFactory_->createGrid();
1174 }
1175
1176 //\}
1177
1178 private:
1179 void checkElementData () const
1180 {
1181 if (!hasElementData_)
1183 "This GmshReader has been constructed without the option 'readElementData'. "
1184 << "Please enable reading element data by passing the option 'Gmsh::ReaderOpts::readElementData' "
1185 << "to the constructor of this class."
1186 );
1187
1188 if (extractedElementData_)
1190 "The element data has already been extracted from this GmshReader "
1191 << "via a function call to reader.extractElementData(). Use the extracted data or "
1192 << "read the grid data from file again by constructing a new reader."
1193 );
1194 }
1195
1196 void checkBoundaryData () const
1197 {
1198 if (!hasBoundaryData_)
1200 "This GmshReader has been constructed without the option 'readBoundaryData'. "
1201 << "Please enable reading boundary data by passing the option 'Gmsh::ReaderOpts::readBoundaryData' "
1202 << "to the constructor of this class."
1203 );
1204
1205 if (extractedBoundaryData_)
1207 "The boundary data has already been extracted from this GmshReader "
1208 << "via a function call to reader.extractBoundaryData(). Use the extracted data or "
1209 << "read the grid data from file again by constructing a new reader."
1210 );
1211 }
1212
1213 void readGridFile (const std::string& fileName, GridFactory<Grid>& factory, Gmsh::ReaderOptions options)
1214 {
1215 const bool verbose = options & Opts::verbose;
1216 const bool insertBoundarySegments = options & Opts::insertBoundarySegments;
1217 const bool readBoundaryData = options & Opts::readBoundaryData;
1218 const bool readElementData = options & Opts::readElementData;
1219
1220 doRead(
1221 factory, fileName, boundarySegmentIndexToGmshPhysicalEntity_,
1222 elementIndexToGmshPhysicalEntity_, verbose,
1223 readBoundaryData || insertBoundarySegments
1224 );
1225
1226 // clear unwanted data
1227 if (!readBoundaryData)
1228 boundarySegmentIndexToGmshPhysicalEntity_ = std::vector<int>{};
1229 if (!readElementData)
1230 elementIndexToGmshPhysicalEntity_ = std::vector<int>{};
1231
1232 hasElementData_ = readElementData;
1233 hasBoundaryData_ = readBoundaryData;
1234 }
1235
1236 std::unique_ptr<Dune::GridFactory<Grid>> gridFactory_;
1237
1238 std::vector<int> elementIndexToGmshPhysicalEntity_;
1239 std::vector<int> boundarySegmentIndexToGmshPhysicalEntity_;
1240
1241 bool hasElementData_;
1242 bool hasBoundaryData_;
1243
1244 // for better error messages, we keep track of these separately
1245 bool extractedElementData_ = false;
1246 bool extractedBoundaryData_ = false;
1247 };
1248
1251} // namespace Dune
1252
1253#endif
Base class for grid boundary segments of arbitrary geometry.
int rank() const
Return rank, is between 0 and size()-1.
Definition: communication.hh:114
int barrier() const
Wait until all processes have arrived at this point in the program.
Definition: communication.hh:267
constexpr FieldTraits< value_type >::real_type two_norm() const
two norm sqrt(sum over squared values of entries)
Definition: densevector.hh:642
constexpr derived_type & axpy(const field_type &a, const DenseVector< Other > &x)
vector space axpy operation ( *this += a x )
Definition: densevector.hh:576
vector space out of a tensor product of fields.
Definition: fvector.hh:97
dimension independent parts for GmshReaderParser
Definition: gmshreader.hh:306
std::vector< std::string > & physicalEntityNames()
Returns the names of the gmsh physical entities (0-based index)
Definition: gmshreader.hh:377
void pass1HandleElement(FILE *file, const int elm_type, std::map< int, unsigned int > &renumber, const std::vector< GlobalVector > &nodes)
Process one element during the first pass through the list of all elements.
Definition: gmshreader.hh:549
std::vector< int > & elementIndexMap()
Returns a map for the gmsh physical entity id (1-based index) for each entity of codim 0.
Definition: gmshreader.hh:371
virtual void pass2HandleElement(FILE *file, const int elm_type, std::map< int, unsigned int > &renumber, const std::vector< GlobalVector > &nodes, const int physical_entity)
Process one element during the second pass through the list of all elements.
Definition: gmshreader.hh:637
Read Gmsh mesh file.
Definition: gmshreader.hh:844
static std::unique_ptr< Grid > read(const std::string &fileName, std::vector< int > &boundarySegmentToPhysicalEntity, std::vector< int > &elementToPhysicalEntity, bool verbose=true, bool insertBoundarySegments=true)
Read Gmsh file, possibly with data.
Definition: gmshreader.hh:966
const std::vector< int > & elementData() const
Access element data (maps element index to Gmsh physical entity)
Definition: gmshreader.hh:1119
static void read(Dune::GridFactory< Grid > &factory, const std::string &fileName, DataFlagArg boundarySegmentData, DataArg elementData, bool verbose=true)
read Gmsh file, possibly with data
Definition: gmshreader.hh:1016
static std::unique_ptr< Grid > read(const std::string &fileName, bool verbose=true, bool insertBoundarySegments=true)
Definition: gmshreader.hh:937
static void read(Dune::GridFactory< Grid > &factory, const std::string &fileName, bool verbose=true, bool insertBoundarySegments=true)
Definition: gmshreader.hh:983
std::unique_ptr< Grid > createGrid()
Create the grid.
Definition: gmshreader.hh:1163
std::vector< int > extractBoundaryData()
Erase boundary data from reader and return the data.
Definition: gmshreader.hh:1155
static void read(Dune::GridFactory< Grid > &factory, const std::string &fileName, std::vector< int > &boundarySegmentToPhysicalEntity, std::vector< int > &elementToPhysicalEntity, bool verbose, bool insertBoundarySegments)
Read Gmsh file, possibly with data.
Definition: gmshreader.hh:1053
bool hasElementData() const
If element data is available.
Definition: gmshreader.hh:1136
bool hasBoundaryData() const
If boundary data is available.
Definition: gmshreader.hh:1143
GmshReader(const std::string &fileName, GridFactory< Grid > &factory, Gmsh::ReaderOptions options=defaultOpts)
Construct a Gmsh reader object from a file name and a grid factory.
Definition: gmshreader.hh:1112
GmshReader(const std::string &fileName, Gmsh::ReaderOptions options=defaultOpts)
Construct a Gmsh reader object (alternatively use one of the static member functions)
Definition: gmshreader.hh:1097
std::vector< int > extractElementData()
Erase element data from reader and return the data.
Definition: gmshreader.hh:1147
const std::vector< int > & boundaryData() const
Access boundary data (maps boundary segment index to Gmsh physical entity)
Definition: gmshreader.hh:1126
Communication comm() const
Return the Communication used by the grid factory.
Definition: gridfactory.hh:258
Provide a generic factory class for unstructured grids.
Definition: gridfactory.hh:275
virtual void insertElement(const GeometryType &type, const std::vector< unsigned int > &vertices)
Insert an element into the coarse grid.
Definition: gridfactory.hh:307
virtual void insertVertex(const FieldVector< ctype, dimworld > &pos)
Insert a vertex into the coarse grid.
Definition: gridfactory.hh:296
virtual void insertBoundarySegment(const std::vector< unsigned int > &vertices)
insert a boundary segment
Definition: gridfactory.hh:325
virtual std::unique_ptr< GridType > createGrid()
Finalize grid creation and hand over the grid.
Definition: gridfactory.hh:333
Default exception class for I/O errors.
Definition: exceptions.hh:325
Default exception if a function was called while the object is not in a valid state for that function...
Definition: exceptions.hh:375
Provide a generic factory class for unstructured grids.
A few common exception classes.
int renumber(const Dune::GeometryType &t, int i)
renumber VTK <-> Dune
Definition: common.hh:186
Implements a vector constructed from a given type representing a field and a compile-time given size.
#define DUNE_THROW(E,...)
Definition: exceptions.hh:314
constexpr GeometryType line
GeometryType representing a line.
Definition: type.hh:498
constexpr GeometryType prism
GeometryType representing a 3D prism.
Definition: type.hh:528
constexpr GeometryType triangle
GeometryType representing a triangle.
Definition: type.hh:504
constexpr GeometryType quadrilateral
GeometryType representing a quadrilateral (a square).
Definition: type.hh:510
constexpr GeometryType hexahedron
GeometryType representing a hexahedron.
Definition: type.hh:534
constexpr GeometryType pyramid
GeometryType representing a 3D pyramid.
Definition: type.hh:522
constexpr GeometryType tetrahedron
GeometryType representing a tetrahedron.
Definition: type.hh:516
ReaderOptions
Option for the Gmsh mesh file reader.
Definition: gmshreader.hh:795
static std::string formatString(const std::string &s, const T &... args)
Format values according to printf format string.
Definition: stringutility.hh:73
Dune namespace.
Definition: alignedallocator.hh:13
Base class for classes implementing geometries of boundary segments.
Definition: boundarysegment.hh:94
Options for read operation.
Definition: gmshreader.hh:43
GeometryOrder
Definition: gmshreader.hh:44
@ firstOrder
edges are straight lines.
Definition: gmshreader.hh:46
A unique label for each type of element that can occur in a grid.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Oct 20, 22:40, 2025)