10#include "gmsh_file_v2.h"
12#include <boost/fusion/include/adapt_struct.hpp>
13#include <boost/fusion/include/adapt_struct_named.hpp>
14#include <boost/fusion/include/boost_array.hpp>
15#include <boost/fusion/include/io.hpp>
16#include <boost/fusion/include/std_pair.hpp>
17#include <boost/fusion/iterator.hpp>
18#include <boost/fusion/support/category_of.hpp>
19#include <boost/fusion/support/iterator_base.hpp>
20#include <boost/fusion/support/tag_of.hpp>
21#include <boost/fusion/support/tag_of_fwd.hpp>
22#include <boost/mpl/minus.hpp>
23#include <boost/phoenix/core.hpp>
24#include <boost/phoenix/function/adapt_function.hpp>
25#include <boost/phoenix/object.hpp>
26#include <boost/phoenix/operator.hpp>
27#include <boost/phoenix/stl.hpp>
28#include <boost/spirit/include/qi.hpp>
29#include <boost/spirit/include/qi_binary.hpp>
31#include "eigen_fusion_adapter.h"
82 stream <<
"PYRAMID14";
97 stream <<
"PYRAMID13";
112 stream <<
"TRIA15_5";
148 << (mf.
IsBinary ?
"(Binary)" :
"(Text)")
149 <<
", size of double = " << mf.
DoubleSize << std::endl;
150 stream <<
"======================================================="
152 stream <<
"PHYSICAL ENTITIES (Dimension, Number, Name):" << std::endl;
154 stream <<
" " << pe.Dimension <<
"\t , " << pe.Number <<
"\t , " << pe.Name
157 stream <<
"NODES (Number, coords)" << std::endl;
158 for (
const auto& n : mf.
Nodes) {
159 stream <<
" " << n.first <<
"\t , " << n.second.transpose() << std::endl;
161 stream <<
"ELEMENTS (Number, Type, PhysicalEntity Nr, ElementaryEntityNr, "
162 "Mesh partitions to which it belongs, Node numbers in it)"
165 stream <<
" " << e.Number <<
"\t " << e.Type <<
'\t' << e.PhysicalEntityNr
166 <<
"\t" << e.ElementaryEntityNr <<
"\t";
167 for (
auto p : e.MeshPartitions) {
171 for (
auto n : e.NodeNumbers) {
177 stream <<
"PERIODIC ENTITIES:" << std::endl;
178 for (
const auto& pe : mf.
Periodic) {
179 std::cout <<
" dim=" << pe.Dimension
180 <<
", slaveNr=" << pe.ElementarySlaveNr
181 <<
", masterNr=" << pe.ElementaryMasterNr << std::endl;
182 for (
auto nm : pe.NodeMapping) {
183 std::cout <<
" " << nm.first <<
" <-> " << nm.second << std::endl;
259 LF_VERIFY_MSG(
false,
"unknown Gmsh element type");
309 false,
"Reference element not supported for GmshElement type " << et);
354 LF_VERIFY_MSG(
false,
"Unknown GmshElement Type.");
365 (
int, Dimension)(
int, Number)(std::string, Name));
367BOOST_FUSION_ADAPT_STRUCT(
370 Type)(
int, PhysicalEntityNr)(
int, ElementaryEntityNr)(
371 std::vector<int>, MeshPartitions)(std::vector<size_type>, NodeNumbers));
374using nodeMapping_t = std::pair<size_type, size_type>;
377 (
int, Dimension)(
int, ElementarySlaveNr)(
379 ElementaryMasterNr)(std::vector<nodeMapping_t>,
383using nodePair_t = std::pair<size_type, Eigen::Vector3d>;
388BOOST_FUSION_ADAPT_STRUCT_NAMED(
393 (std::vector<lf::io::GMshFileV2::PhysicalEntity>,
394 PhysicalEntities)(std::vector<nodePair_t>, Nodes)(
395 std::vector<lf::io::GMshFileV2::Element>,
396 Elements)(std::vector<lf::io::GMshFileV2::PeriodicEntity>, Periodic));
399namespace boost::spirit::traits {
408template <
typename Enum,
typename RawValue>
409struct assign_to_attribute_from_value<
411 typename std::enable_if<std::is_enum<Enum>::value &&
412 std::is_same<Enum, RawValue>::value ==
414 static void call(RawValue
const& raw, Enum& cat) {
415 cat =
static_cast<Enum
>(raw);
425namespace qi = boost::spirit::qi;
426namespace ascii = boost::spirit::ascii;
427namespace phoenix = boost::phoenix;
430struct gmshElementType : qi::symbols<char, unsigned> {
433 add(std::to_string(
static_cast<int>(et)),
static_cast<int>(et));
439BOOST_PHOENIX_ADAPT_FUNCTION(
int, numNodesAdapted,
NumNodes, 1);
442template <
class ITERATOR>
444 : qi::grammar<ITERATOR, boost::fusion::adapted::MshFileAdapted(),
447 qi::rule<ITERATOR, std::pair<size_type, Eigen::Vector3d>()> nodeRule,
448 qi::rule<ITERATOR, std::vector<GMshFileV2::Element>(),
449 qi::locals<size_type, int, int, int, size_type>>
451 : MshGrammarText::base_type(start_,
"Msh File"),
453 elementGroup_(elementGroup) {
454 using phoenix::push_back;
455 using phoenix::reserve;
466 using qi::labels::_1;
467 using qi::labels::_2;
468 using qi::labels::_3;
469 using qi::labels::_4;
470 using qi::labels::_a;
473 quotedString_ %= lexeme[
'"' >> +(char_ -
'"') >>
'"'];
474 quotedString_.name(
"string");
475 startComment_ %= !lit(
"$PhysicalNames") >> !lit(
"$Nodes") >>
476 !lit(
"$Elements") >> !lit(
"$Periodic") >>
477 (lit(
'$') >> (+(char_ - qi::eol)));
478 startComment_.name(
"Start of Comment");
480 startComment_[_a = qi::_1] > *(char_ -
'$') >>
"$End" >> qi::string(_a);
481 comment_.name(
"comment");
482 qi::on_error<qi::fail>(comment_,
483 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
486 physicalEntity_ %= int_ > int_ > quotedString_;
487 physicalEntity_.name(
"Physical Entity Entry");
488 qi::on_error<qi::fail>(physicalEntity_,
489 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
490 physicalEntityGroup_ %=
"$PhysicalNames" >
491 omit[int_[reserve(_val, qi::_1), _a = qi::_1]] >
492 repeat(_a)[physicalEntity_] >
"$EndPhysicalNames";
493 physicalEntityGroup_.name(
"$Physical Entity Section");
494 qi::on_error<qi::fail>(physicalEntityGroup_,
495 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
498 nodeGroup_ %=
"$Nodes" > qi::eol >
499 omit[qi::uint_[reserve(_val, qi::_1), _a = qi::_1]] >
500 qi::eol > repeat(_a)[node_] > -qi::eol >
"$EndNodes";
501 nodeGroup_.name(
"$Node Section");
502 qi::on_error<qi::fail>(node_,
503 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
504 qi::on_error<qi::fail>(nodeGroup_,
505 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
508 qi::on_error<qi::fail>(elementGroup_,
509 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
512 periodicEntityNodeMapping_ =
513 omit[qi::uint_[reserve(_val, qi::_1), _a = qi::_1]] >
514 repeat(_a)[qi::uint_ > qi::uint_];
515 periodicEntityNodeMapping_.name(
"slave-master node mapping");
516 qi::on_error<qi::fail>(periodicEntityNodeMapping_,
517 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
519 int_ > int_ > int_ > periodicEntityNodeMapping_;
520 periodicEntity_.name(
"periodic entity");
521 qi::on_error<qi::fail>(periodicEntity_,
522 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
523 periodicEntityGroup_ =
"$Periodic" >
524 omit[qi::uint_[reserve(_val, qi::_1), _a = qi::_1]] >
525 repeat(_a)[periodicEntity_] >
"$EndPeriodic";
526 periodicEntityGroup_.name(
"periodic entity section");
527 qi::on_error<qi::fail>(periodicEntityGroup_,
528 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
531 start_ %= *comment_ >> -(physicalEntityGroup_ >> *comment_) >> nodeGroup_ >>
532 *comment_ >> elementGroup_ >> *comment_ >>
533 -(periodicEntityGroup_ >> *comment_);
534 start_.name(
"beginning of file");
535 qi::on_error<qi::fail>(start_,
536 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
540 qi::rule<ITERATOR, std::string(), ascii::space_type> quotedString_;
541 qi::rule<ITERATOR, std::string()> startComment_;
542 qi::rule<ITERATOR, qi::locals<std::string>, ascii::space_type> comment_;
544 qi::rule<ITERATOR, GMshFileV2::PhysicalEntity(), ascii::space_type>
546 qi::rule<ITERATOR, std::vector<GMshFileV2::PhysicalEntity>(),
547 qi::locals<size_type>, ascii::space_type>
548 physicalEntityGroup_;
550 qi::rule<ITERATOR, std::pair<size_type, Eigen::Vector3d>()> node_;
551 qi::rule<ITERATOR, std::vector<std::pair<size_type, Eigen::Vector3d>>(),
552 qi::locals<size_type>>
557 qi::rule<ITERATOR, std::vector<GMshFileV2::Element>(),
558 qi::locals<size_type, int, int, int, size_type>>
561 qi::rule<ITERATOR, std::vector<std::pair<size_type, size_type>>(),
562 qi::locals<size_type>, ascii::space_type>
563 periodicEntityNodeMapping_;
564 qi::rule<ITERATOR, GMshFileV2::PeriodicEntity(), ascii::space_type>
566 qi::rule<ITERATOR, std::vector<GMshFileV2::PeriodicEntity>(),
567 qi::locals<size_type>, ascii::space_type>
568 periodicEntityGroup_;
570 qi::rule<ITERATOR, boost::fusion::adapted::MshFileAdapted(),
574 struct ErrorHandler {
575 template <
class,
class,
class,
class>
580 template <
class FIRST,
class LAST,
class ERROR_POS,
class WHAT>
581 void operator()(FIRST first, LAST last, ERROR_POS ,
583 std::string input(first, last);
584 if (input.length() > 40) {
585 input = input.substr(0, 40);
587 std::cout <<
"Error in MshFile! Expecting " << what <<
" here: \""
588 << input <<
"\"" << std::endl;
591 phoenix::function<ErrorHandler> errorHandler_;
597 ElementType::EDGE2, ElementType::TRIA3, ElementType::QUAD4,
598 ElementType::TET4, ElementType::HEX8, ElementType::PRISM6,
599 ElementType::PYRAMID5, ElementType::EDGE3, ElementType::TRIA6,
600 ElementType::QUAD9, ElementType::TET10, ElementType::HEX27,
601 ElementType::PRISM18, ElementType::PYRAMID14, ElementType::POINT,
602 ElementType::QUAD8, ElementType::HEX20, ElementType::PRISM15,
603 ElementType::PYRAMID13, ElementType::TRIA9, ElementType::TRIA10,
604 ElementType::TRIA12, ElementType::TRIA15, ElementType::TRIA15_5,
605 ElementType::TRIA21, ElementType::EDGE4, ElementType::EDGE5,
606 ElementType::EDGE6, ElementType::TET20, ElementType::TET35,
607 ElementType::TET56, ElementType::HEX64, ElementType::HEX125};
610 std::string::const_iterator end,
611 const std::string& version,
bool is_binary,
612 int size_t_size,
int one,
613 const std::string& filename) {
614 LF_VERIFY_MSG(version ==
"2.2",
615 "Version " << version <<
" not supported by readGmshFileV2");
616 LF_ASSERT_MSG(size_t_size == 8,
"Size of std::size_t must be 8.");
633 using iterator_t = std::string::const_iterator;
634 qi::rule<iterator_t, Eigen::Vector3d> vec3;
635 qi::rule<iterator_t, std::pair<size_type, Eigen::Vector3d>()> node;
639 qi::rule<iterator_t, std::vector<GMshFileV2::Element>(),
640 qi::locals<size_type, int, int, int, size_type>>
643 using phoenix::reserve;
646 using qi::labels::_a;
647 using qi::labels::_b;
648 using qi::labels::_c;
649 using qi::labels::_d;
650 using qi::labels::_e;
651 using qi::labels::_r1;
652 using qi::labels::_r2;
653 using qi::labels::_r3;
654 using qi::labels::_val;
658 vec3 = qi::double_ >>
' ' >> qi::double_ >>
' ' >> qi::double_;
659 node = qi::uint_ >>
' ' >> vec3 >> qi::eol;
660 elementText %= qi::int_ >
' ' > qi::int_ >
' ' >
661 qi::omit[qi::int_[qi::_a = qi::_1]] >
' ' > qi::int_ >
' ' >
663 ((qi::eps(_a > 2) >> omit[qi::int_] >>
' ') || qi::eps) >
664 qi::repeat(qi::_a - 3)[qi::int_ >>
' '] > (qi::uint_ %
' ') >
665 *(qi::blank) > qi::eol;
666 elementGroup %=
"$Elements" > qi::eol >
667 qi::omit[qi::uint_[phoenix::reserve(qi::_val, qi::_1),
668 qi::_a = qi::_1]] > qi::eol >
669 qi::repeat(qi::_a)[elementText] >
"$EndElements";
670 }
else if (is_binary && one == 1) {
674 qi::little_bin_double >> qi::little_bin_double >> qi::little_bin_double;
675 node %= qi::no_skip[qi::little_dword >> vec3];
676 elementBin %= qi::little_dword >> qi::attr(_r1) >> qi::little_dword >>
678 ((qi::eps(_r2 > 2) >> omit[qi::little_dword]) || qi::eps) >>
679 qi::repeat(_r2 - 3)[qi::little_dword] >>
680 qi::repeat(_r3)[qi::little_dword];
682 "$Elements" >> qi::eol >> qi::eps[_e = 0] >>
683 omit[qi::uint_[reserve(_val, qi::_1), _a = qi::_1]] >>
686 omit[*((qi::eps(_e < _a) >> qi::little_dword[_b = qi::_1] >>
687 qi::little_dword[_c = qi::_1] >>
688 qi::little_dword[_d = qi::_1]
689 >> repeat(_c)[elementBin(
690 phoenix::static_cast_<GMshFileV2::ElementType>(_b), _d,
692 phoenix::static_cast_<GMshFileV2::ElementType>(
693 _b)))[phoenix::push_back(_val, qi::_1)]]) >>
695 >> qi::eol >>
"$EndElements";
699 vec3 %= qi::big_bin_double >> qi::big_bin_double >> qi::big_bin_double;
700 node %= qi::no_skip[qi::big_dword >> vec3];
702 qi::big_dword >> qi::attr(_r1) >> qi::big_dword >> qi::big_dword >>
703 ((qi::eps(_r2 > 2) >> omit[qi::big_dword]) || qi::eps) >>
704 qi::repeat(_r2 - 3)[qi::big_dword] >> qi::repeat(_r3)[qi::big_dword];
706 "$Elements" >> qi::eol >> qi::eps[_e = 0] >>
707 omit[qi::uint_[reserve(_val, qi::_1), _a = qi::_1]] >>
710 omit[*((qi::eps(_e < _a) >> qi::big_dword[_b = qi::_1] >>
711 qi::big_dword[_c = qi::_1] >>
712 qi::big_dword[_d = qi::_1]
713 >> repeat(_c)[elementBin(
714 phoenix::static_cast_<GMshFileV2::ElementType>(_b), _d,
716 phoenix::static_cast_<GMshFileV2::ElementType>(
717 _b)))[phoenix::push_back(_val, qi::_1)]]) >>
719 >> qi::eol >>
"$EndElements";
725 elementText.name(
"element");
726 elementBin.name(
"element");
727 elementGroup.name(
"ElementSection");
730 MshGrammarText<iterator_t> mshGrammar(node, elementGroup);
731 bool r = qi::phrase_parse(begin, end, mshGrammar, ascii::space, result);
737 LF_VERIFY_MSG(r,
"Could not parse file " << filename);
738 LF_VERIFY_MSG(begin == end,
"Could not parse all of file " << filename);
Represents a reference element with all its properties.
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
static constexpr RefEl kTria()
Returns the reference triangle.
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
lf::base::size_type size_type
Mesh input (from file) and output (in various formats) facilities.
GMshFileV2 readGmshFileV2(std::string::const_iterator begin, std::string::const_iterator end, const std::string &version, bool is_binary, int size_t_size, int one, const std::string &filename)
Read a *.msh file from disk and copy it's contents into the MshFile Datastructure.
int DimOf(GMshFileV2::ElementType et)
Dimension of the GmshElement type.
base::RefEl RefElOf(GMshFileV2::ElementType et)
Reference element type of a GmshElementType.
std::ostream & operator<<(std::ostream &stream, GMshFileV2::ElementType et)
Output the element type onto the console:
size_type NumNodes(GMshFileV2::ElementType et)
Number of nodes that this element type has.
Represents a mesh volume/surface/line/point.
Describes how 2 elementary entities are identified with each to represent periodic boundaries.
Represents a physical entity as defined in gmsh. In GMSH a Physical entity is created through one of ...
A representation of a .msh file (V2) in a c++ data structure.
std::string VersionNumber
The version of GMSH of the msh file, equals usually 2.2.
int DoubleSize
how many bytes is a double?
std::vector< PhysicalEntity > PhysicalEntities
A list of all Physical entities that have a name.
std::vector< Element > Elements
A list of all Elements (Points,Lines,Surfaces or Volumes) present in the *.msh file.
ElementType
All possible element types (see GMSH documentation)
std::vector< std::pair< size_type, Eigen::Vector3d > > Nodes
The nodes that make up this mesh.
bool IsBinary
Is it a binary file?
std::vector< PeriodicEntity > Periodic
static const std::vector< ElementType > AllElementTypes
Contains a list of all element types that are possible.