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 template <typename Fn>
271 void extract_edge_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
272 {
273 extract_vertex_attribute<1>(attr_name, std::forward<Fn>(set_attr));
274 }
275
276 template <typename Fn>
277 void extract_face_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
278 {
279 extract_vertex_attribute<2>(attr_name, std::forward<Fn>(set_attr));
280 }
281
282 template <typename Fn>
283 void extract_tet_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
284 {
285 extract_vertex_attribute<3>(attr_name, std::forward<Fn>(set_attr));
286 }
287
288 template <typename Fn>
289 void extract_edge_attribute(const std::string& attr_name, Fn&& set_attr)
290 {
291 extract_element_attribute<1>(attr_name, std::forward<Fn>(set_attr));
292 }
293
294 template <typename Fn>
295 void extract_face_attribute(const std::string& attr_name, Fn&& set_attr)
296 {
297 extract_element_attribute<2>(attr_name, std::forward<Fn>(set_attr));
298 }
299
300 template <typename Fn>
301 void extract_tet_attribute(const std::string& attr_name, Fn&& set_attr)
302 {
303 extract_element_attribute<3>(attr_name, std::forward<Fn>(set_attr));
304 }
305
309 std::optional<mshio::PhysicalGroup> get_physical_group_by_name(const std::string& name)
310 {
311 for (const mshio::PhysicalGroup& ph : m_spec.physical_groups) {
312 if (ph.name == name) {
313 return ph;
314 }
315 }
316 return {};
317 }
318
319 void get_VF(const int& dim, const int& tag, MatrixXd& V, MatrixXi& F)
320 {
321 assert(dim > 0 && tag > 0);
322
323 const size_t n_V = get_num_vertices(dim, tag);
324 const size_t n_F = get_num_simplex_elements(dim, tag);
325
326 if (n_V > 0) {
327 V.resize(n_V, 3);
328 extract_vertices(dim, tag, [&V](size_t i, double x, double y, double z) {
329 V.row(i) = Vector3d(x, y, z);
330 });
331 }
332 if (n_F > 0) {
333 F.resize(n_F, dim + 1);
334 switch (dim) {
335 case 1:
336 extract_simplex_elements<1>(
337 [&F](size_t i, size_t v0, size_t v1) { F.row(i) = Vector2i(v0, v1); });
338 break;
339 case 2:
340 extract_simplex_elements<2>([&F](size_t i, size_t v0, size_t v1, size_t v2) {
341 F.row(i) = Vector3i((int)v0, (int)v1, (int)v2);
342 });
343 break;
344 case 3:
345 extract_simplex_elements<3>(
346 [&F](size_t i, size_t v0, size_t v1, size_t v2, size_t v3) {
347 F.row(i) = Vector4i((int)v0, (int)v1, (int)v2, (int)v3);
348 });
349 break;
350 default: log_and_throw_error("Cannot extract elements for dimension {}", dim);
351 }
352 }
353 }
354
355 void save(const std::string& filename, bool binary = true)
356 {
357 m_spec.mesh_format.file_type = binary;
358 mshio::validate_spec(m_spec);
359 mshio::save_msh(filename, m_spec);
360 }
361
362 void save(std::ostream& out, bool binary = true)
363 {
364 m_spec.mesh_format.file_type = binary;
365 mshio::validate_spec(m_spec);
366 mshio::save_msh(out, m_spec);
367 }
368
369 void load(const std::string& filename) { m_spec = mshio::load_msh(filename); }
370
371 void load(std::istream& in) { m_spec = mshio::load_msh(in); }
372
373private:
374 template <int DIM, typename Fn>
375 void add_vertices(size_t num_vertices, const Fn& get_vertex_cb)
376 {
377 static_assert(DIM >= 1 && DIM <= 3, "Only 1,2,3D elements are supported!");
378 if (num_vertices == 0) {
379 logger().trace("Adding empty vertex block.");
380 }
381 mshio::NodeBlock block;
382 block.num_nodes_in_block = num_vertices;
383 block.tags.reserve(num_vertices);
384 block.data.reserve(num_vertices * 3);
385 block.entity_dim = DIM;
386 block.entity_tag = (int)m_spec.nodes.num_entity_blocks + 1;
387
388 const size_t tag_offset = m_spec.nodes.max_node_tag;
389 for (size_t i = 0; i < num_vertices; i++) {
390 const auto& v = get_vertex_cb(i);
391 block.tags.push_back(tag_offset + i + 1);
392 block.data.push_back(v[0]);
393 block.data.push_back(v[1]);
394 block.data.push_back(v[2]);
395 }
396
397 m_spec.nodes.num_entity_blocks += 1;
398 m_spec.nodes.num_nodes += num_vertices;
399 m_spec.nodes.min_node_tag = 1;
400 m_spec.nodes.max_node_tag += num_vertices;
401 m_spec.nodes.entity_blocks.push_back(std::move(block));
402 }
403
404 template <int DIM, typename Fn>
405 void add_simplex_elements(size_t num_elements, const Fn& get_element_cb)
406 {
407 static_assert(
408 DIM == 1 || DIM == 2 || DIM == 3,
409 "Only 1,2,3D simplex elements are supported");
410 if (num_elements == 0) return;
411
412 if (m_spec.nodes.num_nodes == 0) {
413 log_and_throw_error("Please add a vertex block before adding elements.");
414 }
415 const auto& vertex_block = m_spec.nodes.entity_blocks.back();
416 // assert(!vertex_block.tags.empty());
417 if (vertex_block.entity_dim != DIM) {
418 log_and_throw_error("It seems the last added vertex block has different dimension "
419 "than the elements you want to add.");
420 }
421
422 mshio::ElementBlock block;
423 block.entity_dim = DIM;
424 block.entity_tag = vertex_block.entity_tag;
425 if constexpr (DIM == 1) {
426 block.element_type = 1; // 2-node line.
427 } else if constexpr (DIM == 2) {
428 block.element_type = 2; // 3-node triangle.
429 } else {
430 block.element_type = 4; // 4-node tet.
431 }
432 block.num_elements_in_block = num_elements;
433
434 const size_t vertex_offset =
435 vertex_block.num_nodes_in_block == 0 ? 0 : vertex_block.tags.front() - 1;
436 if (vertex_offset == 0) {
437 logger().trace(
438 "Do not offset vertex IDs for this element block as vertex block was empty");
439 }
440
441 const size_t tag_offset = m_spec.elements.max_element_tag;
442 block.data.reserve(num_elements * (DIM + 2));
443 for (size_t i = 0; i < num_elements; i++) {
444 const auto& e = get_element_cb(i);
445 block.data.push_back(tag_offset + i + 1); // element tag.
446 for (size_t j = 0; j <= DIM; j++) {
447 block.data.push_back(vertex_offset + e[j] + 1);
448 }
449 }
450
451 m_spec.elements.num_entity_blocks++;
452 m_spec.elements.num_elements += num_elements;
453 m_spec.elements.min_element_tag = 1;
454 m_spec.elements.max_element_tag += num_elements;
455 m_spec.elements.entity_blocks.push_back(std::move(block));
456 }
457
458 template <int NUM_FIELDS, int ELEMENT_DIM, typename Fn>
459 void add_vertex_attribute(const std::string& name, const Fn& get_attribute_cb)
460 {
461 static_assert(
462 NUM_FIELDS == 1 || NUM_FIELDS == 3 || NUM_FIELDS == 9,
463 "Only scalar, vector and tensor fields are supported as attribute!");
464 if (m_spec.nodes.entity_blocks.empty()) {
465 throw std::runtime_error("Please add vertices before adding vertex attributes.");
466 }
467 const auto& vertex_block = m_spec.nodes.entity_blocks.back();
468 const size_t num_vertices = vertex_block.num_nodes_in_block;
469 assert(num_vertices != 0);
470
471 if (vertex_block.entity_dim != ELEMENT_DIM) {
472 throw std::runtime_error("It seems the last added vertex block has different dimension "
473 "from the vertex attribute you want to add.");
474 }
475
476 mshio::Data data;
477 data.header.string_tags = {name};
478 data.header.real_tags = {0.0};
479 data.header.int_tags = {0, NUM_FIELDS, int(num_vertices), 0, ELEMENT_DIM};
480
481 data.entries.resize(num_vertices);
482 for (size_t i = 0; i < num_vertices; i++) {
483 auto& entry = data.entries[i];
484 entry.tag = vertex_block.tags[i];
485 entry.data.reserve(NUM_FIELDS);
486 const auto& attr = get_attribute_cb(i);
487 if constexpr (NUM_FIELDS == 1) {
488 entry.data.push_back(attr);
489 } else {
490 for (size_t j = 0; j < NUM_FIELDS; j++) {
491 entry.data.push_back(attr[j]);
492 }
493 }
494 }
495
496 m_spec.node_data.push_back(std::move(data));
497 }
498
499 template <int NUM_FIELDS, int ELEMENT_DIM, typename Fn>
500 void add_element_attribute(const std::string& name, const Fn& get_attribute_cb)
501 {
502 static_assert(
503 NUM_FIELDS == 1 || NUM_FIELDS == 3 || NUM_FIELDS == 9,
504 "Only scalar, vector and tensor fields are supported as attribute!");
505 if (m_spec.elements.entity_blocks.empty()) {
506 throw std::runtime_error("Please add elements before adding element attributes!");
507 }
508 const auto& elem_block = m_spec.elements.entity_blocks.back();
509 if (elem_block.entity_dim != ELEMENT_DIM) {
510 throw std::runtime_error(
511 "It seems the last added element block has different dimension "
512 "than the element attribute you want to add.");
513 }
514 const size_t num_elements = elem_block.num_elements_in_block;
515
516 mshio::Data data;
517 data.header.string_tags = {name};
518 data.header.real_tags = {0.0};
519 data.header.int_tags = {0, NUM_FIELDS, int(num_elements), 0, ELEMENT_DIM};
520
521 data.entries.resize(num_elements);
522 for (size_t i = 0; i < num_elements; i++) {
523 auto& entry = data.entries[i];
524 entry.tag = elem_block.data[i * (ELEMENT_DIM + 2)];
525 entry.data.reserve(NUM_FIELDS);
526 const auto& attr = get_attribute_cb(i);
527 if constexpr (NUM_FIELDS == 1) {
528 entry.data.push_back(attr);
529 } else {
530 for (size_t j = 0; j < NUM_FIELDS; j++) {
531 entry.data.push_back(attr[j]);
532 }
533 }
534 }
535
536 m_spec.element_data.push_back(std::move(data));
537 }
538
539 const mshio::NodeBlock* get_vertex_block(const int dim) const
540 {
541 for (const auto& block : m_spec.nodes.entity_blocks) {
542 if (block.entity_dim == dim) {
543 return &block;
544 }
545 }
546 return nullptr;
547 }
548
549 const mshio::NodeBlock* get_vertex_block(const int dim, const int tag) const
550 {
551 for (const auto& block : m_spec.nodes.entity_blocks) {
552 if (block.entity_dim == dim && block.entity_tag == tag) {
553 return &block;
554 }
555 }
556 return nullptr;
557 }
558
559 const mshio::ElementBlock* get_simplex_element_block(const int dim) const
560 {
561 for (const auto& block : m_spec.elements.entity_blocks) {
562 if (block.entity_dim == dim) {
563 return &block;
564 }
565 }
566 return nullptr;
567 }
568
569 const mshio::ElementBlock* get_simplex_element_block(const int dim, const int tag) const
570 {
571 for (const auto& block : m_spec.elements.entity_blocks) {
572 if (block.entity_dim == dim && block.entity_tag == tag) {
573 return &block;
574 }
575 }
576 return nullptr;
577 }
578
579 size_t get_num_vertices(const int dim) const
580 {
581 const auto* block = get_vertex_block(dim);
582 if (block != nullptr) {
583 return block->num_nodes_in_block;
584 } else {
585 return 0;
586 }
587 }
588
589 size_t get_num_vertices(const int dim, const int tag) const
590 {
591 const auto* block = get_vertex_block(dim, tag);
592 if (block != nullptr) {
593 return block->num_nodes_in_block;
594 } else {
595 return 0;
596 }
597 }
598
599 size_t get_num_simplex_elements(const int dim) const
600 {
601 const auto* block = get_simplex_element_block(dim);
602 if (block != nullptr) {
603 return block->num_elements_in_block;
604 } else {
605 return 0;
606 }
607 }
608
609 size_t get_num_simplex_elements(const int dim, const int tag) const
610 {
611 const auto* block = get_simplex_element_block(dim, tag);
612 if (block != nullptr) {
613 return block->num_elements_in_block;
614 } else {
615 return 0;
616 }
617 }
618
619 template <typename Fn>
620 void extract_vertices(const int dim, Fn&& set_vertex_cb) const
621 {
622 const auto* block = get_vertex_block(dim);
623 if (block == nullptr) return;
624
625 const size_t num_vertices = block->num_nodes_in_block;
626 if (num_vertices == 0) return;
627
628 const size_t tag_offset = block->tags.front();
629 for (size_t i = 0; i < num_vertices; i++) {
630 size_t tag = block->tags[i] - tag_offset;
631 set_vertex_cb(tag, block->data[i * 3], block->data[i * 3 + 1], block->data[i * 3 + 2]);
632 }
633 }
634
635 template <typename Fn>
636 void extract_vertices(const int dim, const int tag, Fn&& set_vertex_cb) const
637 {
638 const auto* block = get_vertex_block(dim, tag);
639 if (block == nullptr) return;
640
641 const size_t num_vertices = block->num_nodes_in_block;
642 if (num_vertices == 0) return;
643
644 const size_t tag_offset = block->tags.front();
645 for (size_t i = 0; i < num_vertices; i++) {
646 size_t tag = block->tags[i] - tag_offset;
647 set_vertex_cb(tag, block->data[i * 3], block->data[i * 3 + 1], block->data[i * 3 + 2]);
648 }
649 }
650
651 template <int DIM, typename Fn>
652 void extract_simplex_elements(Fn&& set_element_cb) const
653 {
654 const auto* vertex_block = get_vertex_block(DIM);
655 const auto* element_block = get_simplex_element_block(DIM);
656 if (element_block == nullptr) return;
657 assert(vertex_block != nullptr);
658
659 const size_t num_elements = element_block->num_elements_in_block;
660 if (num_elements == 0) return;
661 assert(vertex_block->num_nodes_in_block != 0);
662
663 const size_t vert_tag_offset = vertex_block->tags.front();
664 const size_t elem_tag_offset = element_block->data.front();
665 for (size_t i = 0; i < num_elements; i++) {
666 const size_t tag = element_block->data[i * (DIM + 2)] - elem_tag_offset;
667 assert(tag < num_elements);
668 const auto* element = element_block->data.data() + i * (DIM + 2) + 1;
669
670 if constexpr (DIM == 1) {
671 set_element_cb(tag, element[0] - vert_tag_offset, element[1] - vert_tag_offset);
672 } else if constexpr (DIM == 2) {
673 set_element_cb(
674 tag,
675 element[0] - vert_tag_offset,
676 element[1] - vert_tag_offset,
677 element[2] - vert_tag_offset);
678 } else if constexpr (DIM == 3) {
679 set_element_cb(
680 tag,
681 element[0] - vert_tag_offset,
682 element[1] - vert_tag_offset,
683 element[2] - vert_tag_offset,
684 element[3] - vert_tag_offset);
685 }
686 }
687 }
688
689 template <int DIM>
690 std::vector<std::string> get_vertex_attribute_names() const
691 {
692 std::vector<std::string> attr_names;
693 attr_names.reserve(m_spec.node_data.size());
694 for (const auto& data : m_spec.node_data) {
695 const auto& int_tags = data.header.int_tags;
696 if (int_tags.size() >= 5 && int_tags[4] == DIM) {
697 attr_names.push_back(data.header.string_tags.front());
698 }
699 }
700 return attr_names;
701 }
702
703 template <int DIM>
704 std::vector<std::string> get_element_attribute_names() const
705 {
706 std::vector<std::string> attr_names;
707 attr_names.reserve(m_spec.element_data.size());
708 for (const auto& data : m_spec.element_data) {
709 const auto& int_tags = data.header.int_tags;
710 if (int_tags.size() >= 5 && int_tags[4] == DIM) {
711 attr_names.push_back(data.header.string_tags.front());
712 }
713 }
714 return attr_names;
715 }
716
717 template <int DIM, typename Fn>
718 void extract_vertex_attribute(const std::string& attr_name, Fn&& set_attr)
719 {
720 const auto* vertex_block = get_vertex_block(DIM);
721 const size_t tag_offset = vertex_block->tags.front();
722 for (const auto& data : m_spec.node_data) {
723 if (data.header.string_tags.front() != attr_name) continue;
724 if (data.header.int_tags.size() >= 5 && data.header.int_tags[4] != DIM) {
725 log_and_throw_error("Attribute " + attr_name + " is of the wrong DIM.");
726 }
727
728 for (const auto& entry : data.entries) {
729 const size_t tag = entry.tag - tag_offset;
730 assert(tag < vertex_block->num_nodes_in_block);
731 set_attr(tag, entry.data);
732 }
733 }
734 }
735
736 template <int DIM, typename Fn>
737 void extract_element_attribute(const std::string& attr_name, Fn&& set_attr)
738 {
739 const auto* element_block = get_simplex_element_block(DIM);
740 const size_t tag_offset = element_block->data.front();
741 for (const auto& data : m_spec.element_data) {
742 if (data.header.string_tags.front() != attr_name) continue;
743 if (data.header.int_tags.size() >= 5 && data.header.int_tags[4] != DIM) {
744 throw std::runtime_error("Attribute " + attr_name + " is of the wrong DIM.");
745 }
746
747 for (const mshio::DataEntry& entry : data.entries) {
748 const size_t tag = entry.tag - tag_offset;
749 assert(tag < element_block->num_elements_in_block);
750 set_attr(tag, entry.data);
751 }
752 }
753 }
754
755
756public:
757 mshio::MshSpec m_spec;
758};
759
760} // 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:309
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