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