From 626ec62e843ceaf67636728a7b4fea1a7cb34872 Mon Sep 17 00:00:00 2001 From: gugugu Date: Wed, 19 Jul 2023 22:46:57 +0800 Subject: [PATCH 1/5] add Gmsh mesh file parser In this commit added mesh file io for modmesh, it lets modmesh has capabilty to read third-party mesh generator generated file and convert the content to a data structure that allow modmesh can use it to do some calculation. Currently mesh io only support Gmsh format. --- cpp/modmesh/CMakeLists.txt | 2 + cpp/modmesh/io/CMakeLists.txt | 23 ++ cpp/modmesh/io/gmsh.hpp | 397 +++++++++++++++++++++++++++++ cpp/modmesh/io/io.hpp | 4 + cpp/modmesh/io/pymod/io_pymod.cpp | 31 +++ cpp/modmesh/io/pymod/io_pymod.hpp | 23 ++ cpp/modmesh/io/pymod/wrap_Gmsh.cpp | 46 ++++ cpp/modmesh/python/module.cpp | 2 + gtests/CMakeLists.txt | 2 + gtests/test_nopython_io.cpp | 350 +++++++++++++++++++++++++ modmesh/app/sample_mesh.py | 22 ++ modmesh/core.py | 1 + tests/data/gmsh_triangle.msh | 24 ++ tests/test_gmsh.py | 33 +++ 14 files changed, 960 insertions(+) create mode 100644 cpp/modmesh/io/CMakeLists.txt create mode 100644 cpp/modmesh/io/gmsh.hpp create mode 100644 cpp/modmesh/io/io.hpp create mode 100644 cpp/modmesh/io/pymod/io_pymod.cpp create mode 100644 cpp/modmesh/io/pymod/io_pymod.hpp create mode 100644 cpp/modmesh/io/pymod/wrap_Gmsh.cpp create mode 100644 gtests/test_nopython_io.cpp create mode 100644 tests/data/gmsh_triangle.msh create mode 100644 tests/test_gmsh.py diff --git a/cpp/modmesh/CMakeLists.txt b/cpp/modmesh/CMakeLists.txt index 7c7117df..a41a50d1 100644 --- a/cpp/modmesh/CMakeLists.txt +++ b/cpp/modmesh/CMakeLists.txt @@ -37,6 +37,7 @@ add_subdirectory(onedim) add_subdirectory(python) add_subdirectory(spacetime) add_subdirectory(view) +add_subdirectory(io) set(MODMESH_ROOT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/modmesh.hpp @@ -80,6 +81,7 @@ set(MODMESH_TERMINAL_FILES ${MODMESH_ONEDIM_FILES} ${MODMESH_SPACETIME_FILES} ${MODMESH_PYTHON_FILES} + ${MODMESH_IO_FILES} CACHE FILEPATH "" FORCE) set(MODMESH_GRAPHIC_FILES diff --git a/cpp/modmesh/io/CMakeLists.txt b/cpp/modmesh/io/CMakeLists.txt new file mode 100644 index 00000000..5d8f1e1c --- /dev/null +++ b/cpp/modmesh/io/CMakeLists.txt @@ -0,0 +1,23 @@ + +cmake_minimum_required(VERSION 3.16) + +set(MODMESH_IO_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/io.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/gmsh.hpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_IO_PYMODHEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/io_pymod.hpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_IO_PYMODSOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/io_pymod.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/wrap_Gmsh.cpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_IO_FILES + ${MODMESH_IO_HEADERS} + ${MODMESH_IO_PYMODHEADERS} + ${MODMESH_IO_PYMODSOURCES} + CACHE FILEPATH "" FORCE) +# vim: set ff=unix fenc=utf8 nobomb et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/gmsh.hpp b/cpp/modmesh/io/gmsh.hpp new file mode 100644 index 00000000..ab78fdf5 --- /dev/null +++ b/cpp/modmesh/io/gmsh.hpp @@ -0,0 +1,397 @@ +#pragma once +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace modmesh +{ +namespace IO +{ +namespace Gmsh +{ +struct ElementDef +{ + static ElementDef by_id(uint16_t id); + + ElementDef(uint8_t ndim, uint16_t nnds, uint8_t mmtpn, small_vector const & mmcl) + : m_ndim(ndim) + , m_nnds(nnds) + , m_mmtpn(mmtpn) + , m_mmcl(mmcl) + { + } + + ~ElementDef() = default; + + ElementDef() = default; + ElementDef(const ElementDef & other) = delete; + ElementDef(ElementDef && other) = delete; + ElementDef & operator=(const ElementDef & other) = delete; + ElementDef & operator=(ElementDef && other) = delete; + + uint8_t ndim() const { return m_ndim; } + uint16_t nnds() const { return m_nnds; } + uint8_t mmtpn() const { return m_mmtpn; } + small_vector mmcl() const { return m_mmcl; } + +private: + uint8_t m_ndim = 0; /* Number of dimension */ + uint16_t m_nnds = 0; /* Number of nodes */ + uint8_t m_mmtpn = 0; /* modmesh cell type */ + small_vector m_mmcl; /* modmesh cell order */ +}; /* end struct ElementDef */ + +inline ElementDef ElementDef::by_id(uint16_t id) +{ +#define VEC(...) __VA_ARGS__ +#define MM_DECL_SWITCH_ELEMENT_TYPE(ID, NDIM, NNDS, MMTPN, MMCL) \ + case ID: return ElementDef(NDIM, NNDS, MMTPN, small_vector{MMCL}); break; + switch (id) + { + // clang-format off + // id, dim, nnodes, cell type, cell order + MM_DECL_SWITCH_ELEMENT_TYPE( 1, 1, 2, 2, VEC(0, 1)) // 2-node line + MM_DECL_SWITCH_ELEMENT_TYPE( 2, 2, 3, 4, VEC(0, 1, 2)) // 3-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE( 3, 2, 4, 3, VEC(0, 1, 2, 3)) // 4-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE( 4, 3, 4, 6, VEC(0, 1, 2, 3)) // 4-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE( 5, 3, 8, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 8-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE( 6, 3, 6, 7, VEC(0, 2, 1, 3, 5, 4)) // 6-node prism + MM_DECL_SWITCH_ELEMENT_TYPE( 7, 3, 5, 8, VEC(0, 1, 2, 3, 4)) // 5-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE( 8, 1, 3, 2, VEC(0, 1)) // 3-node line + MM_DECL_SWITCH_ELEMENT_TYPE( 9, 2, 6, 4, VEC(0, 1, 2)) // 6-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(10, 2, 9, 3, VEC(0, 1, 2, 3)) // 9-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE(11, 3, 10, 6, VEC(0, 1, 2, 3)) // 10-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(12, 3, 27, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 27-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(13, 3, 18, 7, VEC(0, 2, 1, 3, 5, 4)) // 18-node prism + MM_DECL_SWITCH_ELEMENT_TYPE(14, 3, 14, 8, VEC(0, 1, 2, 3, 4)) // 14-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE(15, 0, 1, 1, VEC(0)) // 1-node point + MM_DECL_SWITCH_ELEMENT_TYPE(16, 2, 8, 3, VEC(0, 1, 2, 3)) // 8-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE(17, 3, 20, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 20-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(18, 3, 15, 7, VEC(0, 2, 1, 3, 5, 4)) // 15-node prism + MM_DECL_SWITCH_ELEMENT_TYPE(19, 3, 13, 8, VEC(0, 1, 2, 3, 4)) // 13-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE(20, 2, 9, 4, VEC(0, 1, 2)) // 9-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(21, 2, 10, 4, VEC(0, 1, 2)) // 10-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(22, 2, 12, 4, VEC(0, 1, 2)) // 12-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(23, 2, 15, 4, VEC(0, 1, 2)) // 15-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(24, 2, 15, 4, VEC(0, 1, 2)) // 15-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(25, 2, 21, 4, VEC(0, 1, 2)) // 21-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(26, 1, 4, 2, VEC(0, 1)) // 4-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(27, 1, 5, 2, VEC(0, 1)) // 5-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(28, 1, 6, 2, VEC(0, 1)) // 6-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(29, 3, 20, 6, VEC(0, 1, 2, 3)) // 20-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(30, 3, 35, 6, VEC(0, 1, 2 ,3)) // 35-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(31, 3, 56, 6, VEC(0, 1, 2, 3)) // 56-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(92, 3, 64, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 64-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(93, 3, 125, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 125-node hexahedron + default: return ElementDef{}; break; + // clang-format on + } +#undef MM_DECL_SWITCH_ELEMENT_TYPE +#undef VEC +} + +class Gmsh + : public NumberBase +{ + using number_base = NumberBase; + using int_type = typename number_base::int_type; + using uint_type = typename number_base::uint_type; + using real_type = typename number_base::real_type; + +public: + explicit Gmsh(const std::string & file_path) + { + bool meta_enter = false, node_enter = false, element_enter = false; + // clang-format off + std::unordered_map> keyword_handler = { + {"$MeshFormat", [this, &meta_enter]() { _load_meta(); meta_enter = true; }}, + {"$Nodes", [this, &node_enter]() { _load_nodes(); node_enter = true; }}, + {"$Elements", [this, &element_enter]() { _load_elements(); element_enter = true; }}, + {"$PhysicalNames", [this]() { _load_physical(); }} + }; + + stream.open(file_path, std::ios::in); + if (!stream.good()) + { + throw std::invalid_argument(Formatter() << file_path << " path invalid."); + } + + std::string line; + while (std::getline(stream, line)) + { + // Using a finite state machine to check the input msh file format is valid or not. + // $ is a keyword to trigger state transition. + if (line.find('$') != std::string::npos) + { + auto it = keyword_handler.find(line); + if (it != keyword_handler.end()) + { + if (_isValidTransition(it->first)) + { + it->second(); + } + else + { + break; + } + } + else + { + break; + } + } + } + + // MeshFormat, Nodes and Elements section is mandatory in gmsh msh file, + // therefore need to check these sections are exist or not otherwise + // modmesh may crash during mesh processing. + if (!(meta_enter && node_enter && element_enter)) + { + throw std::invalid_argument("Incorrect msh file format."); + } + } + + ~Gmsh() + { + stream.close(); + } + + Gmsh() = delete; + Gmsh(Gmsh const & other) = delete; + Gmsh(Gmsh && other) = delete; + Gmsh & operator=(Gmsh const & other) = delete; + Gmsh & operator=(Gmsh && other) = delete; + + std::shared_ptr toblock(void); + +private: + enum class FormatState + { + BEGIN, + META_END, + PYHSICAL_NAME_END, + NODE_END, + ELEMENT_END + }; + + // Check the finite state machine state transition is valid or not to check msh file format is correct + bool _isValidTransition(const std::string s) + { + if (last_fmt_state == FormatState::BEGIN) + { + return s == "$MeshFormat"; + } + else if (last_fmt_state == FormatState::META_END || last_fmt_state == FormatState::PYHSICAL_NAME_END) + { + return s == "$PhysicalNames" || s == "$Nodes"; + } + else if (last_fmt_state == FormatState::NODE_END) + { + return s == "$Elements"; + } + + return false; + } + + void _load_meta(void) + { + std::string line; + + while (std::getline(stream, line) && line.find('$') == std::string::npos) + { + auto tokens = _tokenize(line, ' '); + msh_ver = std::stod(tokens[0]); + + // The parse only support ver 2.2 msh file. + if (msh_ver != 2.2) + { + throw std::invalid_argument(Formatter() << "modmesh does not support msh file ver " << msh_ver << "."); + } + + msh_file_type = std::stoi(tokens[1]); + msh_data_size = std::stoi(tokens[2]); + } + + if (!line.compare("$EndMeshFormat")) + { + last_fmt_state = FormatState::META_END; + } + } + + // TODO: PhysicalNames section parsing logic not complete yet, but without PhysicalNames section + // modmesh mesh viewer still working, therefore we can finish this later. + void _load_physical(void) + { + std::string line; + + while (std::getline(stream, line) && line.find('$') == std::string::npos) {} + + if (!line.compare("$EndPhysicalNames")) + { + last_fmt_state = FormatState::PYHSICAL_NAME_END; + } + } + + void _load_nodes(void) + { + std::string line; + std::getline(stream, line); + auto nnode = std::stoul(line); + + m_nds.remake(small_vector{nnode, 3}, 0); + + while (std::getline(stream, line) && line.find('$') == std::string::npos) + { + auto tokens = _tokenize(line, ' '); + // gmsh node index is 1-based index + m_nds(std::stoul(tokens[0]) - 1, 0) = std::stod(tokens[1]); + m_nds(std::stoul(tokens[0]) - 1, 1) = std::stod(tokens[2]); + m_nds(std::stoul(tokens[0]) - 1, 2) = std::stod(tokens[3]); + } + + if (!line.compare("$EndNodes")) + { + last_fmt_state = FormatState::NODE_END; + } + } + + void _load_elements(void) + { + std::string line; + std::getline(stream, line); + auto nelement = std::stoul(line); + std::vector usnds; + + m_cltpn.remake(small_vector{nelement}, 0); + m_elgrp.remake(small_vector{nelement}, 0); + m_elgeo.remake(small_vector{nelement}, 0); + m_eldim.remake(small_vector{nelement}, 0); + + uint_type idx = 0; + + while (std::getline(stream, line) && line.find('$') == std::string::npos && idx < nelement) + { + auto tokens = _tokenize(line, ' '); + + // parse element type + auto tpn = std::stoul(tokens[1]); + auto eldef = ElementDef::by_id(tpn); + // parse element tag + std::vector tag; + for (size_t i = 0; i < std::stoul(tokens[2]); ++i) + { + tag.push_back(std::stoul(tokens[3 + i])); + } + + // parse node number list + std::vector nds; + for (size_t i = 3 + std::stoul(tokens[2]); i < tokens.size(); ++i) + { + nds.push_back(std::stoul(tokens[i])); + } + + m_cltpn[idx] = eldef.mmtpn(); + m_elgrp[idx] = tag[0]; + m_elgeo[idx] = tag[1]; + m_eldim[idx] = eldef.ndim(); + + small_vector nds_temp(nds.size() + 1, 0); + auto mmcl = eldef.mmcl(); + + for (size_t i = 0; i < mmcl.size(); ++i) + { + nds_temp[mmcl[i] + 1] = nds[i] - 1; + } + usnds.insert(usnds.end(), nds_temp.begin() + 1, nds_temp.end()); + nds_temp[0] = mmcl.size(); + m_elems.insert(std::pair{idx, nds_temp}); + idx++; + } + + if (!line.compare("$EndElements")) + { + last_fmt_state = FormatState::ELEMENT_END; + } + + // sorting used node and remove duplicate node id + std::sort(usnds.begin(), usnds.end()); + auto remove = std::unique(usnds.begin(), usnds.end()); + usnds.erase(remove, usnds.end()); + + // put used node id to m_ndmap + m_ndmap.remake(small_vector{usnds.size()}, -1); + for (size_t i = 0; i < usnds.size(); ++i) + { + m_ndmap(usnds[i]) = i; + } + } + + std::vector _tokenize(const std::string & str, const char delim) + { + std::vector output; + std::stringstream ss(str); + std::string token; + while (std::getline(ss, token, delim)) + { + output.push_back(token); + } + return output; + } + + void _build_interior(std::shared_ptr blk) + { + blk->cltpn().swap(m_cltpn); + blk->ndcrd().swap(m_nds); + for (size_t i = 0; i < m_elems.size(); ++i) + { + blk->clnds()(i, 0) = m_elems[i][0]; + for (size_t j = 1; j <= m_elems[i][0]; ++j) + { + + blk->clnds()(i, j) = m_elems[i][j]; + } + } + blk->build_interior(true); + blk->build_boundary(); + blk->build_ghost(); + } + + std::ifstream stream; + FormatState last_fmt_state = FormatState::BEGIN; + + real_type msh_ver = 0.0; + + uint_type msh_file_type = 0; + uint_type msh_data_size = 0; + uint_type nnodes = 0; + + SimpleArray m_cltpn; + + SimpleArray m_nds; + + SimpleArray m_elgrp; + SimpleArray m_elgeo; + SimpleArray m_eldim; + SimpleArray m_usnds; + SimpleArray m_ndmap; + + std::unordered_map> m_elems; +}; /* end class Gmsh */ + +inline std::shared_ptr Gmsh::toblock(void) +{ + std::shared_ptr block = StaticMesh::construct(m_eldim.max(), m_nds.shape(0), 0, m_elems.size()); + _build_interior(block); + return block; +} +} /* end namespace Gmsh */ +} /* end namespace IO */ +} /* end namespace modmesh */ + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/io.hpp b/cpp/modmesh/io/io.hpp new file mode 100644 index 00000000..e610f562 --- /dev/null +++ b/cpp/modmesh/io/io.hpp @@ -0,0 +1,4 @@ +#pragma once +#include + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/pymod/io_pymod.cpp b/cpp/modmesh/io/pymod/io_pymod.cpp new file mode 100644 index 00000000..564b8412 --- /dev/null +++ b/cpp/modmesh/io/pymod/io_pymod.cpp @@ -0,0 +1,31 @@ +#include + +namespace modmesh +{ + +namespace python +{ + +struct io_pymod_tag; + +template <> +OneTimeInitializer & OneTimeInitializer::me() +{ + static OneTimeInitializer instance; + return instance; +} + +void initialize_io(pybind11::module & mod) +{ + auto initialize_impl = [](pybind11::module & mod) + { + wrap_Gmsh(mod); + }; + + OneTimeInitializer::me()(mod, initialize_impl); +} +} /* end namespace python */ + +} /* end namespace modmesh */ + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/pymod/io_pymod.hpp b/cpp/modmesh/io/pymod/io_pymod.hpp new file mode 100644 index 00000000..1b46db0b --- /dev/null +++ b/cpp/modmesh/io/pymod/io_pymod.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace modmesh +{ + +namespace python +{ + +void initialize_io(pybind11::module & mod); +void wrap_Gmsh(pybind11::module & mod); + +} /* end namespace python */ + +} /* end namespace modmesh */ + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/pymod/wrap_Gmsh.cpp b/cpp/modmesh/io/pymod/wrap_Gmsh.cpp new file mode 100644 index 00000000..5a9d62f6 --- /dev/null +++ b/cpp/modmesh/io/pymod/wrap_Gmsh.cpp @@ -0,0 +1,46 @@ +#include +#include + +namespace modmesh +{ + +namespace python +{ + +class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapGmsh + : public WrapBase> +{ +public: + + using base_type = WrapBase>; + using wrapped_type = typename base_type::wrapped_type; + + friend root_base_type; + +protected: + + WrapGmsh(pybind11::module & mod, char const * pyname, char const * pydoc) + : WrapBase>(mod, pyname, pydoc) + { + namespace py = pybind11; // NOLINT(misc-unused-alias-decls) + + (*this) + .def( + py::init( + [](const std::string & path) + { return std::make_shared(path); }), + py::arg("file_name")) + .def("toblock", &wrapped_type::toblock); + ; + } + +}; /* end class WrapGmsh */ + +void wrap_Gmsh(pybind11::module & mod) +{ + WrapGmsh::commit(mod, "Gmsh", "Gmsh"); +} + +} /* end namespace python */ + +} /* end namespace modmesh */ diff --git a/cpp/modmesh/python/module.cpp b/cpp/modmesh/python/module.cpp index 3bee0d2a..5c6f43f7 100644 --- a/cpp/modmesh/python/module.cpp +++ b/cpp/modmesh/python/module.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef QT_CORE_LIB #include #endif // QT_CORE_LIB @@ -41,6 +42,7 @@ void initialize(pybind11::module_ mod) initialize_toggle(mod); initialize_buffer(mod); initialize_mesh(mod); + initialize_io(mod); pybind11::module_ spacetime_mod = mod.def_submodule("spacetime", "spacetime"); initialize_spacetime(spacetime_mod); pybind11::module_ onedim_mod = mod.def_submodule("onedim", "onedim"); diff --git a/gtests/CMakeLists.txt b/gtests/CMakeLists.txt index 5efa406f..0ccf4dc8 100644 --- a/gtests/CMakeLists.txt +++ b/gtests/CMakeLists.txt @@ -21,10 +21,12 @@ add_executable( test_nopython test_nopython_buffer.cpp test_nopython_modmesh.cpp + test_nopython_io.cpp ) target_link_libraries( test_nopython GTest::gtest_main + GTest::gmock_main ) include(GoogleTest) diff --git a/gtests/test_nopython_io.cpp b/gtests/test_nopython_io.cpp new file mode 100644 index 00000000..de61f494 --- /dev/null +++ b/gtests/test_nopython_io.cpp @@ -0,0 +1,350 @@ +#include + +#include +#include + +#ifdef Py_PYTHON_H +#error "Python.h should not be included." +#endif + +std::string g_test_file_path; + +TEST(Gmsh_Parser, NonCellTypeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(0); + EXPECT_EQ(ele_def.ndim(), 0); + EXPECT_EQ(ele_def.nnds(), 0); + EXPECT_EQ(ele_def.mmtpn(), 0); + EXPECT_EQ(ele_def.mmcl().empty(), true); +} + +TEST(Gmsh_Parser, Line2NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(1); + EXPECT_EQ(ele_def.ndim(), 1); + EXPECT_EQ(ele_def.nnds(), 2); + EXPECT_EQ(ele_def.mmtpn(), 2); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1)); +} + +TEST(Gmsh_Parser, Triangle3NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(2); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 3); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, Quadrangle4NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(3); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 4); + EXPECT_EQ(ele_def.mmtpn(), 3); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, Tetrahedron4NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(4); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 4); + EXPECT_EQ(ele_def.mmtpn(), 6); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, Hexahedron8NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(5); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 8); + EXPECT_EQ(ele_def.mmtpn(), 5); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7)); +} + +TEST(Gmsh_Parser, Prism6NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(6); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 6); + EXPECT_EQ(ele_def.mmtpn(), 7); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 2, 1, 3, 5, 4)); +} + +TEST(Gmsh_Parser, Pryamid5NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(7); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 5); + EXPECT_EQ(ele_def.mmtpn(), 8); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4)); +} + +TEST(Gmsh_Parser, Line3NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(8); + EXPECT_EQ(ele_def.ndim(), 1); + EXPECT_EQ(ele_def.nnds(), 3); + EXPECT_EQ(ele_def.mmtpn(), 2); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1)); +} + +TEST(Gmsh_Parser, Triangle6NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(9); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 6); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, Quadrangle9NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(10); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 9); + EXPECT_EQ(ele_def.mmtpn(), 3); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, tetrahedron10NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(11); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 10); + EXPECT_EQ(ele_def.mmtpn(), 6); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, hexahedron27NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(12); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 27); + EXPECT_EQ(ele_def.mmtpn(), 5); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7)); +} + +TEST(Gmsh_Parser, Prism18NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(13); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 18); + EXPECT_EQ(ele_def.mmtpn(), 7); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 2, 1, 3, 5, 4)); +} + +TEST(Gmsh_Parser, Pyramid14NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(14); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 14); + EXPECT_EQ(ele_def.mmtpn(), 8); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4)); +} + +TEST(Gmsh_Parser, Point1NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(15); + EXPECT_EQ(ele_def.ndim(), 0); + EXPECT_EQ(ele_def.nnds(), 1); + EXPECT_EQ(ele_def.mmtpn(), 1); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0)); +} + +TEST(Gmsh_Parser, Quadrangle8NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(16); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 8); + EXPECT_EQ(ele_def.mmtpn(), 3); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, hexahedron20NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(17); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 20); + EXPECT_EQ(ele_def.mmtpn(), 5); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7)); +} + +TEST(Gmsh_Parser, Prism15NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(18); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 15); + EXPECT_EQ(ele_def.mmtpn(), 7); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 2, 1, 3, 5, 4)); +} + +TEST(Gmsh_Parser, Pyramid13NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(19); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 13); + EXPECT_EQ(ele_def.mmtpn(), 8); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4)); +} + +TEST(Gmsh_Parser, IncompleteTriangle9NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(20); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 9); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, Triangle10NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(21); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 10); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, IncompleteTriangle12NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(22); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 12); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, Triangle15NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(23); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 15); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, IncompleteTriangle15NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(24); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 15); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, IncompleteTriangle21NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(25); + EXPECT_EQ(ele_def.ndim(), 2); + EXPECT_EQ(ele_def.nnds(), 21); + EXPECT_EQ(ele_def.mmtpn(), 4); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2)); +} + +TEST(Gmsh_Parser, Edge4NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(26); + EXPECT_EQ(ele_def.ndim(), 1); + EXPECT_EQ(ele_def.nnds(), 4); + EXPECT_EQ(ele_def.mmtpn(), 2); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1)); +} + +TEST(Gmsh_Parser, Edge5NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(27); + EXPECT_EQ(ele_def.ndim(), 1); + EXPECT_EQ(ele_def.nnds(), 5); + EXPECT_EQ(ele_def.mmtpn(), 2); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1)); +} + +TEST(Gmsh_Parser, Edge6NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(28); + EXPECT_EQ(ele_def.ndim(), 1); + EXPECT_EQ(ele_def.nnds(), 6); + EXPECT_EQ(ele_def.mmtpn(), 2); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1)); +} + +TEST(Gmsh_Parser, Tetrahedron20NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(29); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 20); + EXPECT_EQ(ele_def.mmtpn(), 6); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, Tetrahedron35NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(30); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 35); + EXPECT_EQ(ele_def.mmtpn(), 6); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, Tetrahedron56NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(31); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 56); + EXPECT_EQ(ele_def.mmtpn(), 6); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3)); +} + +TEST(Gmsh_Parser, Hexahedron64NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(92); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 64); + EXPECT_EQ(ele_def.mmtpn(), 5); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7)); +} + +TEST(Gmsh_Parser, Hexahedron125NodeDefinition) +{ + namespace gmsh = modmesh::IO::Gmsh; + auto ele_def = gmsh::ElementDef::by_id(93); + EXPECT_EQ(ele_def.ndim(), 3); + EXPECT_EQ(ele_def.nnds(), 125); + EXPECT_EQ(ele_def.mmtpn(), 5); + EXPECT_THAT(ele_def.mmcl(), testing::ElementsAre(0, 1, 2, 3, 4, 5, 6, 7)); +} diff --git a/modmesh/app/sample_mesh.py b/modmesh/app/sample_mesh.py index 2ec7d32a..f63828c9 100644 --- a/modmesh/app/sample_mesh.py +++ b/modmesh/app/sample_mesh.py @@ -83,6 +83,25 @@ def help_other(set_command=False): view.mgr.pycon.command = cmd.strip() +def help_mesh_viewer(path, set_command=False): + cmd = f""" +# Open a sub window for the mesh viewer: +w_mh_viewer = add3DWidget() +mh_viewer = make_mesh_viewer("{path}") +w_mh_viewer.updateMesh(mh_viewer) +w_mh_viewer.showMark() +""" + view.mgr.pycon.writeToHistory(cmd) + if set_command: + view.mgr.pycon.command = cmd.strip() + + +def make_mesh_viewer(path): + gm = core.Gmsh(path) + mh = gm.toblock() + return mh + + def make_triangle(): mh = core.StaticMesh(ndim=2, nnode=4, nface=0, ncell=3) mh.ndcrd.ndarray[:, :] = (0, 0), (-1, -1), (1, -1), (0, 1) @@ -110,9 +129,11 @@ def load_app(): symbols = ( 'help_tri', 'help_tet', + 'help_mesh_viewer', 'help_other', 'make_triangle', 'make_tetrahedron', + 'make_mesh_viewer', ('add3DWidget', view.mgr.add3DWidget), ) for k in symbols: @@ -129,6 +150,7 @@ def load_app(): help_tri(set_command=False) # or True help_tet(set_command=False) # or True help_other(set_command=False) # or True +help_mesh_viewer(path, set_command=False) # or True """) # vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/modmesh/core.py b/modmesh/core.py index e64b4e66..263df76a 100644 --- a/modmesh/core.py +++ b/modmesh/core.py @@ -64,6 +64,7 @@ 'METAL_BUILT', 'metal_running', 'HAS_VIEW', + 'Gmsh', ] diff --git a/tests/data/gmsh_triangle.msh b/tests/data/gmsh_triangle.msh new file mode 100644 index 00000000..6cf785d6 --- /dev/null +++ b/tests/data/gmsh_triangle.msh @@ -0,0 +1,24 @@ +$MeshFormat +2.2 0 8 +$EndMeshFormat +$PhysicalNames +5 +1 1 "top" +1 2 "left" +1 3 "bottom" +1 4 "right" +2 5 "domain" +$EndPhysicalNames +$Nodes +4 +1 0 0 0 +2 -1 -1 0 +3 1 -1 0 +4 0 1 0 +$EndNodes +$Elements +3 +1 2 2 5 3 1 2 3 +2 2 2 5 3 1 3 4 +3 2 2 5 3 1 4 2 +$EndElements diff --git a/tests/test_gmsh.py b/tests/test_gmsh.py new file mode 100644 index 00000000..918fb215 --- /dev/null +++ b/tests/test_gmsh.py @@ -0,0 +1,33 @@ +import os + +import unittest + +import numpy as np + +import modmesh + + +class GmshTC(unittest.TestCase): + + def test_gmsh_parsing(self): + path = os.path.join(os.path.abspath(os.path.dirname(__file__)), + "data/gmsh_triangle.msh") + gmsh_instance = modmesh.core.Gmsh(path) + blk = gmsh_instance.toblock() + + # Check nodes information + self.assertEqual(blk.nnode, 4) + + # Due to ghost cell and ghost node had been created, the real body + # had been shifted and start with index 3 + np.testing.assert_almost_equal(blk.ndcrd.ndarray[3:, :].tolist(), + [[0.0, 0.0], + [-1.0, -1.0], + [1.0, -1.0], + [0.0, 1.0]]) + # Check cells information + self.assertEqual(blk.ncell, 3) + self.assertEqual(blk.cltpn.ndarray[3:].tolist(), [4, 4, 4]) + self.assertEqual(blk.clnds.ndarray[3:, :4].tolist(), [[3, 0, 1, 2], + [3, 0, 2, 3], + [3, 0, 3, 1]]) From 946f92cba8633bbf93ec199b9f06ae62eafaf697 Mon Sep 17 00:00:00 2001 From: gugugu Date: Tue, 25 Jul 2023 23:43:29 +0800 Subject: [PATCH 2/5] code quality enhancement In this commit, I made the following additions and modifications: 1. Renamed cpp/modmesh/io to cpp/modmesh/inout to prevent unnecessary ambiguity. 2. Renamed the namespace IO to inout and removed the Gmsh namespace. 3. Renamed the struct ElementDef to GmshElementDef. 4. Moved non-template functions from gmsh.hpp to gmsh.cpp. 5. The Gmsh constructor now takes a string input as data, and the python wrapper also takes py::bytes as input, therefore file IO is now taken care of by python. --- cpp/modmesh/CMakeLists.txt | 4 +- cpp/modmesh/inout/CMakeLists.txt | 28 +++ cpp/modmesh/inout/gmsh.cpp | 83 +++++++ cpp/modmesh/{io => inout}/gmsh.hpp | 227 ++++++------------ cpp/modmesh/{io/io.hpp => inout/inout.hpp} | 2 +- cpp/modmesh/inout/pymod/inout_pymod.cpp | 31 +++ .../pymod/inout_pymod.hpp} | 4 +- cpp/modmesh/{io => inout}/pymod/wrap_Gmsh.cpp | 14 +- cpp/modmesh/io/CMakeLists.txt | 23 -- cpp/modmesh/io/pymod/io_pymod.cpp | 31 --- cpp/modmesh/python/module.cpp | 4 +- gtests/CMakeLists.txt | 2 +- ...opython_io.cpp => test_nopython_inout.cpp} | 104 +++----- modmesh/app/sample_mesh.py | 3 +- modmesh/core.py | 2 +- tests/test_gmsh.py | 5 +- 16 files changed, 274 insertions(+), 293 deletions(-) create mode 100644 cpp/modmesh/inout/CMakeLists.txt create mode 100644 cpp/modmesh/inout/gmsh.cpp rename cpp/modmesh/{io => inout}/gmsh.hpp (73%) rename cpp/modmesh/{io/io.hpp => inout/inout.hpp} (65%) create mode 100644 cpp/modmesh/inout/pymod/inout_pymod.cpp rename cpp/modmesh/{io/pymod/io_pymod.hpp => inout/pymod/inout_pymod.hpp} (80%) rename cpp/modmesh/{io => inout}/pymod/wrap_Gmsh.cpp (59%) delete mode 100644 cpp/modmesh/io/CMakeLists.txt delete mode 100644 cpp/modmesh/io/pymod/io_pymod.cpp rename gtests/{test_nopython_io.cpp => test_nopython_inout.cpp} (71%) diff --git a/cpp/modmesh/CMakeLists.txt b/cpp/modmesh/CMakeLists.txt index a41a50d1..2ef84532 100644 --- a/cpp/modmesh/CMakeLists.txt +++ b/cpp/modmesh/CMakeLists.txt @@ -37,7 +37,7 @@ add_subdirectory(onedim) add_subdirectory(python) add_subdirectory(spacetime) add_subdirectory(view) -add_subdirectory(io) +add_subdirectory(inout) set(MODMESH_ROOT_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/modmesh.hpp @@ -81,7 +81,7 @@ set(MODMESH_TERMINAL_FILES ${MODMESH_ONEDIM_FILES} ${MODMESH_SPACETIME_FILES} ${MODMESH_PYTHON_FILES} - ${MODMESH_IO_FILES} + ${MODMESH_INOUT_FILES} CACHE FILEPATH "" FORCE) set(MODMESH_GRAPHIC_FILES diff --git a/cpp/modmesh/inout/CMakeLists.txt b/cpp/modmesh/inout/CMakeLists.txt new file mode 100644 index 00000000..5afa5852 --- /dev/null +++ b/cpp/modmesh/inout/CMakeLists.txt @@ -0,0 +1,28 @@ + +cmake_minimum_required(VERSION 3.16) + +set(MODMESH_INOUT_HEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/inout.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/gmsh.hpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_INOUT_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/gmsh.cpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_INOUT_PYMODHEADERS + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/inout_pymod.hpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_INOUT_PYMODSOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/inout_pymod.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/pymod/wrap_Gmsh.cpp + CACHE FILEPATH "" FORCE) + +set(MODMESH_INOUT_FILES + ${MODMESH_INOUT_HEADERS} + ${MODMESH_INOUT_SOURCES} + ${MODMESH_INOUT_PYMODHEADERS} + ${MODMESH_INOUT_PYMODSOURCES} + CACHE FILEPATH "" FORCE) +# vim: set ff=unix fenc=utf8 nobomb et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/inout/gmsh.cpp b/cpp/modmesh/inout/gmsh.cpp new file mode 100644 index 00000000..9228b003 --- /dev/null +++ b/cpp/modmesh/inout/gmsh.cpp @@ -0,0 +1,83 @@ +#include + +namespace modmesh +{ +namespace inout +{ +Gmsh::Gmsh(const std::string & data) +{ + bool meta_enter = false; + bool node_enter = false; + bool element_enter = false; + // clang-format off + std::unordered_map> keyword_handler = { + {"$MeshFormat", [this, &meta_enter]() { load_meta(); meta_enter = true; }}, + {"$Nodes", [this, &node_enter]() { load_nodes(); node_enter = true; }}, + {"$Elements", [this, &element_enter]() { load_elements(); element_enter = true; }}, + {"$PhysicalNames", [this]() { load_physical(); }}}; + // clang-format on + + stream << data; + + std::string line; + while (std::getline(stream, line)) + { + // Using a finite state machine to check the input msh file format is valid or not. + // $ is a keyword to trigger state transition. + if (line.find('$') != std::string::npos) + { + auto it = keyword_handler.find(line); + if (it != keyword_handler.end()) + { + if (isValidTransition(it->first)) + { + it->second(); + } + else + { + break; + } + } + else + { + break; + } + } + } + + // MeshFormat, Nodes and Elements section is mandatory in gmsh msh file, + // therefore need to check these sections are exist or not otherwise + // modmesh may crash during mesh processing. + if (!(meta_enter && node_enter && element_enter)) + { + throw std::invalid_argument("Incorrect msh file format."); + } +} + +std::shared_ptr Gmsh::toblock() +{ + std::shared_ptr block = StaticMesh::construct(m_eldim.max(), m_nds.shape(0), 0, m_elems.size()); + build_interior(block); + return block; +} + +void Gmsh::build_interior(const std::shared_ptr & blk) +{ + blk->cltpn().swap(m_cltpn); + blk->ndcrd().swap(m_nds); + for (size_t i = 0; i < m_elems.size(); ++i) + { + blk->clnds()(i, 0) = m_elems[i][0]; + for (size_t j = 1; j <= m_elems[i][0]; ++j) + { + blk->clnds()(i, j) = m_elems[i][j]; + } + } + blk->build_interior(true); + blk->build_boundary(); + blk->build_ghost(); +} +} /* end namespace inout */ +} /* end namespace modmesh */ + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/gmsh.hpp b/cpp/modmesh/inout/gmsh.hpp similarity index 73% rename from cpp/modmesh/io/gmsh.hpp rename to cpp/modmesh/inout/gmsh.hpp index ab78fdf5..89aa2a3f 100644 --- a/cpp/modmesh/io/gmsh.hpp +++ b/cpp/modmesh/inout/gmsh.hpp @@ -1,6 +1,6 @@ #pragma once #include -#include +#include #include #include #include @@ -11,15 +11,13 @@ namespace modmesh { -namespace IO +namespace inout { -namespace Gmsh +struct GmshElementDef { -struct ElementDef -{ - static ElementDef by_id(uint16_t id); + static GmshElementDef by_id(uint16_t id); - ElementDef(uint8_t ndim, uint16_t nnds, uint8_t mmtpn, small_vector const & mmcl) + GmshElementDef(uint8_t ndim, uint16_t nnds, uint8_t mmtpn, small_vector const & mmcl) : m_ndim(ndim) , m_nnds(nnds) , m_mmtpn(mmtpn) @@ -27,13 +25,13 @@ struct ElementDef { } - ~ElementDef() = default; + ~GmshElementDef() = default; - ElementDef() = default; - ElementDef(const ElementDef & other) = delete; - ElementDef(ElementDef && other) = delete; - ElementDef & operator=(const ElementDef & other) = delete; - ElementDef & operator=(ElementDef && other) = delete; + GmshElementDef() = default; + GmshElementDef(const GmshElementDef & other) = delete; + GmshElementDef(GmshElementDef && other) = delete; + GmshElementDef & operator=(const GmshElementDef & other) = delete; + GmshElementDef & operator=(GmshElementDef && other) = delete; uint8_t ndim() const { return m_ndim; } uint16_t nnds() const { return m_nnds; } @@ -45,56 +43,7 @@ struct ElementDef uint16_t m_nnds = 0; /* Number of nodes */ uint8_t m_mmtpn = 0; /* modmesh cell type */ small_vector m_mmcl; /* modmesh cell order */ -}; /* end struct ElementDef */ - -inline ElementDef ElementDef::by_id(uint16_t id) -{ -#define VEC(...) __VA_ARGS__ -#define MM_DECL_SWITCH_ELEMENT_TYPE(ID, NDIM, NNDS, MMTPN, MMCL) \ - case ID: return ElementDef(NDIM, NNDS, MMTPN, small_vector{MMCL}); break; - switch (id) - { - // clang-format off - // id, dim, nnodes, cell type, cell order - MM_DECL_SWITCH_ELEMENT_TYPE( 1, 1, 2, 2, VEC(0, 1)) // 2-node line - MM_DECL_SWITCH_ELEMENT_TYPE( 2, 2, 3, 4, VEC(0, 1, 2)) // 3-node triangle - MM_DECL_SWITCH_ELEMENT_TYPE( 3, 2, 4, 3, VEC(0, 1, 2, 3)) // 4-node quadrangle - MM_DECL_SWITCH_ELEMENT_TYPE( 4, 3, 4, 6, VEC(0, 1, 2, 3)) // 4-node tetrahedron - MM_DECL_SWITCH_ELEMENT_TYPE( 5, 3, 8, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 8-node hexahedron - MM_DECL_SWITCH_ELEMENT_TYPE( 6, 3, 6, 7, VEC(0, 2, 1, 3, 5, 4)) // 6-node prism - MM_DECL_SWITCH_ELEMENT_TYPE( 7, 3, 5, 8, VEC(0, 1, 2, 3, 4)) // 5-node pyramid - MM_DECL_SWITCH_ELEMENT_TYPE( 8, 1, 3, 2, VEC(0, 1)) // 3-node line - MM_DECL_SWITCH_ELEMENT_TYPE( 9, 2, 6, 4, VEC(0, 1, 2)) // 6-node triangle - MM_DECL_SWITCH_ELEMENT_TYPE(10, 2, 9, 3, VEC(0, 1, 2, 3)) // 9-node quadrangle - MM_DECL_SWITCH_ELEMENT_TYPE(11, 3, 10, 6, VEC(0, 1, 2, 3)) // 10-node tetrahedron - MM_DECL_SWITCH_ELEMENT_TYPE(12, 3, 27, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 27-node hexahedron - MM_DECL_SWITCH_ELEMENT_TYPE(13, 3, 18, 7, VEC(0, 2, 1, 3, 5, 4)) // 18-node prism - MM_DECL_SWITCH_ELEMENT_TYPE(14, 3, 14, 8, VEC(0, 1, 2, 3, 4)) // 14-node pyramid - MM_DECL_SWITCH_ELEMENT_TYPE(15, 0, 1, 1, VEC(0)) // 1-node point - MM_DECL_SWITCH_ELEMENT_TYPE(16, 2, 8, 3, VEC(0, 1, 2, 3)) // 8-node quadrangle - MM_DECL_SWITCH_ELEMENT_TYPE(17, 3, 20, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 20-node hexahedron - MM_DECL_SWITCH_ELEMENT_TYPE(18, 3, 15, 7, VEC(0, 2, 1, 3, 5, 4)) // 15-node prism - MM_DECL_SWITCH_ELEMENT_TYPE(19, 3, 13, 8, VEC(0, 1, 2, 3, 4)) // 13-node pyramid - MM_DECL_SWITCH_ELEMENT_TYPE(20, 2, 9, 4, VEC(0, 1, 2)) // 9-node incomplete triangle - MM_DECL_SWITCH_ELEMENT_TYPE(21, 2, 10, 4, VEC(0, 1, 2)) // 10-node triangle - MM_DECL_SWITCH_ELEMENT_TYPE(22, 2, 12, 4, VEC(0, 1, 2)) // 12-node incomplete triangle - MM_DECL_SWITCH_ELEMENT_TYPE(23, 2, 15, 4, VEC(0, 1, 2)) // 15-node triangle - MM_DECL_SWITCH_ELEMENT_TYPE(24, 2, 15, 4, VEC(0, 1, 2)) // 15-node incomplete triangle - MM_DECL_SWITCH_ELEMENT_TYPE(25, 2, 21, 4, VEC(0, 1, 2)) // 21-node incomplete triangle - MM_DECL_SWITCH_ELEMENT_TYPE(26, 1, 4, 2, VEC(0, 1)) // 4-node edge - MM_DECL_SWITCH_ELEMENT_TYPE(27, 1, 5, 2, VEC(0, 1)) // 5-node edge - MM_DECL_SWITCH_ELEMENT_TYPE(28, 1, 6, 2, VEC(0, 1)) // 6-node edge - MM_DECL_SWITCH_ELEMENT_TYPE(29, 3, 20, 6, VEC(0, 1, 2, 3)) // 20-node tetrahedron - MM_DECL_SWITCH_ELEMENT_TYPE(30, 3, 35, 6, VEC(0, 1, 2 ,3)) // 35-node tetrahedron - MM_DECL_SWITCH_ELEMENT_TYPE(31, 3, 56, 6, VEC(0, 1, 2, 3)) // 56-node tetrahedron - MM_DECL_SWITCH_ELEMENT_TYPE(92, 3, 64, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 64-node hexahedron - MM_DECL_SWITCH_ELEMENT_TYPE(93, 3, 125, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 125-node hexahedron - default: return ElementDef{}; break; - // clang-format on - } -#undef MM_DECL_SWITCH_ELEMENT_TYPE -#undef VEC -} +}; /* end struct GmshElementDef */ class Gmsh : public NumberBase @@ -105,62 +54,9 @@ class Gmsh using real_type = typename number_base::real_type; public: - explicit Gmsh(const std::string & file_path) - { - bool meta_enter = false, node_enter = false, element_enter = false; - // clang-format off - std::unordered_map> keyword_handler = { - {"$MeshFormat", [this, &meta_enter]() { _load_meta(); meta_enter = true; }}, - {"$Nodes", [this, &node_enter]() { _load_nodes(); node_enter = true; }}, - {"$Elements", [this, &element_enter]() { _load_elements(); element_enter = true; }}, - {"$PhysicalNames", [this]() { _load_physical(); }} - }; - - stream.open(file_path, std::ios::in); - if (!stream.good()) - { - throw std::invalid_argument(Formatter() << file_path << " path invalid."); - } + explicit Gmsh(const std::string & data); - std::string line; - while (std::getline(stream, line)) - { - // Using a finite state machine to check the input msh file format is valid or not. - // $ is a keyword to trigger state transition. - if (line.find('$') != std::string::npos) - { - auto it = keyword_handler.find(line); - if (it != keyword_handler.end()) - { - if (_isValidTransition(it->first)) - { - it->second(); - } - else - { - break; - } - } - else - { - break; - } - } - } - - // MeshFormat, Nodes and Elements section is mandatory in gmsh msh file, - // therefore need to check these sections are exist or not otherwise - // modmesh may crash during mesh processing. - if (!(meta_enter && node_enter && element_enter)) - { - throw std::invalid_argument("Incorrect msh file format."); - } - } - - ~Gmsh() - { - stream.close(); - } + ~Gmsh() = default; Gmsh() = delete; Gmsh(Gmsh const & other) = delete; @@ -181,7 +77,7 @@ class Gmsh }; // Check the finite state machine state transition is valid or not to check msh file format is correct - bool _isValidTransition(const std::string s) + bool isValidTransition(const std::string s) { if (last_fmt_state == FormatState::BEGIN) { @@ -199,13 +95,13 @@ class Gmsh return false; } - void _load_meta(void) + void load_meta(void) { std::string line; while (std::getline(stream, line) && line.find('$') == std::string::npos) { - auto tokens = _tokenize(line, ' '); + auto tokens = tokenize(line, ' '); msh_ver = std::stod(tokens[0]); // The parse only support ver 2.2 msh file. @@ -226,7 +122,7 @@ class Gmsh // TODO: PhysicalNames section parsing logic not complete yet, but without PhysicalNames section // modmesh mesh viewer still working, therefore we can finish this later. - void _load_physical(void) + void load_physical(void) { std::string line; @@ -238,7 +134,7 @@ class Gmsh } } - void _load_nodes(void) + void load_nodes(void) { std::string line; std::getline(stream, line); @@ -248,7 +144,7 @@ class Gmsh while (std::getline(stream, line) && line.find('$') == std::string::npos) { - auto tokens = _tokenize(line, ' '); + auto tokens = tokenize(line, ' '); // gmsh node index is 1-based index m_nds(std::stoul(tokens[0]) - 1, 0) = std::stod(tokens[1]); m_nds(std::stoul(tokens[0]) - 1, 1) = std::stod(tokens[2]); @@ -261,7 +157,7 @@ class Gmsh } } - void _load_elements(void) + void load_elements(void) { std::string line; std::getline(stream, line); @@ -277,11 +173,11 @@ class Gmsh while (std::getline(stream, line) && line.find('$') == std::string::npos && idx < nelement) { - auto tokens = _tokenize(line, ' '); + auto tokens = tokenize(line, ' '); // parse element type auto tpn = std::stoul(tokens[1]); - auto eldef = ElementDef::by_id(tpn); + auto eldef = GmshElementDef::by_id(tpn); // parse element tag std::vector tag; for (size_t i = 0; i < std::stoul(tokens[2]); ++i) @@ -332,7 +228,7 @@ class Gmsh } } - std::vector _tokenize(const std::string & str, const char delim) + std::vector tokenize(const std::string & str, const char delim) { std::vector output; std::stringstream ss(str); @@ -344,25 +240,9 @@ class Gmsh return output; } - void _build_interior(std::shared_ptr blk) - { - blk->cltpn().swap(m_cltpn); - blk->ndcrd().swap(m_nds); - for (size_t i = 0; i < m_elems.size(); ++i) - { - blk->clnds()(i, 0) = m_elems[i][0]; - for (size_t j = 1; j <= m_elems[i][0]; ++j) - { - - blk->clnds()(i, j) = m_elems[i][j]; - } - } - blk->build_interior(true); - blk->build_boundary(); - blk->build_ghost(); - } + void build_interior(const std::shared_ptr & blk); - std::ifstream stream; + std::stringstream stream; FormatState last_fmt_state = FormatState::BEGIN; real_type msh_ver = 0.0; @@ -384,14 +264,57 @@ class Gmsh std::unordered_map> m_elems; }; /* end class Gmsh */ -inline std::shared_ptr Gmsh::toblock(void) +inline GmshElementDef GmshElementDef::by_id(uint16_t id) { - std::shared_ptr block = StaticMesh::construct(m_eldim.max(), m_nds.shape(0), 0, m_elems.size()); - _build_interior(block); - return block; +#define VEC(...) __VA_ARGS__ +#define MM_DECL_SWITCH_ELEMENT_TYPE(ID, NDIM, NNDS, MMTPN, MMCL) \ + case ID: return GmshElementDef(NDIM, NNDS, MMTPN, small_vector{MMCL}); break; + switch (id) + { + // clang-format off + // NOLINTBEGIN(bugprone-branch-clone,-warnings-as-error) + // id, dim, nnodes, cell type, cell order + MM_DECL_SWITCH_ELEMENT_TYPE( 1, 1, 2, 2, VEC(0, 1)) // 2-node line + MM_DECL_SWITCH_ELEMENT_TYPE( 2, 2, 3, 4, VEC(0, 1, 2)) // 3-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE( 3, 2, 4, 3, VEC(0, 1, 2, 3)) // 4-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE( 4, 3, 4, 6, VEC(0, 1, 2, 3)) // 4-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE( 5, 3, 8, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 8-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE( 6, 3, 6, 7, VEC(0, 2, 1, 3, 5, 4)) // 6-node prism + MM_DECL_SWITCH_ELEMENT_TYPE( 7, 3, 5, 8, VEC(0, 1, 2, 3, 4)) // 5-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE( 8, 1, 3, 2, VEC(0, 1)) // 3-node line + MM_DECL_SWITCH_ELEMENT_TYPE( 9, 2, 6, 4, VEC(0, 1, 2)) // 6-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(10, 2, 9, 3, VEC(0, 1, 2, 3)) // 9-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE(11, 3, 10, 6, VEC(0, 1, 2, 3)) // 10-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(12, 3, 27, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 27-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(13, 3, 18, 7, VEC(0, 2, 1, 3, 5, 4)) // 18-node prism + MM_DECL_SWITCH_ELEMENT_TYPE(14, 3, 14, 8, VEC(0, 1, 2, 3, 4)) // 14-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE(15, 0, 1, 1, VEC(0)) // 1-node point + MM_DECL_SWITCH_ELEMENT_TYPE(16, 2, 8, 3, VEC(0, 1, 2, 3)) // 8-node quadrangle + MM_DECL_SWITCH_ELEMENT_TYPE(17, 3, 20, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 20-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(18, 3, 15, 7, VEC(0, 2, 1, 3, 5, 4)) // 15-node prism + MM_DECL_SWITCH_ELEMENT_TYPE(19, 3, 13, 8, VEC(0, 1, 2, 3, 4)) // 13-node pyramid + MM_DECL_SWITCH_ELEMENT_TYPE(20, 2, 9, 4, VEC(0, 1, 2)) // 9-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(21, 2, 10, 4, VEC(0, 1, 2)) // 10-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(22, 2, 12, 4, VEC(0, 1, 2)) // 12-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(23, 2, 15, 4, VEC(0, 1, 2)) // 15-node triangle + MM_DECL_SWITCH_ELEMENT_TYPE(24, 2, 15, 4, VEC(0, 1, 2)) // 15-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(25, 2, 21, 4, VEC(0, 1, 2)) // 21-node incomplete triangle + MM_DECL_SWITCH_ELEMENT_TYPE(26, 1, 4, 2, VEC(0, 1)) // 4-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(27, 1, 5, 2, VEC(0, 1)) // 5-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(28, 1, 6, 2, VEC(0, 1)) // 6-node edge + MM_DECL_SWITCH_ELEMENT_TYPE(29, 3, 20, 6, VEC(0, 1, 2, 3)) // 20-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(30, 3, 35, 6, VEC(0, 1, 2 ,3)) // 35-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(31, 3, 56, 6, VEC(0, 1, 2, 3)) // 56-node tetrahedron + MM_DECL_SWITCH_ELEMENT_TYPE(92, 3, 64, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 64-node hexahedron + MM_DECL_SWITCH_ELEMENT_TYPE(93, 3, 125, 5, VEC(0, 1, 2, 3, 4, 5, 6, 7)) // 125-node hexahedron + default: return GmshElementDef{}; break; + // NOLINTEND(bugprone-branch-clone,-warnings-as-error) + // clang-format on + } +#undef MM_DECL_SWITCH_ELEMENT_TYPE +#undef VEC } -} /* end namespace Gmsh */ -} /* end namespace IO */ +} /* end namespace inout */ } /* end namespace modmesh */ // vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/io.hpp b/cpp/modmesh/inout/inout.hpp similarity index 65% rename from cpp/modmesh/io/io.hpp rename to cpp/modmesh/inout/inout.hpp index e610f562..12a3a25d 100644 --- a/cpp/modmesh/io/io.hpp +++ b/cpp/modmesh/inout/inout.hpp @@ -1,4 +1,4 @@ #pragma once -#include +#include // vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/inout/pymod/inout_pymod.cpp b/cpp/modmesh/inout/pymod/inout_pymod.cpp new file mode 100644 index 00000000..48884647 --- /dev/null +++ b/cpp/modmesh/inout/pymod/inout_pymod.cpp @@ -0,0 +1,31 @@ +#include + +namespace modmesh +{ + +namespace python +{ + +struct inout_pymod_tag; + +template <> +OneTimeInitializer & OneTimeInitializer::me() +{ + static OneTimeInitializer instance; + return instance; +} + +void initialize_inout(pybind11::module & mod) +{ + auto initialize_impl = [](pybind11::module & mod) + { + wrap_Gmsh(mod); + }; + + OneTimeInitializer::me()(mod, initialize_impl); +} +} /* end namespace python */ + +} /* end namespace modmesh */ + +// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/pymod/io_pymod.hpp b/cpp/modmesh/inout/pymod/inout_pymod.hpp similarity index 80% rename from cpp/modmesh/io/pymod/io_pymod.hpp rename to cpp/modmesh/inout/pymod/inout_pymod.hpp index 1b46db0b..495bbc84 100644 --- a/cpp/modmesh/io/pymod/io_pymod.hpp +++ b/cpp/modmesh/inout/pymod/inout_pymod.hpp @@ -5,7 +5,7 @@ #include #include -#include +#include namespace modmesh { @@ -13,7 +13,7 @@ namespace modmesh namespace python { -void initialize_io(pybind11::module & mod); +void initialize_inout(pybind11::module & mod); void wrap_Gmsh(pybind11::module & mod); } /* end namespace python */ diff --git a/cpp/modmesh/io/pymod/wrap_Gmsh.cpp b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp similarity index 59% rename from cpp/modmesh/io/pymod/wrap_Gmsh.cpp rename to cpp/modmesh/inout/pymod/wrap_Gmsh.cpp index 5a9d62f6..828efb44 100644 --- a/cpp/modmesh/io/pymod/wrap_Gmsh.cpp +++ b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp @@ -1,4 +1,4 @@ -#include +#include #include namespace modmesh @@ -8,11 +8,11 @@ namespace python { class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapGmsh - : public WrapBase> + : public WrapBase> { public: - using base_type = WrapBase>; + using base_type = WrapBase>; using wrapped_type = typename base_type::wrapped_type; friend root_base_type; @@ -20,16 +20,16 @@ class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapGmsh protected: WrapGmsh(pybind11::module & mod, char const * pyname, char const * pydoc) - : WrapBase>(mod, pyname, pydoc) + : WrapBase>(mod, pyname, pydoc) { namespace py = pybind11; // NOLINT(misc-unused-alias-decls) (*this) .def( py::init( - [](const std::string & path) - { return std::make_shared(path); }), - py::arg("file_name")) + [](const py::bytes & data) + { return std::make_shared(data); }), + py::arg("data")) .def("toblock", &wrapped_type::toblock); ; } diff --git a/cpp/modmesh/io/CMakeLists.txt b/cpp/modmesh/io/CMakeLists.txt deleted file mode 100644 index 5d8f1e1c..00000000 --- a/cpp/modmesh/io/CMakeLists.txt +++ /dev/null @@ -1,23 +0,0 @@ - -cmake_minimum_required(VERSION 3.16) - -set(MODMESH_IO_HEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/io.hpp - ${CMAKE_CURRENT_SOURCE_DIR}/gmsh.hpp - CACHE FILEPATH "" FORCE) - -set(MODMESH_IO_PYMODHEADERS - ${CMAKE_CURRENT_SOURCE_DIR}/pymod/io_pymod.hpp - CACHE FILEPATH "" FORCE) - -set(MODMESH_IO_PYMODSOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/pymod/io_pymod.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/pymod/wrap_Gmsh.cpp - CACHE FILEPATH "" FORCE) - -set(MODMESH_IO_FILES - ${MODMESH_IO_HEADERS} - ${MODMESH_IO_PYMODHEADERS} - ${MODMESH_IO_PYMODSOURCES} - CACHE FILEPATH "" FORCE) -# vim: set ff=unix fenc=utf8 nobomb et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/io/pymod/io_pymod.cpp b/cpp/modmesh/io/pymod/io_pymod.cpp deleted file mode 100644 index 564b8412..00000000 --- a/cpp/modmesh/io/pymod/io_pymod.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include - -namespace modmesh -{ - -namespace python -{ - -struct io_pymod_tag; - -template <> -OneTimeInitializer & OneTimeInitializer::me() -{ - static OneTimeInitializer instance; - return instance; -} - -void initialize_io(pybind11::module & mod) -{ - auto initialize_impl = [](pybind11::module & mod) - { - wrap_Gmsh(mod); - }; - - OneTimeInitializer::me()(mod, initialize_impl); -} -} /* end namespace python */ - -} /* end namespace modmesh */ - -// vim: set ff=unix fenc=utf8 et sw=4 ts=4 sts=4: diff --git a/cpp/modmesh/python/module.cpp b/cpp/modmesh/python/module.cpp index 5c6f43f7..d278b076 100644 --- a/cpp/modmesh/python/module.cpp +++ b/cpp/modmesh/python/module.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #ifdef QT_CORE_LIB #include #endif // QT_CORE_LIB @@ -42,7 +42,7 @@ void initialize(pybind11::module_ mod) initialize_toggle(mod); initialize_buffer(mod); initialize_mesh(mod); - initialize_io(mod); + initialize_inout(mod); pybind11::module_ spacetime_mod = mod.def_submodule("spacetime", "spacetime"); initialize_spacetime(spacetime_mod); pybind11::module_ onedim_mod = mod.def_submodule("onedim", "onedim"); diff --git a/gtests/CMakeLists.txt b/gtests/CMakeLists.txt index 0ccf4dc8..29b1db7b 100644 --- a/gtests/CMakeLists.txt +++ b/gtests/CMakeLists.txt @@ -21,7 +21,7 @@ add_executable( test_nopython test_nopython_buffer.cpp test_nopython_modmesh.cpp - test_nopython_io.cpp + test_nopython_inout.cpp ) target_link_libraries( test_nopython diff --git a/gtests/test_nopython_io.cpp b/gtests/test_nopython_inout.cpp similarity index 71% rename from gtests/test_nopython_io.cpp rename to gtests/test_nopython_inout.cpp index de61f494..9a666479 100644 --- a/gtests/test_nopython_io.cpp +++ b/gtests/test_nopython_inout.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -11,8 +11,7 @@ std::string g_test_file_path; TEST(Gmsh_Parser, NonCellTypeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(0); + auto ele_def = modmesh::inout::GmshElementDef::by_id(0); EXPECT_EQ(ele_def.ndim(), 0); EXPECT_EQ(ele_def.nnds(), 0); EXPECT_EQ(ele_def.mmtpn(), 0); @@ -21,8 +20,7 @@ TEST(Gmsh_Parser, NonCellTypeDefinition) TEST(Gmsh_Parser, Line2NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(1); + auto ele_def = modmesh::inout::GmshElementDef::by_id(1); EXPECT_EQ(ele_def.ndim(), 1); EXPECT_EQ(ele_def.nnds(), 2); EXPECT_EQ(ele_def.mmtpn(), 2); @@ -31,8 +29,7 @@ TEST(Gmsh_Parser, Line2NodeDefinition) TEST(Gmsh_Parser, Triangle3NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(2); + auto ele_def = modmesh::inout::GmshElementDef::by_id(2); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 3); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -41,8 +38,7 @@ TEST(Gmsh_Parser, Triangle3NodeDefinition) TEST(Gmsh_Parser, Quadrangle4NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(3); + auto ele_def = modmesh::inout::GmshElementDef::by_id(3); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 4); EXPECT_EQ(ele_def.mmtpn(), 3); @@ -51,8 +47,7 @@ TEST(Gmsh_Parser, Quadrangle4NodeDefinition) TEST(Gmsh_Parser, Tetrahedron4NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(4); + auto ele_def = modmesh::inout::GmshElementDef::by_id(4); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 4); EXPECT_EQ(ele_def.mmtpn(), 6); @@ -61,8 +56,7 @@ TEST(Gmsh_Parser, Tetrahedron4NodeDefinition) TEST(Gmsh_Parser, Hexahedron8NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(5); + auto ele_def = modmesh::inout::GmshElementDef::by_id(5); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 8); EXPECT_EQ(ele_def.mmtpn(), 5); @@ -71,8 +65,7 @@ TEST(Gmsh_Parser, Hexahedron8NodeDefinition) TEST(Gmsh_Parser, Prism6NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(6); + auto ele_def = modmesh::inout::GmshElementDef::by_id(6); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 6); EXPECT_EQ(ele_def.mmtpn(), 7); @@ -81,8 +74,7 @@ TEST(Gmsh_Parser, Prism6NodeDefinition) TEST(Gmsh_Parser, Pryamid5NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(7); + auto ele_def = modmesh::inout::GmshElementDef::by_id(7); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 5); EXPECT_EQ(ele_def.mmtpn(), 8); @@ -91,8 +83,7 @@ TEST(Gmsh_Parser, Pryamid5NodeDefinition) TEST(Gmsh_Parser, Line3NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(8); + auto ele_def = modmesh::inout::GmshElementDef::by_id(8); EXPECT_EQ(ele_def.ndim(), 1); EXPECT_EQ(ele_def.nnds(), 3); EXPECT_EQ(ele_def.mmtpn(), 2); @@ -101,8 +92,7 @@ TEST(Gmsh_Parser, Line3NodeDefinition) TEST(Gmsh_Parser, Triangle6NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(9); + auto ele_def = modmesh::inout::GmshElementDef::by_id(9); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 6); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -111,8 +101,7 @@ TEST(Gmsh_Parser, Triangle6NodeDefinition) TEST(Gmsh_Parser, Quadrangle9NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(10); + auto ele_def = modmesh::inout::GmshElementDef::by_id(10); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 9); EXPECT_EQ(ele_def.mmtpn(), 3); @@ -121,8 +110,7 @@ TEST(Gmsh_Parser, Quadrangle9NodeDefinition) TEST(Gmsh_Parser, tetrahedron10NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(11); + auto ele_def = modmesh::inout::GmshElementDef::by_id(11); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 10); EXPECT_EQ(ele_def.mmtpn(), 6); @@ -131,8 +119,7 @@ TEST(Gmsh_Parser, tetrahedron10NodeDefinition) TEST(Gmsh_Parser, hexahedron27NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(12); + auto ele_def = modmesh::inout::GmshElementDef::by_id(12); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 27); EXPECT_EQ(ele_def.mmtpn(), 5); @@ -141,8 +128,7 @@ TEST(Gmsh_Parser, hexahedron27NodeDefinition) TEST(Gmsh_Parser, Prism18NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(13); + auto ele_def = modmesh::inout::GmshElementDef::by_id(13); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 18); EXPECT_EQ(ele_def.mmtpn(), 7); @@ -151,8 +137,7 @@ TEST(Gmsh_Parser, Prism18NodeDefinition) TEST(Gmsh_Parser, Pyramid14NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(14); + auto ele_def = modmesh::inout::GmshElementDef::by_id(14); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 14); EXPECT_EQ(ele_def.mmtpn(), 8); @@ -161,8 +146,7 @@ TEST(Gmsh_Parser, Pyramid14NodeDefinition) TEST(Gmsh_Parser, Point1NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(15); + auto ele_def = modmesh::inout::GmshElementDef::by_id(15); EXPECT_EQ(ele_def.ndim(), 0); EXPECT_EQ(ele_def.nnds(), 1); EXPECT_EQ(ele_def.mmtpn(), 1); @@ -171,8 +155,7 @@ TEST(Gmsh_Parser, Point1NodeDefinition) TEST(Gmsh_Parser, Quadrangle8NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(16); + auto ele_def = modmesh::inout::GmshElementDef::by_id(16); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 8); EXPECT_EQ(ele_def.mmtpn(), 3); @@ -181,8 +164,7 @@ TEST(Gmsh_Parser, Quadrangle8NodeDefinition) TEST(Gmsh_Parser, hexahedron20NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(17); + auto ele_def = modmesh::inout::GmshElementDef::by_id(17); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 20); EXPECT_EQ(ele_def.mmtpn(), 5); @@ -191,8 +173,7 @@ TEST(Gmsh_Parser, hexahedron20NodeDefinition) TEST(Gmsh_Parser, Prism15NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(18); + auto ele_def = modmesh::inout::GmshElementDef::by_id(18); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 15); EXPECT_EQ(ele_def.mmtpn(), 7); @@ -201,8 +182,7 @@ TEST(Gmsh_Parser, Prism15NodeDefinition) TEST(Gmsh_Parser, Pyramid13NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(19); + auto ele_def = modmesh::inout::GmshElementDef::by_id(19); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 13); EXPECT_EQ(ele_def.mmtpn(), 8); @@ -211,8 +191,7 @@ TEST(Gmsh_Parser, Pyramid13NodeDefinition) TEST(Gmsh_Parser, IncompleteTriangle9NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(20); + auto ele_def = modmesh::inout::GmshElementDef::by_id(20); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 9); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -221,8 +200,7 @@ TEST(Gmsh_Parser, IncompleteTriangle9NodeDefinition) TEST(Gmsh_Parser, Triangle10NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(21); + auto ele_def = modmesh::inout::GmshElementDef::by_id(21); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 10); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -231,8 +209,7 @@ TEST(Gmsh_Parser, Triangle10NodeDefinition) TEST(Gmsh_Parser, IncompleteTriangle12NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(22); + auto ele_def = modmesh::inout::GmshElementDef::by_id(22); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 12); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -241,8 +218,7 @@ TEST(Gmsh_Parser, IncompleteTriangle12NodeDefinition) TEST(Gmsh_Parser, Triangle15NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(23); + auto ele_def = modmesh::inout::GmshElementDef::by_id(23); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 15); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -251,8 +227,7 @@ TEST(Gmsh_Parser, Triangle15NodeDefinition) TEST(Gmsh_Parser, IncompleteTriangle15NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(24); + auto ele_def = modmesh::inout::GmshElementDef::by_id(24); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 15); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -261,8 +236,7 @@ TEST(Gmsh_Parser, IncompleteTriangle15NodeDefinition) TEST(Gmsh_Parser, IncompleteTriangle21NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(25); + auto ele_def = modmesh::inout::GmshElementDef::by_id(25); EXPECT_EQ(ele_def.ndim(), 2); EXPECT_EQ(ele_def.nnds(), 21); EXPECT_EQ(ele_def.mmtpn(), 4); @@ -271,8 +245,7 @@ TEST(Gmsh_Parser, IncompleteTriangle21NodeDefinition) TEST(Gmsh_Parser, Edge4NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(26); + auto ele_def = modmesh::inout::GmshElementDef::by_id(26); EXPECT_EQ(ele_def.ndim(), 1); EXPECT_EQ(ele_def.nnds(), 4); EXPECT_EQ(ele_def.mmtpn(), 2); @@ -281,8 +254,7 @@ TEST(Gmsh_Parser, Edge4NodeDefinition) TEST(Gmsh_Parser, Edge5NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(27); + auto ele_def = modmesh::inout::GmshElementDef::by_id(27); EXPECT_EQ(ele_def.ndim(), 1); EXPECT_EQ(ele_def.nnds(), 5); EXPECT_EQ(ele_def.mmtpn(), 2); @@ -291,8 +263,7 @@ TEST(Gmsh_Parser, Edge5NodeDefinition) TEST(Gmsh_Parser, Edge6NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(28); + auto ele_def = modmesh::inout::GmshElementDef::by_id(28); EXPECT_EQ(ele_def.ndim(), 1); EXPECT_EQ(ele_def.nnds(), 6); EXPECT_EQ(ele_def.mmtpn(), 2); @@ -301,8 +272,7 @@ TEST(Gmsh_Parser, Edge6NodeDefinition) TEST(Gmsh_Parser, Tetrahedron20NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(29); + auto ele_def = modmesh::inout::GmshElementDef::by_id(29); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 20); EXPECT_EQ(ele_def.mmtpn(), 6); @@ -311,8 +281,7 @@ TEST(Gmsh_Parser, Tetrahedron20NodeDefinition) TEST(Gmsh_Parser, Tetrahedron35NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(30); + auto ele_def = modmesh::inout::GmshElementDef::by_id(30); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 35); EXPECT_EQ(ele_def.mmtpn(), 6); @@ -321,8 +290,7 @@ TEST(Gmsh_Parser, Tetrahedron35NodeDefinition) TEST(Gmsh_Parser, Tetrahedron56NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(31); + auto ele_def = modmesh::inout::GmshElementDef::by_id(31); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 56); EXPECT_EQ(ele_def.mmtpn(), 6); @@ -331,8 +299,7 @@ TEST(Gmsh_Parser, Tetrahedron56NodeDefinition) TEST(Gmsh_Parser, Hexahedron64NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(92); + auto ele_def = modmesh::inout::GmshElementDef::by_id(92); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 64); EXPECT_EQ(ele_def.mmtpn(), 5); @@ -341,8 +308,7 @@ TEST(Gmsh_Parser, Hexahedron64NodeDefinition) TEST(Gmsh_Parser, Hexahedron125NodeDefinition) { - namespace gmsh = modmesh::IO::Gmsh; - auto ele_def = gmsh::ElementDef::by_id(93); + auto ele_def = modmesh::inout::GmshElementDef::by_id(93); EXPECT_EQ(ele_def.ndim(), 3); EXPECT_EQ(ele_def.nnds(), 125); EXPECT_EQ(ele_def.mmtpn(), 5); diff --git a/modmesh/app/sample_mesh.py b/modmesh/app/sample_mesh.py index f63828c9..c16a0287 100644 --- a/modmesh/app/sample_mesh.py +++ b/modmesh/app/sample_mesh.py @@ -97,7 +97,8 @@ def help_mesh_viewer(path, set_command=False): def make_mesh_viewer(path): - gm = core.Gmsh(path) + data = open(path, 'rb').read() + gm = core.Gmsh(data) mh = gm.toblock() return mh diff --git a/modmesh/core.py b/modmesh/core.py index 263df76a..317b1c03 100644 --- a/modmesh/core.py +++ b/modmesh/core.py @@ -42,6 +42,7 @@ 'TimeRegistry', 'time_registry', 'ConcreteBuffer', + 'Gmsh', 'SimpleArrayBool', 'SimpleArrayInt8', 'SimpleArrayInt16', @@ -64,7 +65,6 @@ 'METAL_BUILT', 'metal_running', 'HAS_VIEW', - 'Gmsh', ] diff --git a/tests/test_gmsh.py b/tests/test_gmsh.py index 918fb215..b66f0fdf 100644 --- a/tests/test_gmsh.py +++ b/tests/test_gmsh.py @@ -12,7 +12,10 @@ class GmshTC(unittest.TestCase): def test_gmsh_parsing(self): path = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data/gmsh_triangle.msh") - gmsh_instance = modmesh.core.Gmsh(path) + + data = open(path, 'rb').read() + + gmsh_instance = modmesh.core.Gmsh(data) blk = gmsh_instance.toblock() # Check nodes information From 8e36ed1f11329b5a1ad63d59eebb3a742192c49e Mon Sep 17 00:00:00 2001 From: gugugu Date: Thu, 27 Jul 2023 08:19:01 +0800 Subject: [PATCH 3/5] modified gmsh parser and test case for good cross-platform capability --- cpp/modmesh/inout/gmsh.cpp | 15 ++++++++++++++- tests/test_gmsh.py | 3 +-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/cpp/modmesh/inout/gmsh.cpp b/cpp/modmesh/inout/gmsh.cpp index 9228b003..afc5d902 100644 --- a/cpp/modmesh/inout/gmsh.cpp +++ b/cpp/modmesh/inout/gmsh.cpp @@ -1,5 +1,7 @@ #include - +#ifdef _WIN32 +#include +#endif // _WIN32 namespace modmesh { namespace inout @@ -17,7 +19,18 @@ Gmsh::Gmsh(const std::string & data) {"$PhysicalNames", [this]() { load_physical(); }}}; // clang-format on + // String stream on windows need to remove \r for keyword comparison. + // DOS file newline character is CRLF, std::getline default using LF as delimeter + // therefore string seperated by std::getline will contain \r, it will cause + // keyword compare failed. + // TODO: Keyword comparison can use regular expression. +#ifdef _WIN32 + std::string data_copy = data; + data_copy.erase(std::remove(data_copy.begin(), data_copy.end(), '\r'), data_copy.end()); + stream << data_copy; +#else // _WIN32 stream << data; +#endif // _WIN32 std::string line; while (std::getline(stream, line)) diff --git a/tests/test_gmsh.py b/tests/test_gmsh.py index b66f0fdf..a6b7c27a 100644 --- a/tests/test_gmsh.py +++ b/tests/test_gmsh.py @@ -11,10 +11,9 @@ class GmshTC(unittest.TestCase): def test_gmsh_parsing(self): path = os.path.join(os.path.abspath(os.path.dirname(__file__)), - "data/gmsh_triangle.msh") + "data", "gmsh_triangle.msh") data = open(path, 'rb').read() - gmsh_instance = modmesh.core.Gmsh(data) blk = gmsh_instance.toblock() From f7de14ff4eb817cc2c858ee14dfcaa4ec52f2a49 Mon Sep 17 00:00:00 2001 From: gugugu Date: Sun, 30 Jul 2023 00:52:47 +0800 Subject: [PATCH 4/5] change gmsh parser function naming style from camel case to snake case --- cpp/modmesh/inout/gmsh.cpp | 4 ++-- cpp/modmesh/inout/gmsh.hpp | 4 ++-- cpp/modmesh/inout/pymod/wrap_Gmsh.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/modmesh/inout/gmsh.cpp b/cpp/modmesh/inout/gmsh.cpp index afc5d902..b6164c71 100644 --- a/cpp/modmesh/inout/gmsh.cpp +++ b/cpp/modmesh/inout/gmsh.cpp @@ -42,7 +42,7 @@ Gmsh::Gmsh(const std::string & data) auto it = keyword_handler.find(line); if (it != keyword_handler.end()) { - if (isValidTransition(it->first)) + if (is_valid_transition(it->first)) { it->second(); } @@ -67,7 +67,7 @@ Gmsh::Gmsh(const std::string & data) } } -std::shared_ptr Gmsh::toblock() +std::shared_ptr Gmsh::to_block() { std::shared_ptr block = StaticMesh::construct(m_eldim.max(), m_nds.shape(0), 0, m_elems.size()); build_interior(block); diff --git a/cpp/modmesh/inout/gmsh.hpp b/cpp/modmesh/inout/gmsh.hpp index 89aa2a3f..2e4bea7e 100644 --- a/cpp/modmesh/inout/gmsh.hpp +++ b/cpp/modmesh/inout/gmsh.hpp @@ -64,7 +64,7 @@ class Gmsh Gmsh & operator=(Gmsh const & other) = delete; Gmsh & operator=(Gmsh && other) = delete; - std::shared_ptr toblock(void); + std::shared_ptr to_block(void); private: enum class FormatState @@ -77,7 +77,7 @@ class Gmsh }; // Check the finite state machine state transition is valid or not to check msh file format is correct - bool isValidTransition(const std::string s) + bool is_valid_transition(const std::string s) { if (last_fmt_state == FormatState::BEGIN) { diff --git a/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp index 828efb44..49c1b151 100644 --- a/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp +++ b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp @@ -30,7 +30,7 @@ class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapGmsh [](const py::bytes & data) { return std::make_shared(data); }), py::arg("data")) - .def("toblock", &wrapped_type::toblock); + .def("toblock", &wrapped_type::to_block); ; } From becebaed18a3f06ef9029b6c8c3a2dd1bcb1888d Mon Sep 17 00:00:00 2001 From: gugugu Date: Sun, 30 Jul 2023 11:40:12 +0800 Subject: [PATCH 5/5] align the Gmsh python api names with c++ --- cpp/modmesh/inout/pymod/wrap_Gmsh.cpp | 2 +- modmesh/app/sample_mesh.py | 2 +- tests/test_gmsh.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp index 49c1b151..d5e54099 100644 --- a/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp +++ b/cpp/modmesh/inout/pymod/wrap_Gmsh.cpp @@ -30,7 +30,7 @@ class MODMESH_PYTHON_WRAPPER_VISIBILITY WrapGmsh [](const py::bytes & data) { return std::make_shared(data); }), py::arg("data")) - .def("toblock", &wrapped_type::to_block); + .def("to_block", &wrapped_type::to_block); ; } diff --git a/modmesh/app/sample_mesh.py b/modmesh/app/sample_mesh.py index c16a0287..abfd6bc0 100644 --- a/modmesh/app/sample_mesh.py +++ b/modmesh/app/sample_mesh.py @@ -99,7 +99,7 @@ def help_mesh_viewer(path, set_command=False): def make_mesh_viewer(path): data = open(path, 'rb').read() gm = core.Gmsh(data) - mh = gm.toblock() + mh = gm.to_block() return mh diff --git a/tests/test_gmsh.py b/tests/test_gmsh.py index a6b7c27a..2e95c34a 100644 --- a/tests/test_gmsh.py +++ b/tests/test_gmsh.py @@ -15,7 +15,7 @@ def test_gmsh_parsing(self): data = open(path, 'rb').read() gmsh_instance = modmesh.core.Gmsh(data) - blk = gmsh_instance.toblock() + blk = gmsh_instance.to_block() # Check nodes information self.assertEqual(blk.nnode, 4)