FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
mesh_file_reader.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include <kernel/geometry/conformal_mesh.hpp>
9#include <kernel/geometry/mesh_atlas.hpp>
10#include <kernel/geometry/mesh_part.hpp>
11#include <kernel/geometry/mesh_node.hpp>
12#include <kernel/geometry/atlas/bezier.hpp>
13#include <kernel/geometry/atlas/circle.hpp>
14#include <kernel/geometry/atlas/extrude.hpp>
15#include <kernel/geometry/atlas/surface_mesh.hpp>
16#include <kernel/geometry/atlas/sphere.hpp>
17#include <kernel/adjacency/dynamic_graph.hpp>
19#include <kernel/util/xml_scanner.hpp>
20#include <kernel/util/dist_file_io.hpp>
21
22#include <deque>
23#include <vector>
24#include <memory>
25
26namespace FEAT
27{
28 namespace Geometry
29 {
38 public Exception
39 {
40 public:
41 explicit MeshNodeLinkerError(const String& msg) :
42 Exception(msg)
43 {
44 }
45 }; // class MeshNodeLinkerError
46
55 template<typename RootMesh_>
57 {
58 protected:
63
64 // link mesh-parts to charts
65 std::deque<std::pair<String,String>> _meshpart_to_chart;
66 // deduct mesh-part topologies
67 std::deque<String> _meshpart_deduct_topo;
68
69 public:
80 _mesh_node(mesh_node),
81 _atlas(atlas)
82 {
83 }
84
94 void meshpart_link_to_chart(const String& meshpart, const String& chart)
95 {
96 _meshpart_to_chart.emplace_back(std::make_pair(meshpart, chart));
97 }
98
105 void meshpart_deduct_topology(const String& meshpart)
106 {
107 _meshpart_deduct_topo.emplace_back(meshpart);
108 }
109
115 void execute()
116 {
117 // link meshparts to charts
118 while(!_meshpart_to_chart.empty())
119 {
120 String mpart_name = _meshpart_to_chart.front().first;
121 String chart_name = _meshpart_to_chart.front().second;
122
123 // try to find the chart
124 const Atlas::ChartBase<RootMesh_>* chart = _atlas.find_mesh_chart(chart_name);
125 if(chart == nullptr)
126 {
127 String msg = String("Chart '") + chart_name + "' not found for meshpart '" + mpart_name + "'";
128 throw MeshNodeLinkerError(msg);
129 }
130
131 // set the chart
132 if(!_mesh_node.set_mesh_part_chart(mpart_name, chart_name, chart))
133 {
134 String msg = String("meshpart '" + mpart_name + "' not found");
135 throw MeshNodeLinkerError(msg);
136 }
137
138 // done
139 _meshpart_to_chart.pop_front();
140 }
141
142 // get the root mesh (if it exists)
143 const RootMesh_* root_mesh = _mesh_node.get_mesh();
144
145 // deduct meshpart topologies
146 while(!_meshpart_deduct_topo.empty())
147 {
148 String mpart_name = _meshpart_deduct_topo.front();
149 MeshPart<RootMesh_>* mesh_part = _mesh_node.find_mesh_part(mpart_name);
150
151 if(mesh_part == nullptr)
152 {
153 String msg = String("meshpart '" + mpart_name + "' not found");
154 throw MeshNodeLinkerError(msg);
155 }
156
157 // make sure we have the root mesh
158 if(root_mesh == nullptr)
159 {
160 String msg = String("Cannot deduct topology for meshpart '") + mpart_name + "'; no root mesh found";
161 throw MeshNodeLinkerError(msg);
162 }
163
164 // Create the MeshPart's topology from the parent mesh's topology if told so
165 mesh_part->deduct_topology(*(root_mesh->get_topology()));
166
167 // done
168 _meshpart_deduct_topo.pop_front();
169 }
170 }
171 }; // class MeshNodeLinker
172
173 // Note: All the basic Parser classes are declared as internal.
175
176 // Forward declaration
177 template<typename RootMesh_, int world_dim>
178 struct DimensionalChartHelper;
179
180 template<typename RootMesh_>
181 class ChartParser :
182 public Xml::MarkupParser
183 {
184 protected:
185 MeshAtlas<RootMesh_>& _atlas;
186 String _chart_name;
187 std::unique_ptr<Atlas::ChartBase<RootMesh_>> _chart;
188
189 public:
190 explicit ChartParser(MeshAtlas<RootMesh_>& atlas) :
191 _atlas(atlas), _chart_name(), _chart()
192 {
193 }
194
195 virtual ~ChartParser()
196 {
197 }
198
199 virtual bool attribs(std::map<String,bool>& attrs) const override
200 {
201 attrs.emplace("name", true); // mandatory name
202 return true;
203 }
204
205 virtual void create(
206 int iline, const String& sline, const String&,
207 const std::map<String, String>& attrs, bool closed) override
208 {
209 if(closed)
210 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
211
212 // get the chart name
213 _chart_name = attrs.find("name")->second.trim();
214 if(_chart_name.empty())
215 throw Xml::GrammarError(iline, sline, "Empty chart name");
216
217 // make sure that we don't have that chart yet
218 XASSERTM(_atlas.find_mesh_chart(_chart_name) == nullptr,
219 String("Chart '") + _chart_name + "' already exists in atlas");
220
221 // okay, that's all there is to check
222 }
223
224 virtual void close(int iline, const String& sline) override
225 {
226 // make sure that we have a chart here
227 if(!_chart)
228 throw Xml::GrammarError(iline, sline, "Invalid empty chart");
229
230 // insert chart into atlas
231 _atlas.add_mesh_chart(_chart_name, std::move(_chart));
232 }
233
234 virtual bool content(int, const String&) override
235 {
236 return false; // invalid content
237 }
238
239 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String& name) override
240 {
241 return DimensionalChartHelper<RootMesh_, RootMesh_::world_dim>::markup(name, _chart);
242 }
243
244 }; // class ChartParser<...>
245
246 template<int num_coords_, typename Coord_>
247 class VerticesParser :
248 public Xml::MarkupParser
249 {
250 public:
251 typedef VertexSet<num_coords_, Coord_> VertexSetType;
252
253 protected:
254 VertexSetType& _vertex_set;
255 Index _read;
256
257 public:
258 explicit VerticesParser(VertexSetType& vertex_set) :
259 _vertex_set(vertex_set),
260 _read(0)
261 {
262 }
263
264 virtual bool attribs(std::map<String,bool>&) const override
265 {
266 return true;
267 }
268
269 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>&, bool closed) override
270 {
271 if(closed)
272 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
273 }
274
275 virtual void close(int iline, const String& sline) override
276 {
277 // ensure that we have read all vertices
278 if(_read < _vertex_set.get_num_vertices())
279 throw Xml::GrammarError(iline, sline, "Invalid terminator; expected point");
280 }
281
282 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String&) override
283 {
284 // no children allowed
285 return nullptr;
286 }
287
288 virtual bool content(int iline, const String& sline) override
289 {
290 // make sure that we do not read more points than expected
291 if(_read >= _vertex_set.get_num_vertices())
292 throw Xml::ContentError(iline, sline, "Invalid content; expected terminator");
293
294 // split line by whitespaces
295 std::deque<String> scoords = sline.split_by_whitespaces();
296
297 // check size
298 if(scoords.size() != std::size_t(num_coords_))
299 throw Xml::ContentError(iline, sline, "Invalid number of coordinates");
300
301 // get our current vertex
302 auto& vtx = _vertex_set[_read];
303
304 // try to parse all coords
305 for(int i(0); i < num_coords_; ++i)
306 {
307 if(!scoords.at(std::size_t(i)).parse(vtx[i]))
308 throw Xml::ContentError(iline, sline, "Failed to parse vertex coordinate");
309 }
310
311 // okay, another point done
312 ++_read;
313
314 return true;
315 }
316 };
317
318 namespace Intern
319 {
320 template<typename Shape_, int dim_ = Shape_::dimension>
321 struct TopoParseHelper
322 {
323 template<typename TopoParser_>
324 static void init_topo(TopoParser_& tp, IndexSetHolder<Shape_>& ish, int dim)
325 {
326 if(dim_ == dim)
327 tp.init_idx_set(ish.template get_index_set<dim_, 0>(), dim_);
328 else
329 TopoParseHelper<Shape_, dim_-1>::init_topo(tp, ish, dim);
330 }
331 };
332
333 template<typename Shape_>
334 struct TopoParseHelper<Shape_, 0>
335 {
336 template<typename TopoParser_>
337 static void init_topo(TopoParser_&, IndexSetHolder<Shape_>&, int)
338 {
339 XABORTM("Thou shall not arrive here");
340 }
341 };
342
343 template<typename Shape_, int dim_ = Shape_::dimension>
344 struct MappParseHelper
345 {
346 template<typename MappParser_>
347 static void init_mapp(MappParser_& mp, TargetSetHolder<Shape_>& tsh, int dim)
348 {
349 if(dim_ == dim)
350 mp.init_trg_set(tsh.template get_target_set<dim_>(), dim_);
351 else
352 MappParseHelper<Shape_, dim_-1>::init_mapp(mp, tsh, dim);
353 }
354 };
355
356 template<typename Shape_>
357 struct MappParseHelper<Shape_, 0>
358 {
359 template<typename MappParser_>
360 static void init_mapp(MappParser_& mp, TargetSetHolder<Shape_>& tsh, int)
361 {
362 mp.init_trg_set(tsh.template get_target_set<0>(), 0);
363 }
364 };
365 } // namespace Intern
366
367 template<typename Shape_>
368 class TopologyParser :
369 public Xml::MarkupParser
370 {
371 public:
372 typedef IndexSetHolder<Shape_> TopologyType;
373
374 protected:
375 TopologyType& _topology;
376 std::deque<int>& _have_topology;
377 Index* _indices;
378 Index _my_dim;
379 Index _num_idx;
380 Index _bound;
381 Index _count;
382 Index _read;
383
384 public:
385 template<int num_idx_>
386 void init_idx_set(IndexSet<num_idx_>& idx_set, int dim)
387 {
388 _indices = reinterpret_cast<Index*>(idx_set.get_indices());
389 _my_dim = Index(dim);
390 _num_idx = Index(num_idx_);
391 _bound = idx_set.get_index_bound();
392 _count = idx_set.get_num_entities();
393 _read = Index(0);
394 }
395
396 public:
397 explicit TopologyParser(TopologyType& topology, std::deque<int>& have_topology) :
398 _topology(topology),
399 _have_topology(have_topology),
400 _indices(nullptr),
401 _my_dim(0),
402 _num_idx(0),
403 _bound(0),
404 _count(0),
405 _read(0)
406 {
407 }
408
409 virtual bool attribs(std::map<String,bool>& attrs) const override
410 {
411 attrs.emplace("dim", true);
412 return true;
413 }
414
415 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool closed) override
416 {
417 if(closed)
418 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
419
420 // parse dimension
421 if(!attrs.find("dim")->second.parse(_my_dim))
422 throw Xml::ContentError(iline, sline, "Failed to parse 'dim' attribute");
423
424 // make sure that the dimension is not out-of-bounds
425 if((_my_dim > Index(_have_topology.size())) || (_my_dim == Index(0)))
426 throw Xml::ContentError(iline, sline, "Invalid topology dimension");
427
428 // make sure that we did not have that topology yet
429 if(_have_topology.at(_my_dim-1) != 0)
430 throw Xml::ContentError(iline, sline, "Multiple topology for dimension " + stringify(_my_dim));
431 _have_topology.at(_my_dim-1) = 1;
432
433 // initialize the corresponding topology:
434 Intern::TopoParseHelper<Shape_>::init_topo(*this, _topology, int(_my_dim));
435 }
436
437 virtual void close(int iline, const String& sline) override
438 {
439 // ensure that we have read all index tuples
440 if(_read < _count)
441 throw Xml::GrammarError(iline, sline, "Invalid terminator; expected index tuple");
442 }
443
444 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String&) override
445 {
446 // no children allowed
447 return nullptr;
448 }
449
450 virtual bool content(int iline, const String& sline) override
451 {
452 // make sure that we do not read more points than expected
453 if(_read >= _count)
454 throw Xml::ContentError(iline, sline, "Invalid content; expected terminator");
455
456 // split line by whitespaces
457 std::deque<String> sidx = sline.split_by_whitespaces();
458
459 // check size
460 if(sidx.size() != std::size_t(_num_idx))
461 throw Xml::ContentError(iline, sline, "Invalid number of indices");
462
463 // parse
464 for(Index i(0); i < _num_idx; ++i)
465 {
466 Index& idx = _indices[_read*_num_idx+i];
467
468 // try to parse
469 if(!sidx.at(i).parse(idx))
470 throw Xml::ContentError(iline, sline, "Failed to parse index");
471
472 // check for out-of-bounds
473 if(idx >= _bound)
474 throw Xml::ContentError(iline, sline, "Index out of bounds");
475 }
476
477 // okay, another one processed
478 ++_read;
479
480 return true;
481 }
482 };
483
484 template<typename Shape_>
485 class MappingParser :
486 public Xml::MarkupParser
487 {
488 public:
489 typedef TargetSetHolder<Shape_> MappingType;
490
491 protected:
492 MappingType& _mapping;
493 std::deque<int>& _have_mapping;
494 Index* _indices;
495 Index _my_dim;
496 Index _count;
497 Index _read;
498
499 public:
500 void init_trg_set(TargetSet& trg_set, int dim)
501 {
502 _indices = trg_set.get_indices();
503 _my_dim = Index(dim);
504 _count = trg_set.get_num_entities();
505 }
506
507 public:
508 explicit MappingParser(MappingType& mapping, std::deque<int>& have_mapping) :
509 _mapping(mapping),
510 _have_mapping(have_mapping),
511 _indices(nullptr),
512 _my_dim(0),
513 _count(0),
514 _read(0)
515 {
516 }
517
518 virtual bool attribs(std::map<String,bool>& attrs) const override
519 {
520 attrs.emplace("dim", true);
521 return true;
522 }
523
524 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool closed) override
525 {
526 if(closed)
527 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
528
529 // parse dimension
530 if(!attrs.find("dim")->second.parse(_my_dim))
531 throw Xml::ContentError(iline, sline, "Failed to parse 'dim' attribute");
532
533 // make sure that the dimension is not out-of-bounds
534 if((_my_dim > Index(_have_mapping.size())))
535 throw Xml::ContentError(iline, sline, "Invalid mapping dimension");
536
537 // make sure that we did not have that topology yet
538 if(_have_mapping.at(_my_dim) != 0)
539 throw Xml::ContentError(iline, sline, "Multiple mapping for dimension " + stringify(_my_dim));
540 _have_mapping.at(_my_dim) = 1;
541
542 // initialize the corresponding mapping:
543 Intern::MappParseHelper<Shape_>::init_mapp(*this, _mapping, int(_my_dim));
544 }
545
546 virtual void close(int iline, const String& sline) override
547 {
548 // ensure that we have read all index tuples
549 if(_read < _count)
550 throw Xml::GrammarError(iline, sline, "Invalid terminator; expected index");
551 }
552
553 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String&) override
554 {
555 // no children allowed
556 return nullptr;
557 }
558
559 virtual bool content(int iline, const String& sline) override
560 {
561 // make sure that we do not read more points than expected
562 if(_read >= _count)
563 throw Xml::ContentError(iline, sline, "Invalid content; expected terminator");
564
565 // try to parse index
566 if(!sline.parse(_indices[_read]))
567 throw Xml::ContentError(iline, sline, "Failed to parse index");
568
569 // okay, another one processed
570 ++_read;
571
572 return true;
573 }
574 };
575
576 template<typename MeshPart_, typename DataType_ = typename MeshPart_::AttributeDataType>
577 class AttributeParser :
578 public Xml::MarkupParser
579 {
580 public:
581 typedef AttributeSet<DataType_> AttribType;
582
583 protected:
584 MeshPart_& _mesh_part;
585 std::unique_ptr<AttribType> _attrib;
586 Index _my_dim;
587 Index _count;
588 Index _read;
589 String _my_name;
590
591 public:
592 explicit AttributeParser(MeshPart_& mesh_part) :
593 _mesh_part(mesh_part),
594 _attrib(),
595 _my_dim(0),
596 _count(0),
597 _read(0)
598 {
599 }
600
601 virtual ~AttributeParser()
602 {
603 }
604
605 virtual bool attribs(std::map<String,bool>& attrs) const override
606 {
607 attrs.emplace("dim", true);
608 attrs.emplace("name", true);
609 return true;
610 }
611
612 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool closed) override
613 {
614 if(closed)
615 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
616
617 // parse dimension
618 if(!attrs.find("dim")->second.parse(_my_dim))
619 throw Xml::ContentError(iline, sline, "Failed to parse 'dim' attribute");
620
621 // make sure that the dimension is valid
622 if(_my_dim == Index(0))
623 throw Xml::ContentError(iline, sline, "Invalid attribute dimension");
624
625 // fetch name
626 _my_name = attrs.find("name")->second;
627
628 // create mesh attribute
629 _count = _mesh_part.get_num_entities(0);
630 _attrib.reset(new AttribType(_count, int(_my_dim)));
631 }
632
633 virtual void close(int iline, const String& sline) override
634 {
635 // ensure that we have read all index tuples
636 if(_read < _count)
637 throw Xml::GrammarError(iline, sline, "Invalid terminator; expected index");
638
639 // okay, add attribute to mesh part
640 _mesh_part.add_attribute(std::move(_attrib), _my_name);
641 }
642
643 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String&) override
644 {
645 // no children allowed
646 return nullptr;
647 }
648
649 virtual bool content(int iline, const String& sline) override
650 {
651 // make sure that we do not read more points than expected
652 if(_read >= _count)
653 throw Xml::ContentError(iline, sline, "Invalid content; expected terminator");
654
655 // split line by whitespaces
656 std::deque<String> svals = sline.split_by_whitespaces();
657
658 // check size
659 if(svals.size() != std::size_t(_my_dim))
660 throw Xml::ContentError(iline, sline, "Invalid number of values");
661
662 // try to parse all coords
663 for(int i(0); i < int(_my_dim); ++i)
664 {
665 if(!svals.at(std::size_t(i)).parse(_attrib->operator()(_read,i)))
666 throw Xml::ContentError(iline, sline, "Failed to parse value");
667 }
668
669 // okay, another one processed
670 ++_read;
671
672 return true;
673 }
674 };
675
676 template<typename Mesh_>
677 class MeshParser;
678
679 template<typename Shape_, int num_coords_, typename Coord_>
680 class MeshParser<ConformalMesh<Shape_, num_coords_, Coord_>> :
681 public Xml::MarkupParser
682 {
683 public:
684 typedef ConformalMesh<Shape_, num_coords_, Coord_> MeshType;
685
686 protected:
687 RootMeshNode<MeshType>& _root_node;
688 std::unique_ptr<MeshType> _mesh;
689 bool _have_verts;
690 std::deque<int> _have_topology;
691 std::vector<Index> _sizes;
692
693 template<int shape_dim_>
694 static String aux_shape_string(const Shape::Hypercube<shape_dim_>&)
695 {
696 return "hypercube";
697 }
698
699 template<int shape_dim_>
700 static String aux_shape_string(const Shape::Simplex<shape_dim_>&)
701 {
702 return "simplex";
703 }
704
705 public:
706 explicit MeshParser(RootMeshNode<MeshType>& root_node) :
707 _root_node(root_node),
708 _mesh(nullptr),
709 _have_verts(false)
710 {
711 }
712
713 virtual ~MeshParser()
714 {
715 }
716
717 virtual bool attribs(std::map<String,bool>& attrs) const override
718 {
719 attrs.emplace("type", true);
720 attrs.emplace("size", true);
721 return true;
722 }
723
724 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool closed) override
725 {
726 if(closed)
727 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
728
729 // fetch mesh type substrings
730 std::deque<String> stype = attrs.find("type")->second.split_by_string(":");
731
732 // validate mesh type
733 if(stype.size() != std::size_t(4))
734 throw Xml::ContentError(iline, sline, "Invalid mesh type attribue");
735 if(stype.at(0) != "conformal")
736 throw Xml::ContentError(iline, sline, "Invalid mesh type; expected 'conformal'");
737 String sshape = aux_shape_string(Shape_());
738 if(stype.at(1) != sshape)
739 throw Xml::ContentError(iline, sline, "Invalid mesh shape type; expected '" + sshape + "'");
740 int ishape_dim(0), iworld_dim(0);
741 if(!stype.at(2).parse(ishape_dim))
742 throw Xml::ContentError(iline, sline, "Failed to parse mesh shape dimension");
743 if(ishape_dim != Shape_::dimension)
744 throw Xml::ContentError(iline, sline, "Invalid mesh shape dimension");
745 if(!stype.at(3).parse(iworld_dim))
746 throw Xml::ContentError(iline, sline, "Failed to parse mesh world dimension");
747 if(iworld_dim != num_coords_)
748 throw Xml::ContentError(iline, sline, "Invalid mesh world dimension");
749
750 // okay, the mesh type seems fine
751
752 // split sizes
753 std::deque<String> ssize = attrs.find("size")->second.split_by_whitespaces();
754 if(ssize.size() != std::size_t(Shape_::dimension+1))
755 throw Xml::ContentError(iline, sline, "Invalid mesh size count");
756
757 // parse sizes
758 _sizes.resize(ssize.size());
759 for(std::size_t i(0); i <= std::size_t(Shape_::dimension); ++i)
760 {
761 if(!ssize.at(i).parse(_sizes.at(i)))
762 throw Xml::ContentError(iline, sline, "Failed to parse mesh size");
763 }
764
765 // try to create the mesh
766 _mesh.reset(new MeshType(_sizes.data()));
767
768 // initialize
769 _have_verts = false;
770 _have_topology.resize(std::size_t(Shape_::dimension), 0);
771 }
772
773 virtual void close(int iline, const String& sline) override
774 {
775 // do we have coords?
776 if(!_have_verts)
777 throw Xml::GrammarError(iline, sline, "Mesh has no Vertices");
778
779 // make sure we have the whole topology
780 for(std::size_t i(0); i < _have_topology.size(); ++i)
781 {
782 if(_have_topology.at(i) == 0)
783 throw Xml::GrammarError(iline, sline, "Missing topology for dimension " + stringify(i+1));
784 }
785
786 // okay, the mesh is complete
787
788 // compute remaining topology now
789 RedundantIndexSetBuilder<Shape_>::compute(*_mesh->get_topology());
790
791 // add to mesh node
792 _root_node.set_mesh(std::move(_mesh));
793 }
794
795 virtual std::shared_ptr<Xml::MarkupParser> markup(int iline, const String& sline, const String& name) override
796 {
797 // vertices?
798 if(name == "Vertices")
799 {
800 if(_have_verts)
801 throw Xml::GrammarError(iline, sline, "More than one Vertices block in mesh");
802
803 // okay, create a vertex parser
804 _have_verts = true;
805 return std::make_shared<VerticesParser<num_coords_, Coord_>>(_mesh->get_vertex_set());
806 }
807
808 // topology?
809 if(name == "Topology")
810 {
811 // create a topology parser
812 return std::make_shared<TopologyParser<Shape_>>(*_mesh->get_topology(), _have_topology);
813 }
814
815 // invalid
816 return nullptr;
817 }
818
819 virtual bool content(int, const String&) override
820 {
821 return false; // no content allowed
822 }
823 };
824
825 template<typename Mesh_>
826 class MeshPartParser;
827
828 template<typename Shape_, int num_coords_, typename Coord_>
829 class MeshPartParser<ConformalMesh<Shape_, num_coords_, Coord_>> :
830 public Xml::MarkupParser
831 {
832 public:
833 typedef ConformalMesh<Shape_, num_coords_, Coord_> MeshType;
834 typedef MeshPart<MeshType> MeshPartType;
835 typedef Atlas::ChartBase<MeshType> ChartType;
836 enum class TopoType
837 {
838 none,
839 full,
840 parent
841 };
842
843 protected:
844 RootMeshNode<MeshType>& _root_node;
845 MeshNodeLinker<MeshType>& _linker;
846 std::unique_ptr<MeshPartType> _mesh_part;
847 ChartType* _chart;
848 TopoType _topo_type;
849 String _name, _parent, _chart_name;
850 std::deque<int> _have_topology;
851 std::deque<int> _have_mapping;
852 std::vector<Index> _sizes;
853
854 public:
855 explicit MeshPartParser(RootMeshNode<MeshType>& root_node, MeshNodeLinker<MeshType>& linker) :
856 _root_node(root_node),
857 _linker(linker),
858 _mesh_part(),
859 _chart(nullptr),
860 _topo_type(TopoType::none)
861 {
862 }
863
864 virtual ~MeshPartParser()
865 {
866 }
867
868 virtual bool attribs(std::map<String,bool>& attrs) const override
869 {
870 attrs.emplace("name", true);
871 attrs.emplace("parent", true);
872 attrs.emplace("size", true);
873 attrs.emplace("topology", true);
874 attrs.emplace("chart", false);
875 return true;
876 }
877
878 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool closed) override
879 {
880 if(closed)
881 throw Xml::GrammarError(iline, sline, "Invalid closed markup");
882
883 // fetch name and parent
884 _name = attrs.find("name")->second;
885 _parent = attrs.find("parent")->second;
886
887 // make sure that the mesh part does not already exist in the mesh node
888 if(_root_node.find_mesh_part(_name) != nullptr)
889 throw Xml::ContentError(iline, sline, String("Mesh Part '") + _name + "' already exists in mesh node");
890
891 // fetch chart
892 {
893 auto it = attrs.find("chart");
894 if(it != attrs.end())
895 {
896 // try to find chart
897 _chart_name = it->second;
898 _linker.meshpart_link_to_chart(_name, _chart_name);
899 }
900 }
901
902 // make sure the parent is root
903 if(_parent != "root")
904 throw Xml::ContentError(iline, sline, "Invalid mesh part parent; only 'root' is accepted");
905
906 // get topology type
907 String stopo_type = attrs.find("topology")->second;
908 if(stopo_type == "none")
909 _topo_type = TopoType::none;
910 else if(stopo_type == "full")
911 _topo_type = TopoType::full;
912 else if(stopo_type == "parent")
913 {
914 _topo_type = TopoType::parent;
915 _linker.meshpart_deduct_topology(_name);
916 }
917 else
918 throw Xml::ContentError(iline, sline, "Invalid topology attribute '" + stopo_type + "'");
919
920 // split sizes
921 std::deque<String> ssize = attrs.find("size")->second.split_by_whitespaces();
922 if(ssize.size() > std::size_t(Shape_::dimension+1))
923 throw Xml::ContentError(iline, sline, "Invalid mesh part size count");
924
925 // parse sizes
926 _sizes.resize(std::size_t(Shape_::dimension+1), Index(0));
927 for(std::size_t i(0); i < ssize.size(); ++i)
928 {
929 if(!ssize.at(i).parse(_sizes.at(i)))
930 throw Xml::ContentError(iline, sline, "Failed to parse mesh part size");
931 }
932
933 // try to create the mesh part
934 _mesh_part.reset(new MeshPartType(_sizes.data(), _topo_type != TopoType::none));
935
936 // initialize
937 _have_topology.resize(std::size_t(Shape_::dimension), 0);
938 _have_mapping.resize(std::size_t(Shape_::dimension+1), 0);
939 }
940
941 virtual void close(int iline, const String& sline) override
942 {
943 // make sure we have all mappings
944 for(std::size_t i(0); i < _have_mapping.size(); ++i)
945 {
946 if((_have_mapping.at(i) == 0) && (_sizes.at(i) > Index(0)))
947 throw Xml::GrammarError(iline, sline, "Missing mapping for dimension " + stringify(i));
948 }
949
950 if(_topo_type == TopoType::full)
951 {
952 // make sure we have the whole topology
953 bool topo_all(true);
954 for(std::size_t i(0); i < _have_topology.size(); ++i)
955 {
956 // Note: there may be no entities of this dimension here
957 if(_sizes.at(i+1) > 0)
958 topo_all = topo_all && (_have_topology.at(i) != 0);
959 }
960
961 // Make sure we have either all or none topology entires
962 if(!topo_all)
963 throw Xml::GrammarError(iline, sline, "Incomplete topology");
964
965 // compute remaining topology now
966 if(topo_all)
967 RedundantIndexSetBuilder<Shape_>::compute(*_mesh_part->get_topology());
968 }
969 else if(_topo_type == TopoType::parent)
970 {
971 // Note: this has been outsourced to the MeshNodeLinker class!
972 // Create the MeshPart's topology from the parent mesh's topology if told so
973 //_mesh_part->deduct_topology(*(_root_node.get_mesh()->get_topology()));
974 //_linker.meshpart_deduct_topology(_name);
975 }
976
977 // Finally, insert mesh part into root node
978 _root_node.add_mesh_part(_name, std::move(_mesh_part)/*, _chart_name, _chart*/);
979 }
980
981 virtual std::shared_ptr<Xml::MarkupParser> markup(int iline, const String& sline, const String& name) override
982 {
983 // mapping?
984 if(name == "Mapping")
985 {
986 // create mapping parser
987 return std::make_shared<MappingParser<Shape_>>(_mesh_part->get_target_set_holder(), _have_mapping);
988 }
989
990 // topology?
991 if(name == "Topology")
992 {
993 if(_topo_type == TopoType::none)
994 throw Xml::ContentError(iline, sline, "Unexpected Topology found");
995
996 // create a topology parser
997 return std::make_shared<TopologyParser<Shape_>>(*_mesh_part->get_topology(), _have_topology);
998 }
999
1000 // attribute?
1001 if(name == "Attribute")
1002 {
1003 return std::make_shared<AttributeParser<MeshPartType>>(*_mesh_part);
1004 }
1005
1006 // invalid
1007 return nullptr;
1008 }
1009
1010 virtual bool content(int, const String&) override
1011 {
1012 return false; // no content allowed
1013 }
1014 };
1015
1016 class PatchParser :
1017 public Xml::MarkupParser
1018 {
1019 protected:
1020 Adjacency::DynamicGraph& _patches;
1021 Index _rank;
1022 Index _size;
1023 Index _read;
1024
1025 public:
1026 explicit PatchParser(Adjacency::DynamicGraph& patches) :
1027 _patches(patches),
1028 _rank(~Index(0)),
1029 _size(~Index(0)),
1030 _read(Index(0))
1031 {
1032 }
1033
1034 virtual bool attribs(std::map<String,bool>& attrs) const override
1035 {
1036 attrs.emplace("rank", true);
1037 attrs.emplace("size", true);
1038 return true;
1039 }
1040
1041 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool) override
1042 {
1043 // try to parse rank and size
1044 if(!attrs.find("rank")->second.parse(_rank))
1045 throw Xml::ContentError(iline, sline, "Cannot parse patch rank index");
1046 if(!attrs.find("size")->second.parse(_size))
1047 throw Xml::ContentError(iline, sline, "Cannot parse patch size");
1048
1049 // ensure that the rank is valid
1050 if(_rank >= _patches.get_num_nodes_domain())
1051 throw Xml::ContentError(iline, sline, "Patch rank index is out of bounds");
1052 }
1053
1054 virtual void close(int iline, const String& sline) override
1055 {
1056 if(_read < _size)
1057 throw Xml::GrammarError(iline, sline, "Invalid terminator; expected index");
1058 }
1059
1060 virtual bool content(int iline, const String& sline) override
1061 {
1062 // make sure that we do not read more points than expected
1063 if(_read >= _size)
1064 throw Xml::ContentError(iline, sline, "Invalid content; expected terminator");
1065
1066 // try to parse element index
1067 Index elem(0);
1068 if(!sline.parse(elem))
1069 throw Xml::ContentError(iline, sline, "Failed to parse element index");
1070
1071 if(elem >= _patches.get_num_nodes_image())
1072 throw Xml::ContentError(iline, sline, "Patch element index is out of bounds");
1073
1074 // insert adjacency
1075 _patches.insert(_rank, elem);
1076
1077 // okay, another one processed
1078 ++_read;
1079
1080 return true;
1081 }
1082
1083 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String&) override
1084 {
1085 return nullptr;
1086 }
1087 }; // class PatchParser
1088
1089 class PartitionParser :
1090 public Xml::MarkupParser
1091 {
1092 protected:
1093 PartitionSet& _part_set;
1094 String _name;
1095 int _prio;
1096 int _level;
1097 int _num_ranks, _num_elems;
1098 Adjacency::DynamicGraph _patches;
1099
1100 public:
1101 explicit PartitionParser(PartitionSet& part_set) :
1102 _part_set(part_set),
1103 _name(),
1104 _prio(0),
1105 _level(0),
1106 _num_ranks(0),
1107 _num_elems(0),
1108 _patches()
1109 {
1110 }
1111
1112 virtual bool attribs(std::map<String,bool>& attrs) const override
1113 {
1114 attrs.emplace("size", true);
1115 attrs.emplace("name", false);
1116 attrs.emplace("priority", false);
1117 attrs.emplace("level", false);
1118 return true;
1119 }
1120
1121 virtual void create(int iline, const String& sline, const String&, const std::map<String, String>& attrs, bool) override
1122 {
1123 // split sizes
1124 std::deque<String> ssize = attrs.find("size")->second.split_by_whitespaces();
1125 if(ssize.size() != std::size_t(2))
1126 throw Xml::ContentError(iline, sline, "Invalid partition size");
1127
1128 // parse sizes
1129 if(!ssize.front().parse(_num_ranks))
1130 throw Xml::ContentError(iline, sline, "Failed to parse partition rank count");
1131 if(!ssize.back().parse(_num_elems))
1132 throw Xml::ContentError(iline, sline, "Failed to parse partition element count");
1133
1134 // fetch name
1135 {
1136 auto it = attrs.find("name");
1137 if(it != attrs.end())
1138 _name = it->second;
1139 }
1140
1141 // fetch priority
1142 {
1143 auto it = attrs.find("priority");
1144 if(it != attrs.end())
1145 {
1146 if(!it->second.parse(_prio))
1147 throw Xml::ContentError(iline, sline, "Cannot parse partition priority");
1148 }
1149 }
1150
1151 // fetch level
1152 {
1153 auto it = attrs.find("level");
1154 if(it != attrs.end())
1155 {
1156 if(!it->second.parse(_level))
1157 throw Xml::ContentError(iline, sline, "Cannot parse partition level");
1158 if(_level < 0)
1159 throw Xml::ContentError(iline, sline, "Invalid negative partition level");
1160 }
1161 }
1162
1163 // okay, let's create a new partition
1164 _patches = Adjacency::DynamicGraph(Index(_num_ranks), Index(_num_elems));
1165 }
1166
1167 virtual void close(int, const String&) override
1168 {
1169 // add our partition to the set
1170 _part_set.add_partition(Partition(_patches, _name, _prio, _level));
1171 }
1172
1173 virtual bool content(int, const String&) override
1174 {
1175 return false;
1176 }
1177
1178 virtual std::shared_ptr<MarkupParser> markup(int, const String&, const String& name) override
1179 {
1180 if(name == "Patch")
1181 return std::make_shared<PatchParser>(_patches);
1182
1183 return nullptr;
1184 }
1185 }; // class PartitionParser
1186
1187 template<typename RootMesh_>
1188 class MeshNodeParser :
1189 public Xml::MarkupParser
1190 {
1191 public:
1192 typedef RootMesh_ RootMeshType;
1193 typedef RootMeshNode<RootMesh_> RootMeshNodeType;
1194 typedef MeshAtlas<RootMesh_> MeshAtlasType;
1195
1196 protected:
1198 RootMeshNodeType& _root_node;
1200 MeshAtlasType& _mesh_atlas;
1202 PartitionSet* _part_set;
1204 MeshNodeLinker<RootMesh_>& _linker;
1206 String _mesh_decl;
1207
1208 public:
1209 explicit MeshNodeParser(RootMeshNodeType& root_node, MeshAtlasType& mesh_atlas, PartitionSet* part_set, MeshNodeLinker<RootMesh_>& linker) :
1210 _root_node(root_node),
1211 _mesh_atlas(mesh_atlas),
1212 _part_set(part_set),
1213 _linker(linker),
1214 _mesh_decl()
1215 {
1216 }
1217
1218 virtual bool attribs(std::map<String,bool>& attrs) const override
1219 {
1220 attrs.emplace("version", true); // mandatory
1221 attrs.emplace("mesh", false); // optional
1222 return true;
1223 }
1224
1225 virtual void create(int iline, const String& sline, const String& name, const std::map<String, String>& attrs, bool) override
1226 {
1227 // verify marker name
1228 if(name != "FeatMeshFile")
1229 throw Xml::GrammarError(iline, sline, "Invalid root markup; expected '<FeatMeshFile ...>'");
1230
1231 // verify file version
1232 int version(0);
1233 if(!attrs.find("version")->second.parse(version))
1234 throw Xml::ContentError(iline, sline, "Cannot parse file version");
1235 if(version != 1)
1236 throw Xml::ContentError(iline, sline, "Invalid file version; expected 1");
1237
1238 // have a mesh declaration?
1239 auto it = attrs.find("mesh");
1240 if(it != attrs.end())
1241 {
1242 // okay, store the declarator
1243 _mesh_decl = it->second;
1244 }
1245 }
1246
1247 virtual void close(int, const String&) override
1248 {
1249 }
1250
1251 virtual bool content(int, const String&) override
1252 {
1253 return false; // no content allowed
1254 }
1255
1256 virtual std::shared_ptr<MarkupParser> markup(int iline, const String& sline, const String& name) override
1257 {
1258 // check for valid markups
1259 if(name == "Info")
1260 {
1261 // valid info markup
1262 return std::make_shared<Xml::DummyParser>();
1263 }
1264 if(name == "Chart")
1265 {
1266 // create a chart parser
1267 return std::make_shared<ChartParser<RootMeshType>>(_mesh_atlas);
1268 }
1269 if(name == "Mesh")
1270 {
1271 if(_root_node.get_mesh() != nullptr)
1272 {
1273 // that's the second one!
1274 throw Xml::GrammarError(iline, sline, "Invalid second Mesh in file");
1275 }
1276
1277 // valid mesh markup
1278 return std::make_shared<MeshParser<RootMeshType>>(_root_node);
1279 }
1280 if(name == "MeshPart")
1281 {
1282 // valid meshpart markup
1283 return std::make_shared<MeshPartParser<RootMeshType>>(_root_node, _linker);
1284 }
1285 if(name == "Partition")
1286 {
1287 // valid partition markup
1288 if(_part_set != nullptr)
1289 return std::make_shared<PartitionParser>(*_part_set);
1290 else
1291 {
1292 // the user is not interested in partitions, so create a dummy parser
1293 return std::make_shared<Xml::DummyParser>();
1294 }
1295 }
1296
1297 // anything else is invalid
1298 return nullptr;
1299 }
1300 }; // class MeshNodeParser
1301
1303
1324 {
1325 public:
1327 enum class MeshType
1328 {
1330 unknown = 0,
1332 conformal
1333 };
1334
1336 enum class ShapeType
1337 {
1339 unknown = 0,
1341 simplex,
1343 hypercube
1344 };
1345
1346 protected:
1348 std::deque<std::shared_ptr<std::stringstream>> _streams;
1350 std::deque<std::shared_ptr<Xml::Scanner>> _scanners;
1355
1356 // Split up mesh type
1357 MeshType _mesh_type;
1358 // Split up shape type
1359 ShapeType _shape_type;
1360 // Mesh shape dimension
1361 int _shape_dim;
1362 // Mesh world dimension
1363 int _world_dim;
1364
1365 public:
1367 explicit MeshFileReader() :
1368 _have_root_markup(false),
1370 _mesh_type(MeshType::unknown),
1371 _shape_type(ShapeType::unknown),
1372 _shape_dim(0),
1373 _world_dim(0)
1374 {
1375 }
1376
1383 explicit MeshFileReader(std::istream& is) :
1384 _have_root_markup(false),
1386 _mesh_type(MeshType::unknown),
1387 _shape_type(ShapeType::unknown),
1388 _shape_dim(0),
1389 _world_dim(0)
1390 {
1391 // create a new scanner object
1392 _scanners.push_back(std::make_shared<Xml::Scanner>(is));
1393 }
1394
1395 MeshFileReader(const MeshFileReader&) = delete;
1396 MeshFileReader& operator=(const MeshFileReader&) = delete;
1397
1400 {
1401 _scanners.clear();
1402 _streams.clear();
1403 }
1404
1411 void add_stream(std::istream& is)
1412 {
1413 XASSERTM(!_have_root_markup, "cannot add new stream after reading root");
1414
1415 // create a new scanner object
1416 _scanners.push_back(std::make_shared<Xml::Scanner>(is));
1417 }
1418
1431 void add_mesh_files(const Dist::Comm& comm, const std::deque<String>& filenames, String dirpath = "")
1432 {
1433 XASSERTM(!_have_root_markup, "cannot add new stream after reading root");
1434
1435 if(filenames.empty())
1436 return;
1437
1438 // ensure that the directory path ends with a path separator
1439 if(!dirpath.empty())
1440 {
1442#ifdef _WIN32
1443 if((dirpath.back() != '/') && (dirpath.back() != '\\'))
1444 dirpath.push_back('\\');
1445#else
1446 if(dirpath.back() != '/')
1447 dirpath.push_back('/');
1448#endif
1449 }
1450
1451 // read all files
1452 for(std::size_t i(0); i < filenames.size(); ++i)
1453 {
1454 // build file path
1455 String filepath = dirpath + filenames.at(i);
1456
1457 // create a new stream
1458 auto stream = std::make_shared<std::stringstream>();
1459
1460 // read the stream
1461 DistFileIO::read_common(*stream, filepath, comm);
1462
1463 // add stream to deque
1464 _streams.push_back(stream);
1465
1466 // add to mesh reader
1467 add_stream(*_streams.back());
1468 }
1469 }
1470
1480 void add_mesh_files(const std::deque<String>& filenames, String dirpath = "")
1481 {
1483 add_mesh_files(comm, filenames, dirpath);
1484 }
1485
1495 void add_mesh_file(const Dist::Comm& comm, const String& filename)
1496 {
1497 std::deque<String> filenames;
1498 filenames.push_back(filename);
1499 add_mesh_files(comm, filenames);
1500 }
1501
1508 void add_mesh_file(const String& filename)
1509 {
1511 add_mesh_file(comm, filename);
1512 }
1513
1525 {
1526 return _mesh_type_string;
1527 }
1528
1540 {
1541 return _mesh_type;
1542 }
1543
1555 {
1556 return _shape_type;
1557 }
1558
1569 int get_shape_dim() const
1570 {
1571 return _shape_dim;
1572 }
1573
1584 int get_world_dim() const
1585 {
1586 return _world_dim;
1587 }
1588
1593 {
1594 XASSERTM(!_have_root_markup, "root has already been read");
1595
1596 // loop over all scanners
1597 for(auto it = _scanners.begin(); it != _scanners.end(); ++it)
1598 {
1599 // get the scanner
1600 Xml::Scanner& scanner = **it;
1601
1602 // try to read root node
1603 scanner.read_root();
1604
1605 // verify root marker
1606 if(scanner.get_cur_name() != "FeatMeshFile")
1607 scanner.throw_grammar("Invalid mesh file");
1608
1609 // get attributes
1610 const auto& attr = scanner.get_cur_attribs();
1611
1612 // check version attribute
1613 auto it_v = attr.find("version");
1614 if(it_v == attr.end())
1615 scanner.throw_grammar("Mesh file is missing mandatory attribute 'version'");
1616 int iversion(0);
1617 if(!(it_v->second.parse(iversion)))
1618 scanner.throw_grammar("Failed to parse mesh file version attribute");
1619 if(iversion != 1)
1620 scanner.throw_grammar("Invalid mesh file version");
1621
1622 // check mesh attribute
1623 auto it_m = attr.find("mesh");
1624 if(it_m != attr.end())
1625 {
1626 // did we read a mesh type already?
1627 if(!_mesh_type_string.empty())
1628 {
1629 // make sure that the mesh types are identical
1630 XASSERTM(it_m->second == _mesh_type_string, "conflicting mesh types");
1631 }
1632 else
1633 {
1634 // save the mesh type string
1635 _mesh_type_string = it_m->second;
1636
1637 // split up mesh type string
1638 std::deque<String> mts = _mesh_type_string.split_by_string(":");
1639
1640 if(mts.size() != std::size_t(4))
1641 scanner.throw_grammar("Mesh file root markup has invalid 'mesh' attribute");
1642
1643 // check mesh type
1644 if(mts.at(0) == "conformal")
1645 _mesh_type = MeshType::conformal;
1646 else
1647 scanner.throw_grammar("Invalid 'mesh' attribute mesh type");
1648
1649 // check shape type
1650 if(mts.at(1) == "simplex")
1651 _shape_type = ShapeType::simplex;
1652 else if(mts.at(1) == "hypercube")
1653 _shape_type = ShapeType::hypercube;
1654 else
1655 scanner.throw_grammar("Invalid 'mesh' attribute shape type");
1656
1657 // parse shape dimension
1658 if(!mts.at(2).parse(_shape_dim) || (_shape_dim <= 0))
1659 scanner.throw_content("Invalid 'mesh' attribute shape dimension");
1660
1661 // parse world dimension
1662 if(!mts.at(3).parse(_world_dim) || (_world_dim <= 0))
1663 scanner.throw_content("Invalid 'mesh' attribute world dimension");
1664 }
1665 }
1666
1667 // continue with next stream
1668 }
1669
1670 // alright, root markup read
1671 _have_root_markup = true;
1672 }
1673
1691 template<typename RootMesh_>
1692 void parse(
1694 RootMeshNode<RootMesh_>& root_mesh_node,
1695 MeshAtlas<RootMesh_>& mesh_atlas,
1696 PartitionSet* part_set = nullptr)
1697 {
1698 // read root markup unless it has already been read
1701
1702 // loop over all scanners
1703 for(auto it = _scanners.begin(); it != _scanners.end(); ++it)
1704 {
1705 // create a corresponding parser and scan
1706 (*it)->set_root_parser(std::make_shared<MeshNodeParser<RootMesh_>>(root_mesh_node, mesh_atlas, part_set, linker));
1707 (*it)->scan();
1708 }
1709 }
1710
1725 template<typename RootMesh_>
1726 void parse(
1727 RootMeshNode<RootMesh_>& root_mesh_node,
1728 MeshAtlas<RootMesh_>& mesh_atlas,
1729 PartitionSet* part_set = nullptr)
1730 {
1731 // create linker
1732 MeshNodeLinker<RootMesh_> linker(root_mesh_node, mesh_atlas);
1733
1734 // parse
1735 parse(linker, root_mesh_node, mesh_atlas, part_set);
1736
1737 // execute linker
1738 linker.execute();
1739 }
1740
1756 template<typename RootMesh_>
1757 std::unique_ptr<RootMeshNode<RootMesh_>> parse(
1758 MeshAtlas<RootMesh_>& mesh_atlas,
1759 PartitionSet* part_set = nullptr)
1760 {
1761 // create new root mesh node
1762 std::unique_ptr<RootMeshNode<RootMesh_>> root_mesh_node =
1763 RootMeshNode<RootMesh_>::make_unique(nullptr, &mesh_atlas);
1764
1765 // parse
1766 this->parse(*root_mesh_node, mesh_atlas, part_set);
1767
1768 // return root mesh node
1769 return root_mesh_node;
1770 }
1771 }; // class MeshFileReader
1772
1787 template<typename RootMesh_, int world_dim>
1789 {
1790 static_assert(RootMesh_::world_dim == world_dim, "Nonmatching world_dim.");
1791
1802 static std::shared_ptr<Xml::MarkupParser> markup(const String& DOXY(name),
1803 std::unique_ptr<Atlas::ChartBase<RootMesh_>>& DOXY(chart))
1804 {
1805 return nullptr;
1806 }
1807 };
1808
1810 template<typename RootMesh_>
1811 struct DimensionalChartHelper<RootMesh_,2>
1812 {
1813 static std::shared_ptr<Xml::MarkupParser> markup(const String& name,
1814 std::unique_ptr<Atlas::ChartBase<RootMesh_>>& chart)
1815 {
1816 if(name == "Circle")
1817 return std::make_shared<Atlas::CircleChartParser<RootMesh_>>(chart);
1818 if(name == "Bezier")
1819 return std::make_shared<Atlas::BezierChartParser<RootMesh_>>(chart);
1820
1821 return nullptr;
1822 }
1823 };
1824
1825 template<typename RootMesh_>
1826 struct DimensionalChartHelper<RootMesh_,3>
1827 {
1828 static std::shared_ptr<Xml::MarkupParser> markup(const String& name,
1829 std::unique_ptr<Atlas::ChartBase<RootMesh_>>& chart)
1830 {
1831 if(name == "Sphere")
1832 return std::make_shared<Atlas::SphereChartParser<RootMesh_>>(chart);
1833 if(name == "SurfaceMesh")
1834 return std::make_shared<Atlas::SurfaceMeshChartParser<RootMesh_>>(chart);
1835 if(name == "Extrude")
1836 return std::make_shared<Atlas::ExtrudeChartParser<RootMesh_>>(chart);
1837
1838 return nullptr;
1839 }
1840 };
1842
1843#ifdef FEAT_EICKT
1844 extern template class MeshNodeLinker<ConformalMesh<Shape::Simplex<2>, 2, Real>>;
1845 extern template class MeshNodeLinker<ConformalMesh<Shape::Simplex<3>, 3, Real>>;
1846 extern template class MeshNodeLinker<ConformalMesh<Shape::Hypercube<2>, 2, Real>>;
1847 extern template class MeshNodeLinker<ConformalMesh<Shape::Hypercube<3>, 3, Real>>;
1848
1849 extern template void MeshFileReader::parse<ConformalMesh<Shape::Simplex<2>, 2, Real>>(
1850 MeshNodeLinker<ConformalMesh<Shape::Simplex<2>, 2, Real>>&,
1851 RootMeshNode<ConformalMesh<Shape::Simplex<2>, 2, Real>>&,
1852 MeshAtlas<ConformalMesh<Shape::Simplex<2>, 2, Real>>&,
1853 PartitionSet*);
1854 extern template void MeshFileReader::parse<ConformalMesh<Shape::Simplex<3>, 3, Real>>(
1855 MeshNodeLinker<ConformalMesh<Shape::Simplex<3>, 3, Real>>&,
1856 RootMeshNode<ConformalMesh<Shape::Simplex<3>, 3, Real>>&,
1857 MeshAtlas<ConformalMesh<Shape::Simplex<3>, 3, Real>>&,
1858 PartitionSet*);
1859 extern template void MeshFileReader::parse<ConformalMesh<Shape::Hypercube<2>, 2, Real>>(
1860 MeshNodeLinker<ConformalMesh<Shape::Hypercube<2>, 2, Real>>&,
1861 RootMeshNode<ConformalMesh<Shape::Hypercube<2>, 2, Real>>&,
1862 MeshAtlas<ConformalMesh<Shape::Hypercube<2>, 2, Real>>&,
1863 PartitionSet*);
1864 extern template void MeshFileReader::parse<ConformalMesh<Shape::Hypercube<3>, 3, Real>>(
1865 MeshNodeLinker<ConformalMesh<Shape::Hypercube<3>, 3, Real>>&,
1866 RootMeshNode<ConformalMesh<Shape::Hypercube<3>, 3, Real>>&,
1867 MeshAtlas<ConformalMesh<Shape::Hypercube<3>, 3, Real>>&,
1868 PartitionSet*);
1869#endif // FEAT_EICKT
1870 } // namespace Geometry
1871} // namespace FEAT
#define XABORTM(msg)
Abortion macro definition with custom message.
Definition: assertion.hpp:192
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Communicator class.
Definition: dist.hpp:1349
static Comm world()
Returns a copy of the world communicator.
Definition: dist.cpp:429
static void read_common(std::stringstream &stream, const String &filename, const Dist::Comm &comm, int root_rank=0)
Reads a common text file for all ranks.
Base exception class.
Definition: exception.hpp:27
Mesh Atlas class template.
Definition: mesh_atlas.hpp:32
MeshChartType * find_mesh_chart(const String &name)
Searches for a mesh chart.
Definition: mesh_atlas.hpp:162
void add_mesh_files(const Dist::Comm &comm, const std::deque< String > &filenames, String dirpath="")
Adds a list of mesh files to the list of streams to be parsed.
void add_mesh_file(const String &filename)
Adds a single mesh file to the list of streams to be parsed.
MeshFileReader(std::istream &is)
Input-Stream constructor.
const String & get_meshtype_string() const
Returns the mesh-type string from the root markup node.
int get_shape_dim() const
Returns the shape-dimension from the root markup node.
virtual ~MeshFileReader()
virtual destructor
void parse(MeshNodeLinker< RootMesh_ > &linker, RootMeshNode< RootMesh_ > &root_mesh_node, MeshAtlas< RootMesh_ > &mesh_atlas, PartitionSet *part_set=nullptr)
Parses the mesh file into a mesh node and a mesh atlas.
void parse(RootMeshNode< RootMesh_ > &root_mesh_node, MeshAtlas< RootMesh_ > &mesh_atlas, PartitionSet *part_set=nullptr)
Parses the mesh file into a mesh node and a mesh atlas.
ShapeType get_shape_type() const
Returns the shape-type from the root markup node.
void add_mesh_file(const Dist::Comm &comm, const String &filename)
Adds a single mesh file to the list of streams to be parsed.
String _mesh_type_string
The parsed mesh type.
std::deque< std::shared_ptr< std::stringstream > > _streams
Our internally managed streams.
MeshType get_mesh_type() const
Returns the mesh-type from the root markup node.
void add_mesh_files(const std::deque< String > &filenames, String dirpath="")
Adds a list of mesh files to the list of streams to be parsed.
void add_stream(std::istream &is)
Adds an input stream to the list of streams to be parsed.
int get_world_dim() const
Returns the world-dimension from the root markup node.
std::deque< std::shared_ptr< Xml::Scanner > > _scanners
Our Xml scanner objects.
std::unique_ptr< RootMeshNode< RootMesh_ > > parse(MeshAtlas< RootMesh_ > &mesh_atlas, PartitionSet *part_set=nullptr)
Parses the mesh file into a mesh node and a mesh atlas.
bool _have_root_markup
Did we read the root markup yet?
void read_root_markup()
Reads the root markup from the input stream and analyses it.
MeshNodeLinker Error class.
MeshNode liner class template.
void meshpart_deduct_topology(const String &meshpart)
Adds a task to deduct a meshpart topology from the root mesh.
MeshAtlas< RootMesh_ > & _atlas
our atlas
RootMeshNode< RootMesh_ > & _mesh_node
our mesh node
void meshpart_link_to_chart(const String &meshpart, const String &chart)
Adds a task to link a meshpart to a chart.
void execute()
Executes the linker.
MeshNodeLinker(RootMeshNode< RootMesh_ > &mesh_node, MeshAtlas< RootMesh_ > &atlas)
Constructor.
Class template for partial meshes.
Definition: mesh_part.hpp:90
void deduct_topology(const ParentIndexSetHolderType &parent_ish)
Fills the mesh topology from parent information.
Definition: mesh_part.hpp:547
Root mesh node class template.
Definition: mesh_node.hpp:748
static std::unique_ptr< RootMeshNode > make_unique(std::unique_ptr< MeshType > mesh, MeshAtlasType *atlas=nullptr)
Creates a new RootMeshNode on the heap and returns a unique pointer to it.
Definition: mesh_node.hpp:837
String class implementation.
Definition: string.hpp:46
std::deque< String > split_by_string(const String &delimiter) const
Splits the string by a delimiter substring.
Definition: string.hpp:539
String trim(const String &charset) const
Trims the string.
Definition: string.hpp:327
XML Markup Parser interface.
XML Scanner class.
void read_root()
Tries to read the XML root markup.
Definition: xml_scanner.cpp:92
void throw_content(const String &msg) const
Throws a ContentError for the current line.
void throw_grammar(const String &msg) const
Throws a GrammarError for the current line.
const std::map< String, String > & get_cur_attribs() const
const String & get_cur_name() const
@ parent
indicates that the level is a parent level
@ full
full Uzawa preconditioner
FEAT namespace.
Definition: adjactor.hpp:12
double Real
Real data type.
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:944
std::uint64_t Index
Index data type.
World dimension dependent helper class for parsing charts.
static std::shared_ptr< Xml::MarkupParser > markup(const String &name, std::unique_ptr< Atlas::ChartBase< RootMesh_ > > &chart)
Creates a parser for a chart, its type identified by a name String.