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 <<
'\n';
150 stream <<
"=======================================================" <<
'\n';
151 stream <<
"PHYSICAL ENTITIES (Dimension, Number, Name):" <<
'\n';
153 stream <<
" " << pe.Dimension <<
"\t , " << pe.Number <<
"\t , " << pe.Name
156 stream <<
"NODES (Number, coords)" <<
'\n';
157 for (
const auto& n : mf.
Nodes) {
158 stream <<
" " << n.first <<
"\t , " << n.second.transpose() <<
'\n';
160 stream <<
"ELEMENTS (Number, Type, PhysicalEntity Nr, ElementaryEntityNr, "
161 "Mesh partitions to which it belongs, Node numbers in it)"
164 stream <<
" " << e.Number <<
"\t " << e.Type <<
'\t' << e.PhysicalEntityNr
165 <<
"\t" << e.ElementaryEntityNr <<
"\t";
166 for (
auto p : e.MeshPartitions) {
170 for (
auto n : e.NodeNumbers) {
176 stream <<
"PERIODIC ENTITIES:" <<
'\n';
177 for (
const auto& pe : mf.
Periodic) {
178 std::cout <<
" dim=" << pe.Dimension
179 <<
", slaveNr=" << pe.ElementarySlaveNr
180 <<
", masterNr=" << pe.ElementaryMasterNr <<
'\n';
181 for (
auto nm : pe.NodeMapping) {
182 std::cout <<
" " << nm.first <<
" <-> " << nm.second <<
'\n';
258 LF_VERIFY_MSG(
false,
"unknown Gmsh element type");
308 false,
"Reference element not supported for GmshElement type " << et);
353 LF_VERIFY_MSG(
false,
"Unknown GmshElement Type.");
364 (
int, Dimension)(
int, Number)(std::string, Name));
366BOOST_FUSION_ADAPT_STRUCT(
369 Type)(
int, PhysicalEntityNr)(
int, ElementaryEntityNr)(
370 std::vector<int>, MeshPartitions)(std::vector<size_type>, NodeNumbers));
373using nodeMapping_t = std::pair<size_type, size_type>;
376 (
int, Dimension)(
int, ElementarySlaveNr)(
378 ElementaryMasterNr)(std::vector<nodeMapping_t>,
382using nodePair_t = std::pair<size_type, Eigen::Vector3d>;
387BOOST_FUSION_ADAPT_STRUCT_NAMED(
392 (std::vector<lf::io::GMshFileV2::PhysicalEntity>,
393 PhysicalEntities)(std::vector<nodePair_t>, Nodes)(
394 std::vector<lf::io::GMshFileV2::Element>,
395 Elements)(std::vector<lf::io::GMshFileV2::PeriodicEntity>, Periodic));
398namespace boost::spirit::traits {
407template <
class Enum,
typename RawValue>
408 requires(std::is_enum_v<Enum> && !std::is_same_v<Enum, RawValue>)
409struct assign_to_attribute_from_value<Enum, RawValue> {
410 static void call(RawValue
const& raw, Enum& cat) {
411 cat =
static_cast<Enum
>(raw);
421namespace qi = boost::spirit::qi;
422namespace ascii = boost::spirit::ascii;
423namespace phoenix = boost::phoenix;
426struct gmshElementType : qi::symbols<char, unsigned> {
428 for (
const auto& et : GMshFileV2::AllElementTypes) {
429 add(std::to_string(
static_cast<int>(et)),
static_cast<int>(et));
435BOOST_PHOENIX_ADAPT_FUNCTION(
int, numNodesAdapted,
NumNodes, 1);
438template <
class ITERATOR>
440 : qi::grammar<ITERATOR, boost::fusion::adapted::MshFileAdapted(),
443 qi::rule<ITERATOR, std::pair<size_type, Eigen::Vector3d>()> nodeRule,
444 qi::rule<ITERATOR, std::vector<GMshFileV2::Element>(),
445 qi::locals<size_type, int, int, int, size_type>>
447 : MshGrammarText::base_type(start_,
"Msh File"),
449 elementGroup_(elementGroup) {
450 using phoenix::push_back;
451 using phoenix::reserve;
462 using qi::labels::_1;
463 using qi::labels::_2;
464 using qi::labels::_3;
465 using qi::labels::_4;
466 using qi::labels::_a;
469 quotedString_ %= lexeme[
'"' >> +(char_ -
'"') >>
'"'];
470 quotedString_.name(
"string");
471 startComment_ %= !lit(
"$PhysicalNames") >> !lit(
"$Nodes") >>
472 !lit(
"$Elements") >> !lit(
"$Periodic") >>
473 (lit(
'$') >> (+(char_ - qi::eol)));
474 startComment_.name(
"Start of Comment");
476 startComment_[_a = qi::_1] > *(char_ -
'$') >>
"$End" >> qi::string(_a);
477 comment_.name(
"comment");
478 qi::on_error<qi::fail>(comment_,
479 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
482 physicalEntity_ %= int_ > int_ > quotedString_;
483 physicalEntity_.name(
"Physical Entity Entry");
484 qi::on_error<qi::fail>(physicalEntity_,
485 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
486 physicalEntityGroup_ %=
"$PhysicalNames" >
487 omit[int_[(reserve(_val, qi::_1), _a = qi::_1)]] >
488 repeat(_a)[physicalEntity_] >
"$EndPhysicalNames";
489 physicalEntityGroup_.name(
"$Physical Entity Section");
490 qi::on_error<qi::fail>(physicalEntityGroup_,
491 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
494 nodeGroup_ %=
"$Nodes" > qi::eol >
495 omit[qi::uint_[(reserve(_val, qi::_1), _a = qi::_1)]] >
496 qi::eol > repeat(_a)[node_] > -qi::eol >
"$EndNodes";
497 nodeGroup_.name(
"$Node Section");
498 qi::on_error<qi::fail>(node_,
499 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
500 qi::on_error<qi::fail>(nodeGroup_,
501 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
504 qi::on_error<qi::fail>(elementGroup_,
505 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
508 periodicEntityNodeMapping_ =
509 omit[qi::uint_[(reserve(_val, qi::_1), _a = qi::_1)]] >
510 repeat(_a)[qi::uint_ > qi::uint_];
511 periodicEntityNodeMapping_.name(
"slave-master node mapping");
512 qi::on_error<qi::fail>(periodicEntityNodeMapping_,
513 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
515 int_ > int_ > int_ > periodicEntityNodeMapping_;
516 periodicEntity_.name(
"periodic entity");
517 qi::on_error<qi::fail>(periodicEntity_,
518 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
519 periodicEntityGroup_ =
520 "$Periodic" > omit[qi::uint_[(reserve(_val, qi::_1), _a = qi::_1)]] >
521 repeat(_a)[periodicEntity_] >
"$EndPeriodic";
522 periodicEntityGroup_.name(
"periodic entity section");
523 qi::on_error<qi::fail>(periodicEntityGroup_,
524 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
527 start_ %= *comment_ >> -(physicalEntityGroup_ >> *comment_) >> nodeGroup_ >>
528 *comment_ >> elementGroup_ >> *comment_ >>
529 -(periodicEntityGroup_ >> *comment_);
530 start_.name(
"beginning of file");
531 qi::on_error<qi::fail>(start_,
532 errorHandler_(qi::_1, qi::_2, qi::_3, qi::_4));
536 qi::rule<ITERATOR, std::string(), ascii::space_type> quotedString_;
537 qi::rule<ITERATOR, std::string()> startComment_;
538 qi::rule<ITERATOR, qi::locals<std::string>, ascii::space_type> comment_;
540 qi::rule<ITERATOR, GMshFileV2::PhysicalEntity(), ascii::space_type>
542 qi::rule<ITERATOR, std::vector<GMshFileV2::PhysicalEntity>(),
543 qi::locals<size_type>, ascii::space_type>
544 physicalEntityGroup_;
546 qi::rule<ITERATOR, std::pair<size_type, Eigen::Vector3d>()> node_;
547 qi::rule<ITERATOR, std::vector<std::pair<size_type, Eigen::Vector3d>>(),
548 qi::locals<size_type>>
553 qi::rule<ITERATOR, std::vector<GMshFileV2::Element>(),
554 qi::locals<size_type, int, int, int, size_type>>
557 qi::rule<ITERATOR, std::vector<std::pair<size_type, size_type>>(),
558 qi::locals<size_type>, ascii::space_type>
559 periodicEntityNodeMapping_;
560 qi::rule<ITERATOR, GMshFileV2::PeriodicEntity(), ascii::space_type>
562 qi::rule<ITERATOR, std::vector<GMshFileV2::PeriodicEntity>(),
563 qi::locals<size_type>, ascii::space_type>
564 periodicEntityGroup_;
566 qi::rule<ITERATOR, boost::fusion::adapted::MshFileAdapted(),
570 struct ErrorHandler {
571 template <
class,
class,
class,
class>
576 template <
class FIRST,
class LAST,
class ERROR_POS,
class WHAT>
577 void operator()(FIRST first, LAST last, ERROR_POS ,
579 std::string input(first, last);
580 if (input.length() > 40) {
581 input = input.substr(0, 40);
583 std::cout <<
"Error in MshFile! Expecting " << what <<
" here: \""
584 << input <<
"\"" << std::endl;
587 phoenix::function<ErrorHandler> errorHandler_;
593 ElementType::EDGE2, ElementType::TRIA3, ElementType::QUAD4,
594 ElementType::TET4, ElementType::HEX8, ElementType::PRISM6,
595 ElementType::PYRAMID5, ElementType::EDGE3, ElementType::TRIA6,
596 ElementType::QUAD9, ElementType::TET10, ElementType::HEX27,
597 ElementType::PRISM18, ElementType::PYRAMID14, ElementType::POINT,
598 ElementType::QUAD8, ElementType::HEX20, ElementType::PRISM15,
599 ElementType::PYRAMID13, ElementType::TRIA9, ElementType::TRIA10,
600 ElementType::TRIA12, ElementType::TRIA15, ElementType::TRIA15_5,
601 ElementType::TRIA21, ElementType::EDGE4, ElementType::EDGE5,
602 ElementType::EDGE6, ElementType::TET20, ElementType::TET35,
603 ElementType::TET56, ElementType::HEX64, ElementType::HEX125};
606 std::string::const_iterator end,
607 const std::string& version,
bool is_binary,
608 int size_t_size,
int one,
609 const std::string& filename) {
610 LF_VERIFY_MSG(version ==
"2.2",
611 "Version " << version <<
" not supported by readGmshFileV2");
612 LF_ASSERT_MSG(size_t_size == 8,
"Size of std::size_t must be 8.");
629 using iterator_t = std::string::const_iterator;
630 qi::rule<iterator_t, Eigen::Vector3d> vec3;
631 qi::rule<iterator_t, std::pair<size_type, Eigen::Vector3d>()> node;
635 qi::rule<iterator_t, std::vector<GMshFileV2::Element>(),
636 qi::locals<size_type, int, int, int, size_type>>
639 using phoenix::reserve;
642 using qi::labels::_a;
643 using qi::labels::_b;
644 using qi::labels::_c;
645 using qi::labels::_d;
646 using qi::labels::_e;
647 using qi::labels::_r1;
648 using qi::labels::_r2;
649 using qi::labels::_r3;
650 using qi::labels::_val;
654 vec3 = qi::double_ >>
' ' >> qi::double_ >>
' ' >> qi::double_;
655 node = qi::uint_ >>
' ' >> vec3 >> qi::eol;
656 elementText %= qi::int_ >
' ' > qi::int_ >
' ' >
657 qi::omit[qi::int_[qi::_a = qi::_1]] >
' ' > qi::int_ >
' ' >
659 ((qi::eps(_a > 2) >> omit[qi::int_] >>
' ') || qi::eps) >
660 qi::repeat(qi::_a - 3)[qi::int_ >>
' '] > (qi::uint_ %
' ') >
661 *(qi::blank) > qi::eol;
662 elementGroup %=
"$Elements" > qi::eol >
663 qi::omit[qi::uint_[(phoenix::reserve(qi::_val, qi::_1),
664 qi::_a = qi::_1)]] > qi::eol >
665 qi::repeat(qi::_a)[elementText] >
"$EndElements";
666 }
else if (is_binary && one == 1) {
670 qi::little_bin_double >> qi::little_bin_double >> qi::little_bin_double;
671 node %= qi::no_skip[qi::little_dword >> vec3];
672 elementBin %= qi::little_dword >> qi::attr(_r1) >> qi::little_dword >>
674 ((qi::eps(_r2 > 2) >> omit[qi::little_dword]) || qi::eps) >>
675 qi::repeat(_r2 - 3)[qi::little_dword] >>
676 qi::repeat(_r3)[qi::little_dword];
678 "$Elements" >> qi::eol >> qi::eps[_e = 0] >>
679 omit[qi::uint_[(reserve(_val, qi::_1), _a = qi::_1)]] >>
682 omit[*((qi::eps(_e < _a) >> qi::little_dword[_b = qi::_1] >>
683 qi::little_dword[_c = qi::_1] >>
684 qi::little_dword[_d = qi::_1]
685 >> repeat(_c)[elementBin(
686 phoenix::static_cast_<GMshFileV2::ElementType>(_b), _d,
688 phoenix::static_cast_<GMshFileV2::ElementType>(
689 _b)))[phoenix::push_back(_val, qi::_1)]]) >>
691 >> qi::eol >>
"$EndElements";
695 vec3 %= qi::big_bin_double >> qi::big_bin_double >> qi::big_bin_double;
696 node %= qi::no_skip[qi::big_dword >> vec3];
698 qi::big_dword >> qi::attr(_r1) >> qi::big_dword >> qi::big_dword >>
699 ((qi::eps(_r2 > 2) >> omit[qi::big_dword]) || qi::eps) >>
700 qi::repeat(_r2 - 3)[qi::big_dword] >> qi::repeat(_r3)[qi::big_dword];
702 "$Elements" >> qi::eol >> qi::eps[_e = 0] >>
703 omit[qi::uint_[(reserve(_val, qi::_1), _a = qi::_1)]] >>
706 omit[*((qi::eps(_e < _a) >> qi::big_dword[_b = qi::_1] >>
707 qi::big_dword[_c = qi::_1] >>
708 qi::big_dword[_d = qi::_1]
709 >> repeat(_c)[elementBin(
710 phoenix::static_cast_<GMshFileV2::ElementType>(_b), _d,
712 phoenix::static_cast_<GMshFileV2::ElementType>(
713 _b)))[phoenix::push_back(_val, qi::_1)]]) >>
715 >> qi::eol >>
"$EndElements";
721 elementText.name(
"element");
722 elementBin.name(
"element");
723 elementGroup.name(
"ElementSection");
726 const MshGrammarText<iterator_t> mshGrammar(node, elementGroup);
727 const bool r = qi::phrase_parse(begin, end, mshGrammar, ascii::space, result);
733 LF_VERIFY_MSG(r,
"Could not parse file " << filename);
734 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.