69 bool MshReader::load(
const std::string &path, Eigen::MatrixXd &vertices, Eigen::MatrixXi &cells, std::vector<std::vector<int>> &elements, std::vector<std::vector<double>> &weights, std::vector<int> &body_ids, std::vector<std::vector<int>> &boundary_elements, std::vector<int> &boundary_ids, std::vector<std::string> &node_data_name, std::vector<std::vector<double>> &node_data)
71 if (!std::filesystem::exists(path))
73 logger().error(
"Msh file does not exist: {}", path);
80 spec = mshio::load_msh(path);
82 catch (
const std::exception &err)
84 logger().error(
"{}", err.what());
89 logger().error(
"Unknown error while reading MSH file: {}", path);
93 const auto &nodes = spec.nodes;
94 const auto &els = spec.elements;
95 const int n_vertices = nodes.num_nodes;
96 const int max_tag = nodes.max_node_tag;
99 assert(els.entity_blocks.size() > 0);
100 for (
const auto &e : els.entity_blocks)
102 dim = std::max(dim, e.entity_dim);
104 assert(dim == 2 || dim == 3);
106 vertices.resize(n_vertices, dim);
107 std::vector<int> tag_to_index = std::vector<int>(max_tag + 1, -1);
108 if (n_vertices != max_tag)
109 logger().warn(
"MSH file contains more node tags than nodes, condensing nodes which will break input node ordering.");
112 for (
const auto &n : nodes.entity_blocks)
114 for (
int i = 0; i < n.num_nodes_in_block * 3; i += 3)
116 const int node_id = n_vertices != max_tag ? (index++) : (n.tags[i / 3] - 1);
119 vertices.row(node_id) << n.data[i], n.data[i + 1];
121 vertices.row(node_id) << n.data[i], n.data[i + 1], n.data[i + 2];
123 assert(n.tags[i / 3] < tag_to_index.size());
124 tag_to_index[n.tags[i / 3]] = node_id;
130 for (
const auto &e : els.entity_blocks)
132 if (e.entity_dim != dim)
134 const int type = e.element_type;
136 if (type == 2 || type == 9 || type == 21 || type == 23 || type == 25)
138 cells_cols = std::max(cells_cols, 3);
139 num_els += e.num_elements_in_block;
141 else if (type == 3 || type == 10)
143 cells_cols = std::max(cells_cols, 4);
144 num_els += e.num_elements_in_block;
146 else if (type == 4 || type == 11 || type == 29 || type == 30 || type == 31)
148 cells_cols = std::max(cells_cols, 4);
149 num_els += e.num_elements_in_block;
151 else if (type == 5 || type == 12)
153 cells_cols = std::max(cells_cols, 8);
154 num_els += e.num_elements_in_block;
158 cells_cols = std::max(cells_cols, 6);
159 num_els += e.num_elements_in_block;
163 cells_cols = std::max(cells_cols, 5);
164 num_els += e.num_elements_in_block;
167 assert(cells_cols > 0);
169 std::unordered_map<int, int> entity_tag_to_physical_tag;
170 std::unordered_map<int, int> boundary_entity_tag_to_physical_tag;
182 boundary_elements.clear();
183 boundary_ids.clear();
184 for (
const auto &e : els.entity_blocks)
186 if (e.entity_dim != dim - 1)
189 const auto physical_tag = boundary_entity_tag_to_physical_tag.find(e.entity_tag);
190 if (physical_tag == boundary_entity_tag_to_physical_tag.end() || physical_tag->second == 0)
193 const int n_corners = num_corner_nodes(e.element_type);
196 logger().warn(
"Ignoring unsupported tagged codimension-one Gmsh element type {}.", e.element_type);
200 const size_t n_nodes = mshio::nodes_per_element(e.element_type);
201 for (
int i = 0; i < e.data.size(); i += n_nodes + 1)
203 std::vector<int> corners(n_corners);
204 for (
int j = 0; j < n_corners; ++j)
206 const int node_tag = e.data[i + j + 1];
207 assert(node_tag >= 0 && node_tag < tag_to_index.size());
208 corners[j] = tag_to_index[node_tag];
209 assert(corners[j] >= 0 && corners[j] < n_vertices);
211 boundary_elements.emplace_back(std::move(corners));
212 boundary_ids.push_back(physical_tag->second);
216 cells.resize(num_els, cells_cols);
217 cells.setConstant(-1);
218 body_ids.resize(num_els);
219 elements.resize(num_els);
220 weights.resize(num_els);
222 for (
const auto &e : els.entity_blocks)
224 if (e.entity_dim != dim)
226 const int type = e.element_type;
227 if (type == 2 || type == 9 || type == 21 || type == 23 || type == 25 || type == 3 || type == 10 || type == 4 || type == 11 || type == 29 || type == 30 || type == 31 || type == 5 || type == 12 || type == 6 || type == 7)
229 const size_t n_nodes = mshio::nodes_per_element(type);
230 int local_cells_cols = -1;
232 if (type == 2 || type == 9 || type == 21 || type == 23 || type == 25)
233 local_cells_cols = 3;
234 else if (type == 3 || type == 10)
235 local_cells_cols = 4;
236 else if (type == 4 || type == 11 || type == 29 || type == 30 || type == 31)
237 local_cells_cols = 4;
238 else if (type == 5 || type == 12)
239 local_cells_cols = 8;
241 local_cells_cols = 6;
243 local_cells_cols = 5;
245 for (
int i = 0; i < e.data.size(); i += (n_nodes + 1))
248 for (
int j = i + 1; j <= i + local_cells_cols; ++j)
250 const int v_index = tag_to_index[e.data[j]];
251 assert(v_index < n_vertices);
252 cells(cell_index, index++) = v_index;
255 for (
int j = i + 1; j < i + 1 + n_nodes; ++j)
257 const int v_index = tag_to_index[e.data[j]];
258 assert(v_index < n_vertices);
259 elements[cell_index].push_back(v_index);
262 const auto &it = entity_tag_to_physical_tag.find(e.entity_tag);
263 body_ids[cell_index] =
264 it != entity_tag_to_physical_tag.end() ? it->second : 0;
271 node_data.resize(spec.node_data.size());
273 for (
const auto &data : spec.node_data)
275 for (
const auto &str : data.header.string_tags)
276 node_data_name.push_back(str);
278 for (
const auto &entry : data.entries)
279 for (
const auto &d : entry.data)
280 node_data[i].push_back(d);