1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 #ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH
4 #define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH
5 
6 #include <dune/common/concept.hh>
7 #include <dune/common/hybridutilities.hh>
8 #include <dune/common/indices.hh>
9 
10 #include <dune/functions/common/indexaccess.hh>
11 #include <dune/functions/common/utility.hh>
12 #include <dune/functions/common/type_traits.hh>
13 #include <dune/functions/functionspacebases/concepts.hh>
14 
15 
16 namespace Dune {
17 namespace Functions {
18 
19 
20 
21 namespace Imp {
22 
23   // Construct default coefficent type from vector and multiindex type
24   // This requires that MultiIndex has a static size. Otherwise the
25   // vector type itself is returned.
26   template<class V, class MultiIndex>
27   struct CoefficientType
28   {
29     template<class E, std::size_t size>
30     struct DefaultCoefficientTypeHelper
31     {
32       using E0 = decltype(std::declval<E>()[Dune::Indices::_0]);
33       using type = typename DefaultCoefficientTypeHelper<E0, size-1>::type;
34     };
35 
36     template<class E>
37     struct DefaultCoefficientTypeHelper<E, 0>
38     {
39       using type = E;
40     };
41 
42     template<class MI,
43       typename std::enable_if<HasStaticSize<MI>::value, int>::type = 0>
getStaticSizeOrZeroDune::Functions::Imp::CoefficientType44     static constexpr std::size_t getStaticSizeOrZero()
45     {
46       return StaticSize<MI>::value;
47     }
48 
49     template<class MI,
50       typename std::enable_if<not HasStaticSize<MI>::value, int>::type = 0>
getStaticSizeOrZeroDune::Functions::Imp::CoefficientType51     static constexpr std::size_t getStaticSizeOrZero()
52     {
53       return 0;
54     }
55 
56     using type = typename DefaultCoefficientTypeHelper<V, getStaticSizeOrZero<MultiIndex>()>::type;
57   };
58 
59 
60 
61   // This tag class is used as Coefficient template parameter
62   // for HierarchicVectorWrapper if the coefficient type should
63   // be deduced.
64   struct DeducedCoefficientTag {};
65 
66 } // namespace Imp
67 
68 
69 
70 /**
71  * \brief A wrapper providing multiindex access to vector entries
72  *
73  * The coefficient type should be a type such that the coefficients
74  * entries for each global basis function can be cast to this type.
75  * This is necessary because the wrapper cannot determine this type
76  * automatically for multi-type containers and non-uniform indices.
77  * The reason for this is, that the multi-index type will then be
78  * dynamically sized such that the index depth cannot statically
79  * be determined from the multi-indices. However, the compiler needs
80  * a fixed termination criterion for instantiation of recursive
81  * functions.
82  *
83  * If no coefficient type is given, the wrapper tries to determine
84  * the coefficient type on its own assuming that the multi-indices
85  * have fixed size.
86  *
87  * \tparam V Type of the raw wrapper vector
88  * \tparam CO Coefficient type
89  */
90 template<class V, class CO=Imp::DeducedCoefficientTag>
91 class HierarchicVectorWrapper
92 {
93   template<class MultiIndex>
94   using Coefficient = typename std::conditional< std::is_same<Imp::DeducedCoefficientTag,CO>::value and HasStaticSize<MultiIndex>::value,
95             typename Imp::CoefficientType<V, MultiIndex>::type,
96             CO
97             >::type;
98 
99 
100   using size_type = std::size_t;
101 
102   template<class C, class SizeProvider,
103     typename std::enable_if< not models<Concept::HasResize, C>(), int>::type = 0,
104     typename std::enable_if< not models<Concept::HasSizeMethod, C>(), int>::type = 0>
resizeHelper(C & c,const SizeProvider & sizeProvider,typename SizeProvider::SizePrefix prefix)105   static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix)
106   {
107     auto size = sizeProvider.size(prefix);
108     if (size != 0)
109       DUNE_THROW(RangeError, "Can't resize scalar vector entry v[" << prefix << "] to size(" << prefix << ")=" << size);
110   }
111 
112   struct StaticResizeHelper
113   {
114     template<class I, class C, class SizeProvider>
applyDune::Functions::HierarchicVectorWrapper::StaticResizeHelper115     static void apply(I&& i, C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix)
116     {
117       prefix.back() = i;
118       resizeHelper(c[i], sizeProvider, prefix);
119     }
120   };
121 
122   template<class C, class SizeProvider,
123     typename std::enable_if< not models<Concept::HasResize, C>(), int>::type = 0,
124     typename std::enable_if< models<Concept::HasSizeMethod, C>(), int>::type = 0>
resizeHelper(C & c,const SizeProvider & sizeProvider,typename SizeProvider::SizePrefix prefix)125   static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix)
126   {
127     auto size = sizeProvider.size(prefix);
128     if (size == 0)
129       return;
130 
131     if (c.size() != size)
132       DUNE_THROW(RangeError, "Can't resize statically sized vector entry v[" << prefix << "] of size " << c.size() << " to size(" << prefix << ")=" << size);
133 
134     using namespace Dune::Hybrid;
135     prefix.push_back(0);
136     forEach(integralRange(Hybrid::size(c)), [&](auto&& i) {
137         StaticResizeHelper::apply(i, c, sizeProvider, prefix);
138       });
139   }
140 
141   template<class C, class SizeProvider,
142     typename std::enable_if< models<Concept::HasResize, C>(), int>::type = 0>
resizeHelper(C & c,const SizeProvider & sizeProvider,typename SizeProvider::SizePrefix prefix)143   static void resizeHelper(C& c, const SizeProvider& sizeProvider, typename SizeProvider::SizePrefix prefix)
144   {
145     auto size = sizeProvider.size(prefix);
146     if (size==0)
147     {
148       if (c.size()==0)
149         DUNE_THROW(RangeError, "Can't resize dynamically sized vector entry v[" << prefix << "]. Its size is 0 but the target size is unknown due to size(" << prefix << ")=0.");
150       else
151         return;
152     }
153 
154     c.resize(size);
155     prefix.push_back(0);
156     for(std::size_t i=0; i<size; ++i)
157     {
158       prefix.back() = i;
159       resizeHelper(c[i], sizeProvider, prefix);
160     }
161   }
162 
163 
164 
165 public:
166 
167   using Vector = V;
168 
169   template<class MultiIndex>
170   using Entry = Coefficient<MultiIndex>;
171 
HierarchicVectorWrapper(Vector & vector)172   HierarchicVectorWrapper(Vector& vector) :
173     vector_(&vector)
174   {}
175 
176   template<class SizeProvider>
resize(const SizeProvider & sizeProvider)177   void resize(const SizeProvider& sizeProvider)
178   {
179     typename SizeProvider::SizePrefix prefix;
180     prefix.resize(0);
181     resizeHelper(*vector_, sizeProvider, prefix);
182   }
183 
184   template<class MultiIndex>
operator [](const MultiIndex & index) const185   const Entry<MultiIndex>& operator[](const MultiIndex& index) const
186   {
187       static_assert(not std::is_same<Imp::DeducedCoefficientTag,Entry<MultiIndex>>::value, "Coefficient type for HierarchicVectorWrapper and given multi-index type cannot be determined automatically!");
188       return hybridMultiIndexAccess<const Entry<MultiIndex>&>(*vector_, index);
189   }
190 
191   template<class MultiIndex>
operator [](const MultiIndex & index)192   Entry<MultiIndex>& operator[](const MultiIndex& index)
193   {
194       static_assert(not std::is_same<Imp::DeducedCoefficientTag,Entry<MultiIndex>>::value, "Coefficient type for HierarchicVectorWrapper and given multi-index type cannot be determined automatically!");
195       return hybridMultiIndexAccess<Entry<MultiIndex>&>(*vector_, index);
196   }
197 
198   template<class MultiIndex>
operator ()(const MultiIndex & index) const199   const Entry<MultiIndex>& operator()(const MultiIndex& index) const
200   {
201       static_assert(not std::is_same<Imp::DeducedCoefficientTag,Entry<MultiIndex>>::value, "Coefficient type for HierarchicVectorWrapper and given multi-index type cannot be determined automatically!");
202       return (*this)[index];
203   }
204 
205   template<class MultiIndex>
operator ()(const MultiIndex & index)206   Entry<MultiIndex>& operator()(const MultiIndex& index)
207   {
208       static_assert(not std::is_same<Imp::DeducedCoefficientTag,Entry<MultiIndex>>::value, "Coefficient type for HierarchicVectorWrapper and given multi-index type cannot be determined automatically!");
209       return (*this)[index];
210   }
211 
vector() const212   const Vector& vector() const
213   {
214     return *vector_;
215   }
216 
vector()217   Vector& vector()
218   {
219     return *vector_;
220   }
221 
222 private:
223 
224   Vector* vector_;
225 };
226 
227 
228 
229 
230 template<class V>
hierarchicVector(V & v)231 HierarchicVectorWrapper< V > hierarchicVector(V& v)
232 {
233   return HierarchicVectorWrapper<V>(v);
234 }
235 
236 
237 
238 template<class MultiIndex, class V,
239     typename std::enable_if< models<Concept::HasIndexAccess, V, MultiIndex>(), int>::type = 0>
240 V& makeHierarchicVectorForMultiIndex(V& v)
241 {
242   return v;
243 }
244 
245 
246 
247 template<class MultiIndex, class V,
248     typename std::enable_if< not models<Concept::HasIndexAccess, V, MultiIndex>(), int>::type = 0>
249 HierarchicVectorWrapper< V > makeHierarchicVectorForMultiIndex(V& v)
250 {
251   return HierarchicVectorWrapper<V>(v);
252 }
253 
254 
255 
256 } // namespace Dune::Functions
257 } // namespace Dune
258 
259 
260 #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_HIERARCHICVECTORWRAPPER_HH
261