127 dim_mesh >= 2 && dim_mesh <= 3 && dim_world >= 2 && dim_world <= 3,
128 "GmshReader supports only 2D and 3D meshes.");
137 std::vector<bool> is_main_node(msh_file.
Nodes.size(),
false);
142 std::vector<std::vector<std::vector<size_type>>> mi2gi(dim_mesh + 1);
146 std::vector<size_type> num_entities(
mesh_factory_->DimMesh() + 1, 0);
148 for (
const auto& e : msh_file.
Elements) {
149 LF_ASSERT_MSG(
DimOf(e.Type) <= dim_mesh,
150 "mesh_factory->DimMesh() = "
152 <<
", but msh-file contains entities with dimension "
155 ++num_entities[
DimOf(e.Type)];
160 for (
unsigned int i = 0; i < ref_el.NumNodes(); ++i) {
161 auto node_number = e.NodeNumbers[i];
162 if (is_main_node.size() <= node_number) {
163 is_main_node.resize(node_number + 1);
165 is_main_node[node_number] =
true;
170 for (
dim_t c = 0; c <= dim_mesh; ++c) {
171 mi2gi[c].reserve(num_entities[dim_mesh - c]);
174 LF_ASSERT_MSG(num_entities[dim_mesh] > 0,
175 "MshFile contains no elements with dimension " << dim_mesh);
183 std::vector<size_type> gi2mi;
184 gi2mi.resize(is_main_node.size(), -1);
187 std::vector<size_type> gi2i;
188 gi2i.resize(is_main_node.size(), -1);
190 for (std::size_t i = 0; i < msh_file.
Nodes.size(); ++i) {
191 const auto& n = msh_file.
Nodes[i];
192 if (gi2i.size() <= n.first) {
193 gi2i.resize(n.first + 1, -1);
197 if (is_main_node.size() <= n.first || !is_main_node[n.first]) {
202 if (dim_world == 2) {
205 "In a 2D GmshMesh, the z-coordinate of every node must be zero");
216 std::size_t begin = 0;
217 for (std::size_t end = 0; end < msh_file.
Elements.size(); ++end) {
218 const auto& begin_element = msh_file.
Elements[begin];
219 const auto& end_element = msh_file.
Elements[end];
220 auto ref_el =
RefElOf(end_element.Type);
221 auto codim = dim_mesh - ref_el.Dimension();
222 if (begin_element.NodeNumbers == end_element.NodeNumbers && begin != end &&
223 begin_element.Type == end_element.Type) {
225 mi2gi[codim].back().push_back(end);
231 auto mesh_index = gi2mi[end_element.NodeNumbers[0]];
234 if (mesh_index != std::numeric_limits<unsigned int>::max()) {
237 if (mi2gi[dim_mesh].size() <= mesh_index) {
238 mi2gi[dim_mesh].resize(mesh_index + 1);
240 mi2gi[dim_mesh][mesh_index].push_back(end);
245 base::narrow<Eigen::Index>(end_element.NodeNumbers.size());
246 Eigen::MatrixXd node_coords(dim_world, num_nodes);
247 for (Eigen::Index i = 0; i < num_nodes; ++i) {
249 msh_file.
Nodes[gi2i[end_element.NodeNumbers[i]]].second;
250 if (dim_world == 2) {
251 node_coords.col(i) = node_coord.topRows(2);
253 node_coords.col(i) = node_coord;
256 std::unique_ptr<geometry::Geometry> geom;
258 switch (end_element.Type) {
261 geom = std::make_unique<geometry::SegmentO1>(node_coords);
265 geom = std::make_unique<geometry::SegmentO2>(node_coords);
269 geom = std::make_unique<geometry::TriaO1>(node_coords);
273 geom = std::make_unique<geometry::TriaO2>(node_coords);
277 geom = std::make_unique<geometry::QuadO1>(node_coords);
281 geom = std::make_unique<geometry::QuadO2>(node_coords);
285 geom = std::make_unique<geometry::QuadO2>(node_coords.leftCols(8));
288 LF_VERIFY_MSG(
false,
"Gmsh element type "
290 <<
" not (yet) supported by GmshReader.");
292 std::vector<size_type> main_nodes(ref_el.NumNodes());
293 for (
dim_t i = 0; i < ref_el.NumNodes(); ++i) {
294 main_nodes[i] = gi2mi[end_element.NodeNumbers[i]];
297 mesh_factory_->AddEntity(ref_el, main_nodes, std::move(geom));
298 mi2gi[codim].emplace_back(std::vector{
static_cast<unsigned int>(end)});
309 mesh::utils::make_AllCodimMeshDataSet<std::vector<size_type>>(
mesh_);
311 for (
dim_t c = 0; c <= dim_mesh; ++c) {
312 for (
const auto*
const e :
mesh_->Entities(c)) {
313 auto mi =
mesh_->Index(*e);
314 if (c == dim_mesh && mi >= mi2gi[dim_mesh].size()) {
319 if (mi2gi[c].size() > mi) {
320 std::vector<size_type> temp;
321 for (
auto& gmsh_index : mi2gi[c][mi]) {
322 temp.push_back(msh_file.
Elements[gmsh_index].PhysicalEntityNr);
335 std::pair{pe.Name, std::pair{pe.Number, dim_mesh - pe.Dimension}});
337 std::pair{pe.Number, std::pair{pe.Name, dim_mesh - pe.Dimension}});
356 dim_mesh >= 2 && dim_mesh <= 3 && dim_world >= 2 && dim_world <= 3,
357 "GmshReader supports only 2D and 3D meshes.");
369 std::vector<bool> is_main_node(max_node_tag - min_node_tag + 1,
false);
374 std::vector<std::vector<std::vector<std::size_t>>> mi2gi(dim_mesh + 1);
378 std::vector<size_type> num_entities(
mesh_factory_->DimMesh() + 1, 0);
381 LF_ASSERT_MSG(eb.dimension <= dim_mesh,
382 "mesh_factory->DimMesh() = "
384 <<
", but msh-file contains entities with dimension "
385 <<
DimOf(eb.element_type));
386 LF_ASSERT_MSG(eb.dimension ==
DimOf(eb.element_type),
387 "error in GmshFile: Mismatch between entity block type ("
388 << eb.element_type <<
") and dimension ("
389 <<
DimOf(eb.element_type) <<
")");
391 num_entities[eb.dimension] += eb.elements.size();
393 if (eb.dimension == dim_mesh) {
395 auto ref_el =
RefElOf(eb.element_type);
396 for (
const auto& element : eb.elements) {
397 const auto& node_indices = std::get<1>(element);
398 for (
unsigned int i = 0; i < ref_el.NumNodes(); ++i) {
399 auto node_tag = node_indices[i];
400 if (is_main_node.size() <= node_tag - min_node_tag) {
401 is_main_node.resize(node_tag - min_node_tag + 1);
403 is_main_node[node_tag - min_node_tag] =
true;
409 for (
dim_t c = 0; c <= dim_mesh; ++c) {
410 mi2gi[c].reserve(num_entities[dim_mesh - c]);
413 LF_ASSERT_MSG(num_entities[dim_mesh] > 0,
414 "MshFile contains no elements with dimension " << dim_mesh);
423 std::vector<size_type> gi2mi;
424 gi2mi.resize(is_main_node.size(), -1);
428 std::vector<std::pair<size_type, size_type>> gi2i;
429 gi2i.resize(is_main_node.size(), {-1, -1});
433 for (std::size_t k = 0; k < node_block.nodes.size(); ++k) {
434 const auto& n = node_block.nodes[k];
435 LF_ASSERT_MSG(gi2i.size() > n.first - min_node_tag,
436 "error: node_tag is higher than max_node_tag");
438 gi2i[n.first - min_node_tag] = std::make_pair(j, k);
440 if (!is_main_node[n.first - min_node_tag]) {
445 if (dim_world == 2) {
448 "In a 2D GmshMesh, the z-coordinate of every node must be zero");
453 gi2mi[n.first - min_node_tag] = mi;
463 std::size_t begin = 0;
464 auto ref_el =
RefElOf(element_block.element_type);
465 auto codim = dim_mesh - ref_el.Dimension();
467 for (std::size_t end = 0; end < element_block.elements.size(); ++end) {
468 const auto& begin_element = element_block.elements[begin];
469 const auto& end_element = element_block.elements[end];
471 if (begin_element.second == end_element.second && begin != end) {
473 mi2gi[codim].back().emplace_back(ebi);
482 auto mesh_index = gi2mi[end_element.second[0] - min_node_tag];
483 if (mesh_index != std::numeric_limits<unsigned int>::max()) {
486 if (mi2gi[dim_mesh].size() <= mesh_index) {
487 mi2gi[dim_mesh].resize(mesh_index + 1);
489 mi2gi[dim_mesh][mesh_index].emplace_back(ebi);
493 auto num_nodes = base::narrow<Eigen::Index>(end_element.second.size());
494 Eigen::MatrixXd node_coords(dim_world, num_nodes);
495 for (Eigen::Index i = 0; i < num_nodes; ++i) {
496 auto& gi2i_e = gi2i[end_element.second[i] - min_node_tag];
498 .nodes[gi2i_e.second]
500 if (dim_world == 2) {
501 node_coords.col(i) = node_coord.topRows(2);
503 node_coords.col(i) = node_coord;
506 std::unique_ptr<geometry::Geometry> geom;
508 switch (element_block.element_type) {
511 geom = std::make_unique<geometry::SegmentO1>(node_coords);
515 geom = std::make_unique<geometry::SegmentO2>(node_coords);
519 geom = std::make_unique<geometry::TriaO1>(node_coords);
523 geom = std::make_unique<geometry::TriaO2>(node_coords);
527 geom = std::make_unique<geometry::QuadO1>(node_coords);
531 geom = std::make_unique<geometry::QuadO2>(node_coords);
535 geom = std::make_unique<geometry::QuadO2>(node_coords.leftCols(8));
538 LF_VERIFY_MSG(
false,
"Gmsh element type "
539 << element_block.element_type
540 <<
" not (yet) supported by GmshReader.");
542 std::vector<size_type> main_nodes(ref_el.NumNodes());
543 for (
dim_t i = 0; i < ref_el.NumNodes(); ++i) {
544 main_nodes[i] = gi2mi[end_element.second[i] - min_node_tag];
547 mesh_factory_->AddEntity(ref_el, main_nodes, std::move(geom));
548 mi2gi[codim].push_back(std::vector<std::size_t>{ebi});
563 std::array<std::vector<std::vector<int>>, 4> gmei2gmphi;
565 auto makeMap = [](std::vector<std::vector<int>>& result,
auto& entities) {
567 int max_entity_tag = 0;
568 for (
auto& e : entities) {
569 max_entity_tag = std::max(max_entity_tag, e.tag);
571 result.resize(max_entity_tag + 1);
574 for (
auto& e : entities) {
575 result[e.tag] = e.physical_tags;
580 makeMap(gmei2gmphi[dim_mesh], std::get<0>(msh_file.
entities));
581 makeMap(gmei2gmphi[dim_mesh - 1], std::get<1>(msh_file.
entities));
582 makeMap(gmei2gmphi[dim_mesh - 2], std::get<2>(msh_file.
entities));
584 makeMap(gmei2gmphi[0], std::get<3>(msh_file.
entities));
587 makeMap(gmei2gmphi[dim_mesh],
589 makeMap(gmei2gmphi[dim_mesh - 1],
591 makeMap(gmei2gmphi[dim_mesh - 2],
594 makeMap(gmei2gmphi[0],
602 mesh::utils::make_AllCodimMeshDataSet<std::vector<size_type>>(
mesh_);
604 for (
dim_t c = 0; c <= dim_mesh; ++c) {
605 for (
const auto* e :
mesh_->Entities(c)) {
606 auto mi =
mesh_->Index(*e);
607 if (c == dim_mesh && mi >= mi2gi[dim_mesh].size()) {
612 if (mi2gi[c].size() > mi) {
613 std::vector<size_type> temp;
614 for (
auto& gmsh_index : mi2gi[c][mi]) {
615 const auto& element_block =
617 auto& physical_tags = gmei2gmphi[c][element_block.entity_tag];
618 temp.insert(std::end(temp), std::begin(physical_tags),
619 std::end(physical_tags));
632 pn.name, std::pair{pn.physical_tag, dim_mesh - pn.dimension}});
634 std::pair{pn.name, dim_mesh - pn.dimension}});
645std::variant<GMshFileV2, GMshFileV4>
ReadGmshFile(
const std::string& filename) {
648 std::ifstream in(filename, std::ios_base::in | std::ios_base::binary);
650 std::string error(
"Could not open file ");
656 in.unsetf(std::ios::skipws);
657 std::copy(std::istream_iterator<char>(in), std::istream_iterator<char>(),
658 std::back_inserter(storage));
663 auto iter = storage.cbegin();
664 auto end = storage.cend();
666 namespace qi = boost::spirit::qi;
667 namespace ascii = boost::spirit::ascii;
670 std::tuple<std::string, bool, int, int> header;
671 qi::rule<
decltype(iter), std::string()> version_parser;
673 version_parser %= +(ascii::alnum | ascii::punct);
674 qi::rule<
decltype(iter),
decltype(header)(), ascii::space_type> header_parser;
675 header_parser %= qi::lit(
"$MeshFormat") >>
676 (qi::hold[(version_parser >> qi::lit(
'0') >>
677 qi::attr(
false) >> qi::int_ >> qi::attr(1))] |
678 (version_parser >> qi::lit(
'1') >> qi::attr(
true) >>
679 qi::int_ >> qi::little_dword)) >>
680 qi::lit(
"$EndMeshFormat");
683 succesful = qi::phrase_parse(iter, end, header_parser, ascii::space, header);
685 LF_VERIFY_MSG(succesful,
"Could not read header of file " << filename);
687 if (std::get<0>(header) ==
"4.1") {
688 return ReadGmshFileV4(iter, end, std::get<0>(header), std::get<1>(header),
689 std::get<2>(header), std::get<3>(header), filename);
691 if (std::get<0>(header) ==
"2.2") {
692 return readGmshFileV2(iter, end, std::get<0>(header), std::get<1>(header),
693 std::get<2>(header), std::get<3>(header), filename);
695 LF_VERIFY_MSG(
false,
"GmshFiles with Version " << std::get<0>(header)
696 <<
" are not yet supported.");