Wildmeshing Toolkit
Loading...
Searching...
No Matches
io.hpp
1#pragma once
2
3#include <functional>
4#include <iostream>
5#include <optional>
6#include <string>
7
8#include <mshio/mshio.h>
9#include <wmtk/Types.hpp>
10
11#include "Logger.hpp"
12
13namespace wmtk {
14
23{
24public:
25 template <typename Fn>
26 void add_edge_vertices(size_t num_vertices, const Fn& get_vertex_cb)
27 {
28 add_vertices<1>(num_vertices, get_vertex_cb);
29 }
30
34 template <typename Fn>
35 void add_face_vertices(size_t num_vertices, const Fn& get_vertex_cb)
36 {
37 add_vertices<2>(num_vertices, get_vertex_cb);
38 }
39
40 template <typename Fn>
41 void add_tet_vertices(size_t num_vertices, const Fn& get_vertex_cb)
42 {
43 add_vertices<3>(num_vertices, get_vertex_cb);
44 }
45
46 void add_empty_vertices(int dim)
47 {
48 if (dim < 1 || dim > 3) {
49 log_and_throw_error("Only 1,2,3D elements are supported!");
50 }
51
52 if (m_spec.nodes.entity_blocks.empty()) {
53 log_and_throw_error("First vertex block cannot be empty.");
54 }
55
56 mshio::NodeBlock block;
57 block.num_nodes_in_block = 0;
58 block.entity_dim = dim;
59 block.entity_tag = (int)m_spec.nodes.num_entity_blocks + 1;
60
61 m_spec.nodes.num_entity_blocks += 1;
62 m_spec.nodes.entity_blocks.push_back(std::move(block));
63 }
64
65 void add_edge_vertices() { add_empty_vertices(1); }
66 void add_face_vertices() { add_empty_vertices(2); }
67 void add_tet_vertices() { add_empty_vertices(3); }
68
69 template <typename Fn>
70 void add_edges(size_t num_edges, const Fn& get_edge_cb)
71 {
72 add_simplex_elements<1>(num_edges, get_edge_cb);
73 }
74
83 template <typename Fn>
84 void add_faces(size_t num_faces, const Fn& get_face_cb)
85 {
86 add_simplex_elements<2>(num_faces, get_face_cb);
87 }
88
89 template <typename Fn>
90 void add_tets(size_t num_tets, const Fn& get_tet_cb)
91 {
92 add_simplex_elements<3>(num_tets, get_tet_cb);
93 }
94
95 template <int NUM_FIELDS, typename Fn>
96 void add_edge_vertex_attribute(const std::string& name, const Fn& get_attribute_cb)
97 {
98 add_vertex_attribute<NUM_FIELDS, 1>(name, get_attribute_cb);
99 }
100
101 template <int NUM_FIELDS, typename Fn>
102 void add_face_vertex_attribute(const std::string& name, const Fn& get_attribute_cb)
103 {
104 add_vertex_attribute<NUM_FIELDS, 2>(name, get_attribute_cb);
105 }
106
107 template <int NUM_FIELDS, typename Fn>
108 void add_tet_vertex_attribute(const std::string& name, const Fn& get_attribute_cb)
109 {
110 add_vertex_attribute<NUM_FIELDS, 3>(name, get_attribute_cb);
111 }
112
113 template <int NUM_FIELDS, typename Fn>
114 void add_edge_attribute(const std::string& name, const Fn& get_attribute_cb)
115 {
116 add_element_attribute<NUM_FIELDS, 1>(name, get_attribute_cb);
117 }
118
119 template <int NUM_FIELDS, typename Fn>
120 void add_face_attribute(const std::string& name, const Fn& get_attribute_cb)
121 {
122 add_element_attribute<NUM_FIELDS, 2>(name, get_attribute_cb);
123 }
124
125 template <int NUM_FIELDS, typename Fn>
126 void add_tet_attribute(const std::string& name, const Fn& get_attribute_cb)
127 {
128 add_element_attribute<NUM_FIELDS, 3>(name, get_attribute_cb);
129 }
130
134 void add_physical_group(const std::string& name)
135 {
136 auto& entities = m_spec.entities;
137
138 const auto& vertex_block = m_spec.nodes.entity_blocks.back();
139 const int tag = vertex_block.entity_tag;
140 const int dim = vertex_block.entity_dim;
141
142 double min_x = std::numeric_limits<double>::max();
143 double min_y = std::numeric_limits<double>::max();
144 double min_z = std::numeric_limits<double>::max();
145 double max_x = std::numeric_limits<double>::lowest();
146 double max_y = std::numeric_limits<double>::lowest();
147 double max_z = std::numeric_limits<double>::lowest();
148 for (size_t i = 0; i < vertex_block.num_nodes_in_block; ++i) {
149 min_x = std::min(vertex_block.data[3 * i + 0], min_x);
150 min_y = std::min(vertex_block.data[3 * i + 1], min_y);
151 min_z = std::min(vertex_block.data[3 * i + 2], min_z);
152 max_x = std::max(vertex_block.data[3 * i + 0], max_x);
153 max_y = std::max(vertex_block.data[3 * i + 1], max_y);
154 max_z = std::max(vertex_block.data[3 * i + 2], max_z);
155 }
156
157 mshio::PhysicalGroup ph;
158 ph.dim = dim;
159 ph.tag = tag;
160 ph.name = name;
161 m_spec.physical_groups.emplace_back(ph);
162
163 switch (dim) {
164 case 0: {
165 mshio::PointEntity e{tag, min_x, min_y, min_z};
166 e.physical_group_tags.push_back(tag);
167 entities.points.push_back(e);
168 break;
169 }
170 case 1: {
171 mshio::CurveEntity e{tag, min_x, min_y, min_z, max_x, max_y, max_z};
172 e.physical_group_tags.push_back(tag);
173 entities.curves.push_back(e);
174 break;
175 }
176 case 2: {
177 mshio::SurfaceEntity e{tag, min_x, min_y, min_z, max_x, max_y, max_z};
178 e.physical_group_tags.push_back(tag);
179 entities.surfaces.push_back(e);
180 break;
181 }
182 case 3: {
183 mshio::VolumeEntity e{tag, min_x, min_y, min_z, max_x, max_y, max_z};
184 e.physical_group_tags.push_back(tag);
185 entities.volumes.push_back(e);
186 break;
187 }
188 default: log_and_throw_error("Entity of dim {} cannot be written to .msh.");
189 }
190 }
191
192 inline size_t get_num_edge_vertices() const { return get_num_vertices(1); }
193
194 inline size_t get_num_face_vertices() const { return get_num_vertices(2); }
195
196 inline size_t get_num_tet_vertices() const { return get_num_vertices(3); }
197
198 inline size_t get_num_edges() const { return get_num_simplex_elements(1); }
199
200 inline size_t get_num_faces() const { return get_num_simplex_elements(2); }
201
202 inline size_t get_num_tets() const { return get_num_simplex_elements(3); }
203
204 template <typename Fn>
205 void extract_tet_vertices(Fn&& set_vertex_cb) const
206 {
207 return extract_vertices(3, std::forward<Fn>(set_vertex_cb));
208 }
209
210 template <typename Fn>
211 void extract_face_vertices(Fn&& set_vertex_cb) const
212 {
213 return extract_vertices(2, std::forward<Fn>(set_vertex_cb));
214 }
215
216 template <typename Fn>
217 void extract_edge_vertices(Fn&& set_vertex_cb) const
218 {
219 extract_vertices(1, std::forward<Fn>(set_vertex_cb));
220 }
221
222 template <typename Fn>
223 void extract_edges(Fn&& set_edge_cb) const
224 {
225 extract_simplex_elements<1>(std::forward<Fn>(set_edge_cb));
226 }
227
228 template <typename Fn>
229 void extract_faces(Fn&& set_face_cb) const
230 {
231 extract_simplex_elements<2>(std::forward<Fn>(set_face_cb));
232 }
233
234 template <typename Fn>
235 void extract_tets(Fn&& set_tet_cb) const
236 {
237 extract_simplex_elements<3>(std::forward<Fn>(set_tet_cb));
238 }
239
240 std::vector<std::string> get_edge_vertex_attribute_names() const
241 {
242 return get_vertex_attribute_names<1>();
243 }
244
245 std::vector<std::string> get_face_vertex_attribute_names() const
246 {
247 return get_vertex_attribute_names<2>();
248 }
249
250 std::vector<std::string> get_tet_vertex_attribute_names() const
251 {
252 return get_vertex_attribute_names<3>();
253 }
254
255 std::vector<std::string> get_edge_attribute_names() const
256 {
257 return get_element_attribute_names<1>();
258 }
259
260 std::vector<std::string> get_face_attribute_names() const
261 {
262 return get_element_attribute_names<2>();
263 }
264
265 std::vector<std::string> get_tet_attribute_names() const
266 {
267 return get_element_attribute_names<3>();
268 }
269
270 std::vector<std::string> get_all_element_attribute_names() const
271 {
272 std::vector<std::string> attr_names;
273 attr_names.reserve(m_spec.element_data.size());
274 for (const auto& data : m_spec.element_data) {
275 attr_names.push_back(data.header.string_tags.front());
276 }
277 return attr_names;
278 }
279
280 template <typename Fn>
281 void extract_edge_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
282 {
283 extract_vertex_attribute<1>(attr_name, std::forward<Fn>(set_attr));
284 }
285
286 template <typename Fn>
287 void extract_face_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
288 {
289 extract_vertex_attribute<2>(attr_name, std::forward<Fn>(set_attr));
290 }
291
292 template <typename Fn>
293 void extract_tet_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
294 {
295 extract_vertex_attribute<3>(attr_name, std::forward<Fn>(set_attr));
296 }
297
298 template <typename Fn>
299 void extract_edge_attribute(const std::string& attr_name, Fn&& set_attr)
300 {
301 extract_element_attribute<1>(attr_name, std::forward<Fn>(set_attr));
302 }
303
304 template <typename Fn>
305 void extract_face_attribute(const std::string& attr_name, Fn&& set_attr)
306 {
307 extract_element_attribute<2>(attr_name, std::forward<Fn>(set_attr));
308 }
309
310 template <typename Fn>
311 void extract_tet_attribute(const std::string& attr_name, Fn&& set_attr)
312 {
313 extract_element_attribute<3>(attr_name, std::forward<Fn>(set_attr));
314 }
315
319 std::optional<mshio::PhysicalGroup> get_physical_group_by_name(const std::string& name)
320 {
321 for (const mshio::PhysicalGroup& ph : m_spec.physical_groups) {
322 if (ph.name == name) {
323 return ph;
324 }
325 }
326 return {};
327 }
328
329 void get_VF(const int& dim, const int& tag, MatrixXd& V, MatrixXi& F)
330 {
331 assert(dim > 0 && tag > 0);
332
333 const size_t n_V = get_num_vertices(dim, tag);
334 const size_t n_F = get_num_simplex_elements(dim, tag);
335
336 if (n_V > 0) {
337 V.resize(n_V, 3);
338 extract_vertices(dim, tag, [&V](size_t i, double x, double y, double z) {
339 V.row(i) = Vector3d(x, y, z);
340 });
341 }
342 if (n_F > 0) {
343 F.resize(n_F, dim + 1);
344 switch (dim) {
345 case 1:
346 extract_simplex_elements<1>([&F](size_t i, size_t v0, size_t v1) {
347 F.row(i) = Vector2i((int)v0, (int)v1);
348 });
349 break;
350 case 2:
351 extract_simplex_elements<2>([&F](size_t i, size_t v0, size_t v1, size_t v2) {
352 F.row(i) = Vector3i((int)v0, (int)v1, (int)v2);
353 });
354 break;
355 case 3:
356 extract_simplex_elements<3>(
357 [&F](size_t i, size_t v0, size_t v1, size_t v2, size_t v3) {
358 F.row(i) = Vector4i((int)v0, (int)v1, (int)v2, (int)v3);
359 });
360 break;
361 default: log_and_throw_error("Cannot extract elements for dimension {}", dim);
362 }
363 }
364 }
365
366 void save(const std::string& filename, bool binary = true)
367 {
368 m_spec.mesh_format.file_type = binary;
369 mshio::validate_spec(m_spec);
370 mshio::save_msh(filename, m_spec);
371 }
372
373 void save(std::ostream& out, bool binary = true)
374 {
375 m_spec.mesh_format.file_type = binary;
376 mshio::validate_spec(m_spec);
377 mshio::save_msh(out, m_spec);
378 }
379
380 void load(const std::string& filename) { m_spec = mshio::load_msh(filename); }
381
382 void load(std::istream& in) { m_spec = mshio::load_msh(in); }
383
384private:
385 template <int DIM, typename Fn>
386 void add_vertices(size_t num_vertices, const Fn& get_vertex_cb)
387 {
388 static_assert(DIM >= 1 && DIM <= 3, "Only 1,2,3D elements are supported!");
389 if (num_vertices == 0) {
390 logger().trace("Adding empty vertex block.");
391 }
392 mshio::NodeBlock block;
393 block.num_nodes_in_block = num_vertices;
394 block.tags.reserve(num_vertices);
395 block.data.reserve(num_vertices * 3);
396 block.entity_dim = DIM;
397 block.entity_tag = (int)m_spec.nodes.num_entity_blocks + 1;
398
399 const size_t tag_offset = m_spec.nodes.max_node_tag;
400 for (size_t i = 0; i < num_vertices; i++) {
401 const auto& v = get_vertex_cb(i);
402 block.tags.push_back(tag_offset + i + 1);
403 block.data.push_back(v[0]);
404 block.data.push_back(v[1]);
405 block.data.push_back(v[2]);
406 }
407
408 m_spec.nodes.num_entity_blocks += 1;
409 m_spec.nodes.num_nodes += num_vertices;
410 m_spec.nodes.min_node_tag = 1;
411 m_spec.nodes.max_node_tag += num_vertices;
412 m_spec.nodes.entity_blocks.push_back(std::move(block));
413 }
414
415 template <int DIM, typename Fn>
416 void add_simplex_elements(size_t num_elements, const Fn& get_element_cb)
417 {
418 static_assert(
419 DIM == 1 || DIM == 2 || DIM == 3,
420 "Only 1,2,3D simplex elements are supported");
421 if (num_elements == 0) return;
422
423 if (m_spec.nodes.num_nodes == 0) {
424 log_and_throw_error("Please add a vertex block before adding elements.");
425 }
426 const auto& vertex_block = m_spec.nodes.entity_blocks.back();
427 // assert(!vertex_block.tags.empty());
428 if (vertex_block.entity_dim != DIM) {
429 log_and_throw_error(
430 "It seems the last added vertex block has different dimension "
431 "than the elements you want to add.");
432 }
433
434 mshio::ElementBlock block;
435 block.entity_dim = DIM;
436 block.entity_tag = vertex_block.entity_tag;
437 if constexpr (DIM == 1) {
438 block.element_type = 1; // 2-node line.
439 } else if constexpr (DIM == 2) {
440 block.element_type = 2; // 3-node triangle.
441 } else {
442 block.element_type = 4; // 4-node tet.
443 }
444 block.num_elements_in_block = num_elements;
445
446 const size_t vertex_offset =
447 vertex_block.num_nodes_in_block == 0 ? 0 : vertex_block.tags.front() - 1;
448 if (vertex_offset == 0) {
449 logger().trace(
450 "Do not offset vertex IDs for this element block as vertex block was empty");
451 }
452
453 const size_t tag_offset = m_spec.elements.max_element_tag;
454 block.data.reserve(num_elements * (DIM + 2));
455 for (size_t i = 0; i < num_elements; i++) {
456 const auto& e = get_element_cb(i);
457 block.data.push_back(tag_offset + i + 1); // element tag.
458 for (size_t j = 0; j <= DIM; j++) {
459 block.data.push_back(vertex_offset + e[j] + 1);
460 }
461 }
462
463 m_spec.elements.num_entity_blocks++;
464 m_spec.elements.num_elements += num_elements;
465 m_spec.elements.min_element_tag = 1;
466 m_spec.elements.max_element_tag += num_elements;
467 m_spec.elements.entity_blocks.push_back(std::move(block));
468 }
469
470 template <int NUM_FIELDS, int ELEMENT_DIM, typename Fn>
471 void add_vertex_attribute(const std::string& name, const Fn& get_attribute_cb)
472 {
473 static_assert(
474 NUM_FIELDS == 1 || NUM_FIELDS == 3 || NUM_FIELDS == 9,
475 "Only scalar, vector and tensor fields are supported as attribute!");
476 if (m_spec.nodes.entity_blocks.empty()) {
477 throw std::runtime_error("Please add vertices before adding vertex attributes.");
478 }
479 const auto& vertex_block = m_spec.nodes.entity_blocks.back();
480 const size_t num_vertices = vertex_block.num_nodes_in_block;
481 assert(num_vertices != 0);
482
483 if (vertex_block.entity_dim != ELEMENT_DIM) {
484 throw std::runtime_error(
485 "It seems the last added vertex block has different dimension "
486 "from the vertex attribute you want to add.");
487 }
488
489 mshio::Data data;
490 data.header.string_tags = {name};
491 data.header.real_tags = {0.0};
492 data.header.int_tags = {0, NUM_FIELDS, int(num_vertices), 0, ELEMENT_DIM};
493
494 data.entries.resize(num_vertices);
495 for (size_t i = 0; i < num_vertices; i++) {
496 auto& entry = data.entries[i];
497 entry.tag = vertex_block.tags[i];
498 entry.data.reserve(NUM_FIELDS);
499 const auto& attr = get_attribute_cb(i);
500 if constexpr (NUM_FIELDS == 1) {
501 entry.data.push_back(attr);
502 } else {
503 for (size_t j = 0; j < NUM_FIELDS; j++) {
504 entry.data.push_back(attr[j]);
505 }
506 }
507 }
508
509 m_spec.node_data.push_back(std::move(data));
510 }
511
512 template <int NUM_FIELDS, int ELEMENT_DIM, typename Fn>
513 void add_element_attribute(const std::string& name, const Fn& get_attribute_cb)
514 {
515 static_assert(
516 NUM_FIELDS == 1 || NUM_FIELDS == 3 || NUM_FIELDS == 9,
517 "Only scalar, vector and tensor fields are supported as attribute!");
518 if (m_spec.elements.entity_blocks.empty()) {
519 throw std::runtime_error("Please add elements before adding element attributes!");
520 }
521 const auto& elem_block = m_spec.elements.entity_blocks.back();
522 if (elem_block.entity_dim != ELEMENT_DIM) {
523 throw std::runtime_error(
524 "It seems the last added element block has different dimension "
525 "than the element attribute you want to add.");
526 }
527 const size_t num_elements = elem_block.num_elements_in_block;
528
529 mshio::Data data;
530 data.header.string_tags = {name};
531 data.header.real_tags = {0.0};
532 data.header.int_tags = {0, NUM_FIELDS, int(num_elements), 0, ELEMENT_DIM};
533
534 data.entries.resize(num_elements);
535 for (size_t i = 0; i < num_elements; i++) {
536 auto& entry = data.entries[i];
537 entry.tag = elem_block.data[i * (ELEMENT_DIM + 2)];
538 entry.data.reserve(NUM_FIELDS);
539 const auto& attr = get_attribute_cb(i);
540 if constexpr (NUM_FIELDS == 1) {
541 entry.data.push_back(attr);
542 } else {
543 for (size_t j = 0; j < NUM_FIELDS; j++) {
544 entry.data.push_back(attr[j]);
545 }
546 }
547 }
548
549 m_spec.element_data.push_back(std::move(data));
550 }
551
552 const mshio::NodeBlock* get_vertex_block(const int dim) const
553 {
554 for (const auto& block : m_spec.nodes.entity_blocks) {
555 if (block.entity_dim == dim) {
556 return &block;
557 }
558 }
559 return nullptr;
560 }
561
562 const mshio::NodeBlock* get_vertex_block(const int dim, const int tag) const
563 {
564 for (const auto& block : m_spec.nodes.entity_blocks) {
565 if (block.entity_dim == dim && block.entity_tag == tag) {
566 return &block;
567 }
568 }
569 return nullptr;
570 }
571
572 const mshio::ElementBlock* get_simplex_element_block(const int dim) const
573 {
574 for (const auto& block : m_spec.elements.entity_blocks) {
575 if (block.entity_dim == dim) {
576 return &block;
577 }
578 }
579 return nullptr;
580 }
581
582 const mshio::ElementBlock* get_simplex_element_block(const int dim, const int tag) const
583 {
584 for (const auto& block : m_spec.elements.entity_blocks) {
585 if (block.entity_dim == dim && block.entity_tag == tag) {
586 return &block;
587 }
588 }
589 return nullptr;
590 }
591
592 size_t get_num_vertices(const int dim) const
593 {
594 const auto* block = get_vertex_block(dim);
595 if (block != nullptr) {
596 return block->num_nodes_in_block;
597 } else {
598 return 0;
599 }
600 }
601
602 size_t get_num_vertices(const int dim, const int tag) const
603 {
604 const auto* block = get_vertex_block(dim, tag);
605 if (block != nullptr) {
606 return block->num_nodes_in_block;
607 } else {
608 return 0;
609 }
610 }
611
612 size_t get_num_simplex_elements(const int dim) const
613 {
614 const auto* block = get_simplex_element_block(dim);
615 if (block != nullptr) {
616 return block->num_elements_in_block;
617 } else {
618 return 0;
619 }
620 }
621
622 size_t get_num_simplex_elements(const int dim, const int tag) const
623 {
624 const auto* block = get_simplex_element_block(dim, tag);
625 if (block != nullptr) {
626 return block->num_elements_in_block;
627 } else {
628 return 0;
629 }
630 }
631
632 template <typename Fn>
633 void extract_vertices(const int dim, Fn&& set_vertex_cb) const
634 {
635 const auto* block = get_vertex_block(dim);
636 if (block == nullptr) return;
637
638 const size_t num_vertices = block->num_nodes_in_block;
639 if (num_vertices == 0) return;
640
641 const size_t tag_offset = block->tags.front();
642 for (size_t i = 0; i < num_vertices; i++) {
643 size_t tag = block->tags[i] - tag_offset;
644 set_vertex_cb(tag, block->data[i * 3], block->data[i * 3 + 1], block->data[i * 3 + 2]);
645 }
646 }
647
648 template <typename Fn>
649 void extract_vertices(const int dim, const int tag, Fn&& set_vertex_cb) const
650 {
651 const auto* block = get_vertex_block(dim, tag);
652 if (block == nullptr) return;
653
654 const size_t num_vertices = block->num_nodes_in_block;
655 if (num_vertices == 0) return;
656
657 const size_t tag_offset = block->tags.front();
658 for (size_t i = 0; i < num_vertices; i++) {
659 size_t tag = block->tags[i] - tag_offset;
660 set_vertex_cb(tag, block->data[i * 3], block->data[i * 3 + 1], block->data[i * 3 + 2]);
661 }
662 }
663
664 template <int DIM, typename Fn>
665 void extract_simplex_elements(Fn&& set_element_cb) const
666 {
667 const auto* vertex_block = get_vertex_block(DIM);
668 const auto* element_block = get_simplex_element_block(DIM);
669 if (element_block == nullptr) return;
670 assert(vertex_block != nullptr);
671
672 const size_t num_elements = element_block->num_elements_in_block;
673 if (num_elements == 0) return;
674 assert(vertex_block->num_nodes_in_block != 0);
675
676 const size_t vert_tag_offset = vertex_block->tags.front();
677 const size_t elem_tag_offset = element_block->data.front();
678 for (size_t i = 0; i < num_elements; i++) {
679 const size_t tag = element_block->data[i * (DIM + 2)] - elem_tag_offset;
680 assert(tag < num_elements);
681 const auto* element = element_block->data.data() + i * (DIM + 2) + 1;
682
683 if constexpr (DIM == 1) {
684 set_element_cb(tag, element[0] - vert_tag_offset, element[1] - vert_tag_offset);
685 } else if constexpr (DIM == 2) {
686 set_element_cb(
687 tag,
688 element[0] - vert_tag_offset,
689 element[1] - vert_tag_offset,
690 element[2] - vert_tag_offset);
691 } else if constexpr (DIM == 3) {
692 set_element_cb(
693 tag,
694 element[0] - vert_tag_offset,
695 element[1] - vert_tag_offset,
696 element[2] - vert_tag_offset,
697 element[3] - vert_tag_offset);
698 }
699 }
700 }
701
702 template <int DIM>
703 std::vector<std::string> get_vertex_attribute_names() const
704 {
705 std::vector<std::string> attr_names;
706 attr_names.reserve(m_spec.node_data.size());
707 for (const auto& data : m_spec.node_data) {
708 const auto& int_tags = data.header.int_tags;
709 if (int_tags.size() >= 5 && int_tags[4] == DIM) {
710 attr_names.push_back(data.header.string_tags.front());
711 }
712 }
713 return attr_names;
714 }
715
716 template <int DIM>
717 std::vector<std::string> get_element_attribute_names() const
718 {
719 std::vector<std::string> attr_names;
720 attr_names.reserve(m_spec.element_data.size());
721 for (const auto& data : m_spec.element_data) {
722 const auto& int_tags = data.header.int_tags;
723 if (int_tags.size() >= 5 && int_tags[4] == DIM) {
724 attr_names.push_back(data.header.string_tags.front());
725 }
726 }
727 return attr_names;
728 }
729
730 template <int DIM, typename Fn>
731 void extract_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
732 {
733 const auto* vertex_block = get_vertex_block(DIM);
734 const size_t tag_offset = vertex_block->tags.front();
735 for (const auto& data : m_spec.node_data) {
736 if (data.header.string_tags.front() != attr_name) continue;
737 if (data.header.int_tags.size() >= 5 && data.header.int_tags[4] != DIM) {
738 log_and_throw_error("Attribute " + attr_name + " is of the wrong DIM.");
739 }
740
741 for (const auto& entry : data.entries) {
742 const size_t tag = entry.tag - tag_offset;
743 assert(tag < vertex_block->num_nodes_in_block);
744 set_attr(tag, entry.data);
745 }
746 }
747 }
748
749 template <int DIM, typename Fn>
750 void extract_element_attribute(const std::string& attr_name, Fn&& set_attr)
751 {
752 const auto* element_block = get_simplex_element_block(DIM);
753 const size_t tag_offset = element_block->data.front();
754 for (const auto& data : m_spec.element_data) {
755 if (data.header.string_tags.front() != attr_name) continue;
756 if (data.header.int_tags.size() >= 5 && data.header.int_tags[4] != DIM) {
757 throw std::runtime_error("Attribute " + attr_name + " is of the wrong DIM.");
758 }
759
760 for (const mshio::DataEntry& entry : data.entries) {
761 const size_t tag = entry.tag - tag_offset;
762 assert(tag < element_block->num_elements_in_block);
763 set_attr(tag, entry.data);
764 }
765 }
766 }
767
768
769public:
770 mshio::MshSpec m_spec;
771};
772
773} // namespace wmtk
Definition io.hpp:23
void add_physical_group(const std::string &name)
Adds the pysical group and the corresponding entity entry.
Definition io.hpp:134
void add_faces(size_t num_faces, const Fn &get_face_cb)
Add face block. Must be called after vertices were added.
Definition io.hpp:84
std::optional< mshio::PhysicalGroup > get_physical_group_by_name(const std::string &name)
Returns the (first) physical group with the given name, if it exists.
Definition io.hpp:319
void add_face_vertices(size_t num_vertices, const Fn &get_vertex_cb)
Add vertex block. Must be called before adding anything else.
Definition io.hpp:35