1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 
4 #include <config.h>
5 
6 #include <dune/grid/onedgrid/onedgridfactory.hh>
7 #include <dune/grid/onedgrid/onedgridindexsets.hh>
8 
9 using namespace Dune;
10 
11 
12 Dune::GridFactory<Dune::OneDGrid >::
GridFactory()13 GridFactory() :
14   factoryOwnsGrid_(true),
15   vertexIndex_(0)
16 {
17   grid_ = new OneDGrid;
18 
19   createBegin();
20 }
21 
22 Dune::GridFactory<Dune::OneDGrid >::
GridFactory(OneDGrid * grid)23 GridFactory(OneDGrid* grid) :
24   factoryOwnsGrid_(false),
25   vertexIndex_(0)
26 {
27   grid_ = grid;
28 
29   createBegin();
30 }
31 
32 Dune::GridFactory<Dune::OneDGrid>::
~GridFactory()33 ~GridFactory()
34 {
35   if (grid_ && factoryOwnsGrid_)
36     delete grid_;
37 }
38 
39 void Dune::GridFactory<Dune::OneDGrid>::
insertVertex(const Dune::FieldVector<GridFactory<OneDGrid>::ctype,1> & pos)40 insertVertex(const Dune::FieldVector<GridFactory<OneDGrid >::ctype,1>& pos)
41 {
42   vertexPositions_.insert(std::make_pair(pos, vertexIndex_++));
43 }
44 
45 void Dune::GridFactory<Dune::OneDGrid>::
insertElement(const GeometryType & type,const std::vector<unsigned int> & vertices)46 insertElement(const GeometryType& type,
47               const std::vector<unsigned int>& vertices)
48 {
49   if (type.dim() != 1)
50     DUNE_THROW(GridError, "You cannot insert a " << type << " into a OneDGrid!");
51 
52   if (vertices.size() != 2)
53     DUNE_THROW(GridError, "You cannot insert an element with " << vertices.size() << " vertices into a OneDGrid!");
54 
55   elements_.push_back(std::array<unsigned int,2>());
56   elements_.back()[0] = vertices[0];
57   elements_.back()[1] = vertices[1];
58 }
59 
60 void Dune::GridFactory<Dune::OneDGrid>::
insertBoundarySegment(const std::vector<unsigned int> & vertices)61 insertBoundarySegment(const std::vector<unsigned int>& vertices)
62 {
63   if (vertices.size() != 1)
64     DUNE_THROW(GridError, "OneDGrid BoundarySegments must have exactly one vertex.");
65 
66   boundarySegments_.push_back(vertices[0]);
67 }
68 
69 void Dune::GridFactory<Dune::OneDGrid>::
insertBoundarySegment(const std::vector<unsigned int> & vertices,const std::shared_ptr<BoundarySegment<1>> &)70 insertBoundarySegment(const std::vector<unsigned int>& vertices,
71                       const std::shared_ptr<BoundarySegment<1> > & /* boundarySegment */)
72 {
73   insertBoundarySegment(vertices);
74 }
75 
76 bool Dune::GridFactory<Dune::OneDGrid>::
wasInserted(const typename OneDGrid::LeafIntersection & intersection) const77 wasInserted(const typename OneDGrid::LeafIntersection& intersection) const
78 {
79   bool inserted(false);
80   const auto vtx(intersection.geometry().center()[0]);
81   for(const auto& idx : boundarySegments_)
82     if(std::abs(vertexPositionsByIndex_[idx]-vtx)<1.e-12)
83     {
84       inserted=true;
85       break;
86     }
87   return inserted;
88 }
89 
90 unsigned int Dune::GridFactory<Dune::OneDGrid>::
insertionIndex(const typename OneDGrid::LeafIntersection & intersection) const91 insertionIndex(const typename OneDGrid::LeafIntersection& intersection) const
92 {
93   unsigned int insertionIdx(0);
94   const auto vtx(intersection.geometry().center()[0]);
95   for(const auto& idx : boundarySegments_)
96     if(std::abs(vertexPositionsByIndex_[idx]-vtx)<1.e-12)
97       break;
98     else
99       ++insertionIdx;
100   return insertionIdx;
101 }
102 
103 std::unique_ptr<OneDGrid> Dune::GridFactory<Dune::OneDGrid>::
createGrid()104 createGrid()
105 {
106   // Prevent a crash when this method is called twice in a row
107   // You never know who may do this...
108   if (grid_==nullptr)
109     return nullptr;
110 
111   // Assert that vertices are given
112   assert (vertexPositions_.size() > 0);
113 
114   // Insert the vertices into the grid
115   grid_->entityImps_.resize(1);
116   for (const auto& vtx : vertexPositions_)
117   {
118     OneDEntityImp<0> newVertex(0, vtx.first, grid_->getNextFreeId());
119 
120     newVertex.leafIndex_ = vtx.second;
121     newVertex.levelIndex_ = vtx.second;
122 
123     grid_->vertices(0).push_back(newVertex);
124   }
125 
126   // Fill the vector with the vertex positions accessible by index
127   vertexPositionsByIndex_.resize(vertexPositions_.size());
128   for (const auto& vtx : vertexPositions_)
129     vertexPositionsByIndex_[vtx.second] = vtx.first;
130 
131   // Set the numbering of the boundary segments
132   if (boundarySegments_.size() > 2)
133     DUNE_THROW(GridError, "You cannot provide more than two boundary segments to a OneDGrid (it must be connected).");
134 
135   if (boundarySegments_.size() > 1
136       && vertexPositionsByIndex_[boundarySegments_[0]] > vertexPositions_.begin()->first[0])
137     grid_->reversedBoundarySegmentNumbering_ = true;
138 
139   // ///////////////////////////////////////////////////////////////////
140   //   Insert the elements into the grid
141   //
142   // This is a 1d grid and it has to be connected. Hence we actually
143   // know where the elements are, even without being told explicitly.
144   // The only thing of interest are the indices.
145   // ///////////////////////////////////////////////////////////////////
146 
147   // First sort elements by increasing position. That is how they are expected in the grid data structure
148   std::map<ctype, std::pair<std::array<unsigned int, 2>, unsigned int> > elementsByPosition;
149   for (std::size_t i=0; i<elements_.size(); i++)
150     elementsByPosition.insert(std::make_pair(vertexPositionsByIndex_[elements_[i][0]],     // order by position of left vertex
151                                              std::make_pair(elements_[i], i)      // the element and its position in the insertion sequence
152                                              ));
153 
154   auto it = std::get<0>(grid_->entityImps_[0]).begin();
155   auto eIt = elementsByPosition.begin();
156 
157   // Looping over the vertices to get all elements assumes that the grid is connected
158   for (size_t i=0; i<vertexPositions_.size()-1; i++, ++eIt)
159   {
160     OneDEntityImp<1> newElement(0, grid_->getNextFreeId(), grid_->reversedBoundarySegmentNumbering_);
161     newElement.vertex_[0] = it;
162     it = it->succ_;
163     newElement.vertex_[1] = it;
164 
165     newElement.levelIndex_ = eIt->second.second;
166     newElement.leafIndex_  = eIt->second.second;
167 
168     grid_->elements(0).push_back(newElement);
169   }
170 
171   // Create the index sets
172   grid_->levelIndexSets_.resize(1);
173   grid_->levelIndexSets_[0] = new OneDGridLevelIndexSet<const OneDGrid>(*grid_, 0);
174   grid_->levelIndexSets_[0]->setSizesAndTypes(vertexPositions_.size(), elements_.size());
175 
176   grid_->leafIndexSet_.setSizesAndTypes(vertexPositions_.size(), elements_.size());
177 
178   // Hand over the grid and delete the member pointer
179   auto tmp = grid_;
180   grid_ = nullptr;
181   return std::unique_ptr<OneDGrid>(tmp);
182 }
183 
184 void Dune::GridFactory<Dune::OneDGrid >::
createBegin()185 createBegin()
186 {
187   vertexPositions_.clear();
188 }
189