OGS
FEFLOWMeshInterface.cpp
Go to the documentation of this file.
1
10#include "FEFLOWMeshInterface.h"
11
12#include <boost/algorithm/string/trim.hpp>
13#include <cctype>
14#include <fstream>
15#include <memory>
16
18#include "BaseLib/FileTools.h"
19#include "BaseLib/Logging.h"
20#include "BaseLib/StringTools.h"
21#include "GeoLib/Point.h"
22#include "GeoLib/Polygon.h"
24#include "MeshLib/Mesh.h"
25#include "MeshLib/Node.h"
26
27namespace FileIO
28{
30{
31 std::ifstream in(filename.c_str());
32 if (!in)
33 {
34 ERR("FEFLOWMeshInterface::readFEFLOWFile(): Could not open file {:s}.",
35 filename);
36 return nullptr;
37 }
38
39 FEM_CLASS fem_class;
40 FEM_DIM fem_dim;
41 std::vector<GeoLib::Point*> points;
42 std::vector<GeoLib::Polyline*> lines;
43
44 bool isXZplane = false;
45
46 std::vector<MeshLib::Node*> vec_nodes;
47 std::vector<MeshLib::Element*> vec_elements;
48
49 std::vector<std::vector<std::size_t>> vec_elementsets;
50
51 std::string line_string;
52 std::stringstream line_stream;
53 while (!in.eof())
54 {
55 std::getline(in, line_string);
56 boost::trim_right(line_string);
57 //....................................................................
58 // CLASS: the version number follows afterward, e.g. CLASS (v.5.313)
59 if (line_string.find("CLASS") != std::string::npos)
60 {
61 std::getline(in, line_string);
62 boost::trim_right(line_string);
63 line_stream.str(line_string);
64 // problem class, time mode, problem orientation, dimension, nr.
65 // layers for 3D, saturation switch, precision of results, precision
66 // of coordinates
67 line_stream >> fem_class.problem_class >> fem_class.time_mode >>
68 fem_class.orientation >> fem_class.dimension >>
69 fem_class.n_layers3d;
70 line_stream.clear();
71 }
72 //....................................................................
73 // DIMENS
74 else if (line_string == "DIMENS")
75 {
76 // DIMENS
77 std::getline(in, line_string);
78 line_stream.str(line_string);
79 line_stream >> fem_dim.n_nodes >> fem_dim.n_elements >>
80 fem_dim.n_nodes_of_element >> std::ws;
81 // create node pointers with dummy coordinates to create element
82 // objects.
83 // True coordinates are set later in COOR and ELEV_I.
84 vec_nodes.resize(fem_dim.n_nodes);
85 std::size_t count = 0;
86 double dummy_coords[3] = {};
87 std::generate(vec_nodes.begin(), vec_nodes.end(),
88 [&]()
89 { return new MeshLib::Node(dummy_coords, count++); });
90 line_stream.clear();
91 }
92 //....................................................................
93 // NODE (node index for elements)
94 else if (line_string == "NODE")
95 {
96 assert(!vec_nodes.empty());
97
99 if (fem_dim.n_nodes_of_element == 2)
100 {
102 }
103 else if (fem_dim.n_nodes_of_element == 3)
104 {
106 }
107 else if (fem_dim.n_nodes_of_element == 4 &&
108 fem_class.dimension == 2)
109 {
111 }
112 else if (fem_dim.n_nodes_of_element == 4 &&
113 fem_class.dimension == 3)
114 {
116 }
117 else if (fem_dim.n_nodes_of_element == 6 &&
118 fem_class.dimension == 3)
119 {
121 }
122 else if (fem_dim.n_nodes_of_element == 8 &&
123 fem_class.dimension == 3)
124 {
126 }
127
128 if (eleType == MeshLib::MeshElemType::INVALID)
129 {
130 ERR("FEFLOWInterface::readFEFLOWFile(): Unsupported element "
131 "type with the number of node = {:d} and dim = {:d}",
132 fem_dim.n_nodes_of_element, fem_class.dimension);
133 std::for_each(vec_nodes.begin(), vec_nodes.end(),
134 [](MeshLib::Node* nod) { delete nod; });
135 vec_nodes.clear();
136 return nullptr;
137 }
138
139 vec_elements.reserve(fem_dim.n_elements);
140 for (std::size_t i = 0; i < fem_dim.n_elements; i++)
141 {
142 std::getline(in, line_string);
143 vec_elements.push_back(
144 readElement(fem_dim, eleType, line_string, vec_nodes));
145 }
146 }
147 else if (line_string == "VARNODE")
148 {
149 assert(!vec_nodes.empty());
150
151 vec_elements.reserve(fem_dim.n_elements);
152 if (fem_dim.n_nodes_of_element == 0)
153 { // mixed element case
154 if (!std::getline(in, line_string))
155 {
156 ERR("FEFLOWInterface::readFEFLOWFile(): read element "
157 "error");
158 std::for_each(vec_nodes.begin(), vec_nodes.end(),
159 [](MeshLib::Node* nod) { delete nod; });
160 vec_nodes.clear();
161 return nullptr;
162 }
163 }
164
165 for (std::size_t i = 0; i < fem_dim.n_elements; i++)
166 {
167 std::getline(in, line_string);
168 vec_elements.push_back(readElement(line_string, vec_nodes));
169 }
170 }
171 //....................................................................
172 // COOR
173 else if (line_string == "COOR")
174 {
175 readNodeCoordinates(in, fem_class, fem_dim, vec_nodes);
176 }
177 else if (line_string == "XYZCOOR")
178 {
179 readNodeCoordinates(in, vec_nodes);
180 }
181 // ELEV_I
182 else if (line_string == "ELEV_I")
183 {
184 if (fem_class.dimension == 2)
185 {
186 continue;
187 }
188 readElevation(in, fem_class, fem_dim, vec_nodes);
189 }
190 //....................................................................
191 // GRAVITY
192 else if (line_string == "GRAVITY")
193 {
194 std::getline(in, line_string);
195 line_stream.str(line_string);
196 double vec[3] = {};
197 line_stream >> vec[0] >> vec[1] >> vec[2];
198 if (vec[0] == 0.0 && vec[1] == -1.0 && vec[2] == 0.0)
199 {
200 // x-z plane
201 isXZplane = true;
202 }
203 line_stream.clear();
204 }
205 //....................................................................
206 // ELEMENTALSETS
207 else if (line_string == "ELEMENTALSETS")
208 {
209 readELEMENTALSETS(in, vec_elementsets);
210 }
211 //....................................................................
212 // SUPERMESH
213 else if (line_string == "SUPERMESH")
214 {
216 points, lines);
217 }
218 //....................................................................
219 }
220 in.close();
221
222 INFO("Create mesh");
223 std::string project_name(
225 auto mesh(
226 std::make_unique<MeshLib::Mesh>(project_name, vec_nodes, vec_elements));
227 INFO("Set values for material property.");
228 auto opt_material_ids(mesh->getProperties().createNewPropertyVector<int>(
229 "MaterialIDs", MeshLib::MeshItemType::Cell, 1));
230 if (!opt_material_ids)
231 {
232 WARN("Could not create PropertyVector for MaterialIDs in Mesh.");
233 }
234 else
235 {
236 opt_material_ids->resize(mesh->getNumberOfElements());
237 setMaterialIDs(fem_class, fem_dim, lines, vec_elementsets, vec_elements,
238 *opt_material_ids);
239 }
240
241 if (isXZplane)
242 {
243 for (auto* nod : vec_nodes)
244 {
245 (*nod)[2] = (*nod)[1];
246 (*nod)[1] = 0.0;
247 }
248 if (!points.empty())
249 {
250 for (auto* pt : points)
251 {
252 (*pt)[2] = (*pt)[1];
253 (*pt)[1] = .0;
254 }
255 }
256 }
257
258 return mesh.release();
259}
260
262 std::ifstream& in, std::vector<MeshLib::Node*>& vec_nodes)
263{
264 std::string line_string;
265 char dummy_char; // for comma(,)
266
267 for (unsigned k = 0; k < vec_nodes.size(); ++k)
268 {
269 // read the line containing the coordinates as string
270 if (!std::getline(in, line_string))
271 {
272 ERR("Could not read the node '{:d}'.", k);
273 for (auto* n : vec_nodes)
274 {
275 delete n;
276 }
277 return;
278 }
279 std::stringstream line_stream;
280 line_stream.str(line_string);
281 // parse the particular coordinates from the string read above
282 for (std::size_t i(0); i < 3; ++i)
283 {
284 if (!(line_stream >> (*vec_nodes[k])[i]))
285 {
286 ERR("Could not parse coordinate {:d} of node '{:d}'.", i, k);
287 for (auto* n : vec_nodes)
288 {
289 delete n;
290 }
291 return;
292 }
293 if (!(line_stream >> dummy_char) && i < 2) // read comma
294 {
295 ERR("Could not parse node '{:d}'.", k);
296 for (auto* n : vec_nodes)
297 {
298 delete n;
299 }
300 return;
301 }
302 }
303 }
304}
305
307 std::ifstream& in, const FEM_CLASS& fem_class, const FEM_DIM& fem_dim,
308 std::vector<MeshLib::Node*> const& vec_nodes)
309{
310 const std::size_t no_nodes_per_layer =
311 (fem_class.dimension == 2)
312 ? fem_dim.n_nodes
313 : fem_dim.n_nodes / (fem_class.n_layers3d + 1);
314 assert(no_nodes_per_layer > 0);
315 const std::size_t n_lines = (no_nodes_per_layer - 1) / 12 + 1;
316 const std::size_t n_layers =
317 (fem_class.dimension == 3) ? fem_class.n_layers3d + 1 : 1;
318 std::string line_string;
319 std::stringstream line_stream;
320 double x;
321 char dummy_char; // for comma(,)
322 // x, y
323 for (unsigned k = 0; k < 2; k++)
324 {
325 // each line
326 for (std::size_t i = 0; i < n_lines; i++)
327 {
328 std::getline(in, line_string);
329 line_stream.str(line_string);
330 for (unsigned j = 0; j < 12; j++)
331 {
332 if (i * 12 + j >= no_nodes_per_layer)
333 {
334 break;
335 }
336 line_stream >> x >> dummy_char;
337 for (std::size_t l = 0; l < n_layers; l++)
338 {
339 const std::size_t n = i * 12 + l * no_nodes_per_layer + j;
340 MeshLib::Node* m_nod = vec_nodes[n];
341 if (k == 0)
342 {
343 (*m_nod)[0] = x;
344 }
345 else
346 {
347 (*m_nod)[1] = x;
348 }
349 }
350 }
351 line_stream.clear();
352 }
353 }
354}
355
356std::vector<std::size_t> FEFLOWMeshInterface::getIndexList(
357 const std::string& str_ranges)
358{
359 std::vector<std::size_t> vec_node_IDs;
360
361 // insert space before and after minus for splitting
362 std::string str_ranges2(BaseLib::replaceString("-", " # ", str_ranges));
363 BaseLib::trim(str_ranges2);
364 auto splitted_str = BaseLib::splitString(str_ranges2, ' ');
365 bool is_range = false;
366 for (auto str : splitted_str)
367 {
368 if (str.empty())
369 {
370 continue;
371 }
372 if (str[0] == '#')
373 {
374 is_range = true;
375 }
376 else if (is_range)
377 {
378 const std::size_t start = vec_node_IDs.back();
379 const auto end = BaseLib::str2number<std::size_t>(str);
380 for (std::size_t i = start + 1; i < end + 1; i++)
381 {
382 vec_node_IDs.push_back(i);
383 }
384 is_range = false;
385 }
386 else
387 {
388 BaseLib::trim(str);
389 vec_node_IDs.push_back(BaseLib::str2number<std::size_t>(str));
390 }
391 }
392
393 return vec_node_IDs;
394}
395
397 const FEM_CLASS& fem_class,
398 const FEM_DIM& fem_dim,
399 std::vector<MeshLib::Node*>& vec_nodes)
400{
401 const std::size_t no_nodes_per_layer =
402 fem_dim.n_nodes / (fem_class.n_layers3d + 1);
403 double z = .0;
404 std::string str_nodeList;
405 std::string line_string;
406 std::stringstream line_stream;
407 std::size_t l = 0;
408 unsigned mode = 0; // 0: exit, 1: slice no, 2: elevation value, 3:
409 // continued line of mode 2
410 std::streamoff pos_prev_line = 0;
411 while (true)
412 {
413 pos_prev_line = in.tellg();
414 std::getline(in, line_string);
415 boost::trim_right(line_string);
416
417 // check mode
418 auto columns = BaseLib::splitString(line_string, ' ');
419 if (!in || std::isalpha(line_string[0]))
420 {
421 mode = 0;
422 }
423 else if (line_string.empty())
424 {
425 continue;
426 }
427 else if (line_string[0] == '\t')
428 {
429 mode = 3;
430 }
431 else if (columns.size() == 1)
432 {
433 mode = 1;
434 }
435 else
436 { // columns.size()>1
437 mode = 2;
438 }
439
440 // process stocked data
441 if (mode != 3 && !str_nodeList.empty())
442 {
443 // process previous lines
444 auto vec_nodeIDs = getIndexList(str_nodeList);
445 for (auto n0 : vec_nodeIDs)
446 {
447 const std::size_t n = n0 - 1 + l * no_nodes_per_layer;
448 (*vec_nodes[n])[2] = z;
449 }
450 str_nodeList.clear();
451 }
452
453 if (mode == 0)
454 {
455 break;
456 }
457 if (mode == 1)
458 {
459 // slice number
460 l++;
461 assert(l + 1 == BaseLib::str2number<std::size_t>(columns.front()));
462 }
463 else if (mode == 2)
464 {
465 // parse current line
466 line_stream.str(line_string);
467 line_stream >> z;
468 std::getline(line_stream, str_nodeList);
469 boost::trim(str_nodeList);
470 line_stream.clear();
471 }
472 else if (mode == 3)
473 {
474 // continue reading node range
475 BaseLib::trim(line_string, '\t');
476 str_nodeList += " " + line_string;
477 }
478 }
479
480 // move stream position to previous line
481 if (std::isalpha(line_string[0]))
482 {
483 in.seekg(pos_prev_line);
484 }
485}
486
488 std::string const& line, std::vector<MeshLib::Node*> const& nodes)
489{
490 std::stringstream ss(line);
491
492 int ele_type;
493 ss >> ele_type;
494
495 MeshLib::MeshElemType elem_type;
496 std::size_t n_nodes_of_element;
497 switch (ele_type)
498 {
499 case 6:
501 n_nodes_of_element = 4;
502 break;
503 case 7:
505 n_nodes_of_element = 6;
506 break;
507 case 8:
509 n_nodes_of_element = 8;
510 break;
511 default:
512 WARN("Could not parse element type.");
513 return nullptr;
514 }
515
516 unsigned idx[8];
517 for (std::size_t i = 0; i < n_nodes_of_element; ++i)
518 {
519 ss >> idx[i];
520 }
521 auto** ele_nodes = new MeshLib::Node*[n_nodes_of_element];
522
523 switch (elem_type)
524 {
525 default:
526 for (std::size_t k(0); k < n_nodes_of_element; ++k)
527 {
528 ele_nodes[k] = nodes[idx[k] - 1];
529 }
530 break;
533 const unsigned n_half_nodes = n_nodes_of_element / 2;
534 for (unsigned k(0); k < n_half_nodes; ++k)
535 {
536 ele_nodes[k] = nodes[idx[k + n_half_nodes] - 1];
537 ele_nodes[k + n_half_nodes] = nodes[idx[k] - 1];
538 }
539 break;
540 }
541
542 switch (elem_type)
543 {
545 return new MeshLib::Tet(ele_nodes);
547 return new MeshLib::Hex(ele_nodes);
549 return new MeshLib::Prism(ele_nodes);
550 default:
551 return nullptr;
552 }
553}
554
556 const FEM_DIM& fem_dim, const MeshLib::MeshElemType elem_type,
557 const std::string& line, const std::vector<MeshLib::Node*>& nodes)
558{
559 std::stringstream ss(line);
560
561 unsigned idx[8];
562 for (std::size_t i = 0; i < fem_dim.n_nodes_of_element; ++i)
563 {
564 ss >> idx[i];
565 }
566 auto** ele_nodes = new MeshLib::Node*[fem_dim.n_nodes_of_element];
567
568 switch (elem_type)
569 {
570 default:
571 for (unsigned k(0); k < fem_dim.n_nodes_of_element; ++k)
572 {
573 ele_nodes[k] = nodes[idx[k] - 1];
574 }
575 break;
578 const unsigned n_half_nodes = fem_dim.n_nodes_of_element / 2;
579 for (unsigned k(0); k < n_half_nodes; ++k)
580 {
581 ele_nodes[k] = nodes[idx[k + n_half_nodes] - 1];
582 ele_nodes[k + n_half_nodes] = nodes[idx[k] - 1];
583 }
584 break;
585 }
586
587 switch (elem_type)
588 {
590 return new MeshLib::Line(ele_nodes);
592 return new MeshLib::Tri(ele_nodes);
594 return new MeshLib::Quad(ele_nodes);
596 return new MeshLib::Tet(ele_nodes);
598 return new MeshLib::Hex(ele_nodes);
600 return new MeshLib::Prism(ele_nodes);
601 default:
602 assert(false);
603 return nullptr;
604 }
605}
606
608 std::ifstream& in, std::vector<std::vector<std::size_t>>& vec_elementsets)
609{
610 auto compressSpaces = [](std::string const& str)
611 {
612 std::stringstream ss(str);
613 std::string new_str;
614 std::string word;
615 while (ss)
616 {
617 ss >> word;
618 new_str += " " + word;
619 }
620 return new_str;
621 };
622
623 std::string line_string;
624 std::string str_idList;
625 std::streampos pos_prev_line = 0;
626 while (true)
627 {
628 pos_prev_line = in.tellg();
629 std::getline(in, line_string);
630
631 unsigned mode = 0;
632 if (!in)
633 {
634 mode = 0; // reached the end of the file
635 }
636 else if (line_string.empty())
637 {
638 continue; // skip and see what comes next
639 }
640 else if (std::isalpha(line_string[0]))
641 {
642 mode = 0; // reached the next section
643 }
644 else if (line_string[0] == ' ')
645 {
646 mode = 1; // start of the element set definition
647 }
648 else if (line_string[0] == '\t')
649 {
650 mode = 2; // continue the definition
651 }
652 else
653 {
654 ERR("Failed during parsing of an ELEMENTALSETS section in a FEFLOW "
655 "file");
656 break;
657 }
658
659 if (mode != 2 && !str_idList.empty())
660 {
661 vec_elementsets.push_back(getIndexList(str_idList));
662 str_idList.clear();
663 }
664
665 if (mode == 0)
666 {
667 break;
668 }
669 if (mode == 1)
670 {
671 // starting a new set
672 std::string set_name;
673 std::string ids;
674 BaseLib::trim(line_string, ' ');
675 if (line_string[0] == '"')
676 { // multiple words
677 auto pos = line_string.find_last_of('"');
678 set_name = line_string.substr(1, pos - 1); // without quotation
679 ids = line_string.substr(pos + 1);
680 }
681 else
682 { // single word
683 auto pos = line_string.find_first_of(' ');
684 set_name = line_string.substr(0, pos);
685 ids = line_string.substr(pos + 1);
686 }
687 INFO("Found an element group - {:s}", set_name.data());
688 str_idList += compressSpaces(ids);
689 }
690 else
691 {
692 // continue reading a element ids
693 BaseLib::trim(line_string, '\t');
694 str_idList += compressSpaces(line_string);
695 }
696 }
697 // move stream position to previous line
698 if (std::isalpha(line_string[0]))
699 {
700 in.seekg(pos_prev_line);
701 }
702}
703
705 FEM_CLASS const& fem_class,
706 FEM_DIM const& fem_dim,
707 std::vector<GeoLib::Polyline*> const& lines,
708 std::vector<std::vector<std::size_t>> const& vec_elementsets,
709 std::vector<MeshLib::Element*> const& vec_elements,
710 std::vector<int>& material_ids)
711{
712 assert(material_ids.size() == vec_elements.size());
713 if (!vec_elementsets.empty())
714 {
715 for (std::size_t matid = 0; matid < vec_elementsets.size(); ++matid)
716 {
717 auto& eids = vec_elementsets[matid];
718 for (auto eid : eids)
719 {
720 material_ids[eid - 1] =
721 matid; // Element IDs given by FEFLOW starts from one!
722 }
723 }
724 }
725 else if (!lines.empty())
726 {
727 for (std::size_t i = 0; i < vec_elements.size(); ++i)
728 {
729 auto const gpt = MeshLib::getCenterOfGravity(*vec_elements[i]);
730 std::size_t matId = 0;
731 for (std::size_t j = 0; j < lines.size(); j++)
732 {
733 GeoLib::Polyline const& poly = *lines[j];
734 if (!poly.isClosed())
735 {
736 continue;
737 }
738
739 GeoLib::Polygon polygon(poly, true);
740 if (polygon.isPntInPolygon(gpt))
741 {
742 matId = j;
743 break;
744 }
745 }
746 material_ids[i] = matId;
747 }
748 }
749 else if (fem_class.n_layers3d > 0)
750 {
751 const std::size_t no_nodes_per_layer =
752 fem_dim.n_nodes / (fem_class.n_layers3d + 1);
753 for (std::size_t i = 0; i < vec_elements.size(); i++)
754 {
755 MeshLib::Element* e = vec_elements[i];
756 std::size_t e_min_nodeID = std::numeric_limits<std::size_t>::max();
757 for (std::size_t j = 0; j < e->getNumberOfBaseNodes(); j++)
758 {
759 e_min_nodeID = std::min(e_min_nodeID, getNodeIndex(*e, j));
760 }
761 std::size_t layer_id = e_min_nodeID / no_nodes_per_layer;
762 material_ids[i] = layer_id;
763 }
764 }
765}
766
767} // namespace FileIO
Filename manipulation routines.
Definition of the Point class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:35
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:45
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition: Logging.h:40
Definition of the Mesh class.
Definition of the Node class.
Definition of the Polygon class.
Definition of string helper functions.
static void readSuperMesh(std::ifstream &in, unsigned dimension, std::vector< GeoLib::Point * > &points, std::vector< GeoLib::Polyline * > &lines)
void setMaterialIDs(FEM_CLASS const &fem_class, FEM_DIM const &fem_dim, std::vector< GeoLib::Polyline * > const &lines, std::vector< std::vector< std::size_t > > const &vec_elementsets, std::vector< MeshLib::Element * > const &vec_elements, std::vector< int > &material_ids)
std::vector< std::size_t > getIndexList(const std::string &str_ranges)
void readNodeCoordinates(std::ifstream &in, std::vector< MeshLib::Node * > &nodes)
read node coordinates given in the XYZCOOR section
MeshLib::Mesh * readFEFLOWFile(const std::string &filename)
void readElevation(std::ifstream &in, const FEM_CLASS &fem_class, const FEM_DIM &fem_dim, std::vector< MeshLib::Node * > &vec_nodes)
read elevation data
MeshLib::Element * readElement(std::string const &line, std::vector< MeshLib::Node * > const &nodes)
Read element type and node indices according to the element type.
void readELEMENTALSETS(std::ifstream &in, std::vector< std::vector< std::size_t > > &vec_elementsets)
parse ELEMENTALSETS
bool isPntInPolygon(MathLib::Point3d const &pnt) const
Definition: Polygon.cpp:206
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition: Polyline.h:42
bool isClosed() const
Definition: Polyline.cpp:119
virtual unsigned getNumberOfBaseNodes() const =0
std::string replaceString(const std::string &searchString, const std::string &replaceString, std::string stringToReplace)
Definition: StringTools.cpp:51
void trim(std::string &str, char ch)
Definition: StringTools.cpp:59
std::string extractBaseNameWithoutExtension(std::string const &pathname)
Definition: FileTools.cpp:187
std::vector< std::string > splitString(std::string const &str)
Definition: StringTools.cpp:29
TemplateElement< MeshLib::TetRule4 > Tet
Definition: Tet.h:25
TemplateElement< MeshLib::LineRule2 > Line
Definition: Line.h:25
TemplateElement< MeshLib::TriRule3 > Tri
Definition: Tri.h:26
TemplateElement< MeshLib::PrismRule6 > Prism
Definition: Prism.h:25
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition: Element.cpp:124
MeshElemType
Types of mesh elements supported by OpenGeoSys. Values are from VTKCellType enum.
Definition: MeshEnums.h:27
TemplateElement< MeshLib::HexRule8 > Hex
Definition: Hex.h:25
TemplateElement< MeshLib::QuadRule4 > Quad
Definition: Quad.h:28