dune-functions 2.9.0
compositebasis.hh
Go to the documentation of this file.
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_COMPOSITEBASIS_HH
4#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
5
6#include <tuple>
7#include <utility>
8
9#include <dune/common/std/apply.hh>
10#include <dune/common/hybridutilities.hh>
11#include <dune/common/reservedvector.hh>
12#include <dune/common/typeutilities.hh>
13#include <dune/common/hybridutilities.hh>
14#include <dune/common/tupleutility.hh>
15#include <dune/common/tuplevector.hh>
16
24
25
26namespace Dune {
27namespace Functions {
28
29// *****************************************************************************
30// This is the reusable part of the composite bases. It contains
31//
32// CompositePreBasis
33//
34// The pre-basis allows to create the others and is the owner of possible shared
35// state. These components do _not_ depend on the global basis and local view
36// and can be used without a global basis.
37// *****************************************************************************
38
39
51template<class IMS, class... SPB>
53{
54 static const bool isBlocked = std::is_same_v<IMS,BasisFactory::BlockedLexicographic> or std::is_same_v<IMS,BasisFactory::BlockedInterleaved>;
55public:
56
58 using SubPreBases = std::tuple<SPB...>;
59
61 template<std::size_t i>
62 using SubPreBasis = std::tuple_element_t<i, SubPreBases>;
63
65 using GridView = typename std::tuple_element_t<0, SubPreBases>::GridView;
66
68 using size_type = std::size_t;
69
72
73protected:
74 static const std::size_t children = sizeof...(SPB);
75
76 using ChildIndices = std::make_index_sequence<children>;
77
78public:
79
81 using Node = CompositeBasisNode<typename SPB::Node...>;
82
83 static constexpr size_type maxMultiIndexSize = std::max({SPB::maxMultiIndexSize...}) + isBlocked;
84 static constexpr size_type minMultiIndexSize = std::min({SPB::minMultiIndexSize...}) + isBlocked;
85 static constexpr size_type multiIndexBufferSize = std::max({SPB::multiIndexBufferSize...}) + isBlocked;
86
92 template<class... SFArgs,
93 disableCopyMove<CompositePreBasis, SFArgs...> = 0,
94 enableIfConstructible<std::tuple<SPB...>, SFArgs...> = 0>
95 CompositePreBasis(SFArgs&&... sfArgs) :
96 subPreBases_(std::forward<SFArgs>(sfArgs)...)
97 {
98 Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
99 static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
100 });
101 }
102
109 template<class GV,
110 std::enable_if_t<std::conjunction_v<
111 std::bool_constant<(children > 1)>, // Avoid ambiguous constructor if there's only one child
112 std::is_same<GV, GridView>,
113 std::is_constructible<SPB, GridView>...
114 >, int> = 0>
115 CompositePreBasis(const GV& gv) :
116 subPreBases_(SPB(gv)...)
117 {
118 Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
119 static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
120 });
121 }
122
125 {
126 Hybrid::forEach(ChildIndices(), [&](auto i) {
127 this->subPreBasis(i).initializeIndices();
128 });
129 }
130
132 const GridView& gridView() const
133 {
134 return std::get<0>(subPreBases_).gridView();
135 }
136
138 void update(const GridView& gv)
139 {
140 Hybrid::forEach(ChildIndices(), [&](auto i) {
141 this->subPreBasis(i).update(gv);
142 });
143 }
144
149 {
150 auto node = Node{};
151 Hybrid::forEach(ChildIndices(), [&](auto i) {
152 node.setChild(this->subPreBasis(i).makeNode(), i);
153 });
154 return node;
155 }
156
159 {
160 return size(Dune::ReservedVector<size_type, multiIndexBufferSize>{});
161 }
162
164 template<class SizePrefix>
165 size_type size(const SizePrefix& prefix) const
166 {
167 return size(prefix, IndexMergingStrategy{});
168 }
169
170private:
171
172 template<class SizePrefix>
173 size_type size(const SizePrefix& prefix, BasisFactory::BlockedLexicographic) const
174 {
175 if (prefix.size() == 0)
176 return children;
177
178 return Hybrid::switchCases(ChildIndices(), prefix[0], [&] (auto i) {
179 SizePrefix subPrefix;
180 for(std::size_t i=1; i<prefix.size(); ++i)
181 subPrefix.push_back(prefix[i]);
182 return this->subPreBasis(i).size(subPrefix);
183 }, []() {
184 return size_type(0);
185 });
186 }
187
188 template<class SizePrefix>
189 size_type size(const SizePrefix& prefix, BasisFactory::FlatLexicographic) const
190 {
191 size_type result = 0;
192 if (prefix.size() == 0)
193 Hybrid::forEach(ChildIndices(), [&](auto i) {
194 result += this->subPreBasis(i).size();
195 });
196 else {
197 size_type shiftedFirstDigit = prefix[0];
198 staticFindInRange<0, children>([&](auto i) {
199 auto firstDigitSize = this->subPreBasis(i).size();
200 if (shiftedFirstDigit < firstDigitSize)
201 {
202 SizePrefix subPrefix;
203 subPrefix.push_back(shiftedFirstDigit);
204 for(std::size_t i=1; i<prefix.size(); ++i)
205 subPrefix.push_back(prefix[i]);
206 result = this->subPreBasis(i).size(subPrefix);
207 return true;
208 }
209 shiftedFirstDigit -= firstDigitSize;
210 return false;
211 });
212 }
213 return result;
214 }
215
216public:
217
220 {
221 size_type r=0;
222 // Accumulate dimension() for all subprebases
223 Hybrid::forEach(ChildIndices(), [&](auto i) {
224 r += this->subPreBasis(i).dimension();
225 });
226 return r;
227 }
228
231 {
232 size_type r=0;
233 // Accumulate maxNodeSize() for all subprebases
234 Hybrid::forEach(ChildIndices(), [&](auto i) {
235 r += this->subPreBasis(i).maxNodeSize();
236 });
237 return r;
238 }
239
241 template<std::size_t i>
242 const SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {}) const
243 {
244 return std::get<i>(subPreBases_);
245 }
246
248 template<std::size_t i>
249 SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {})
250 {
251 return std::get<i>(subPreBases_);
252 }
253
255 template<typename It>
256 It indices(const Node& node, It it) const
257 {
258 return indices(node, it, IndexMergingStrategy{});
259 }
260
261private:
262
263 template<typename It>
264 It indices(const Node& node, It multiIndices, BasisFactory::FlatLexicographic) const
265 {
266 size_type firstComponentOffset = 0;
267 // Loop over all children
268 Hybrid::forEach(ChildIndices(), [&](auto child){
269 size_type subTreeSize = node.child(child).size();
270 // Fill indices for current child into index buffer starting from current
271 // buffer position and shift first index component of any index for current
272 // child by suitable offset to get lexicographic indices.
273 subPreBasis(child).indices(node.child(child), multiIndices);
274 for (std::size_t i = 0; i<subTreeSize; ++i)
275 multiIndices[i][0] += firstComponentOffset;
276 // Increment offset by the size for first index component of the current child
277 firstComponentOffset += subPreBasis(child).size();
278 // Increment buffer iterator by the number of indices processed for current child
279 multiIndices += subTreeSize;
280 });
281 return multiIndices;
282 }
283
284 template<class MultiIndex>
285 static void multiIndexPushFront(MultiIndex& M, size_type M0)
286 {
287 M.resize(M.size()+1);
288 for(std::size_t i=M.size()-1; i>0; --i)
289 M[i] = M[i-1];
290 M[0] = M0;
291 }
292
293 template<typename It>
294 It indices(const Node& node, It multiIndices, BasisFactory::BlockedLexicographic) const
295 {
296 // Loop over all children
297 Hybrid::forEach(ChildIndices(), [&](auto child){
298 size_type subTreeSize = node.child(child).size();
299 // Fill indices for current child into index buffer starting from current position
300 subPreBasis(child).indices(node.child(child), multiIndices);
301 // Insert child index before first component of all indices of current child.
302 for (std::size_t i = 0; i<subTreeSize; ++i)
303 this->multiIndexPushFront(multiIndices[i], child);
304 // Increment buffer iterator by the number of indices processed for current child
305 multiIndices += subTreeSize;
306 });
307 return multiIndices;
308 }
309
310 std::tuple<SPB...> subPreBases_;
311};
312
313
314
315namespace BasisFactory {
316
317namespace Imp {
318
319template<class IndexMergingStrategy, class... ChildPreBasisFactory>
320class CompositePreBasisFactory
321{
322
323 template<class GridView, class... ChildPreBasis>
324 auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
325 {
326 return CompositePreBasis<IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
327 }
328
329public:
330
331 CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
332 childPreBasisFactories_(childPreBasisFactory...)
333 {}
334
335 CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
336 childPreBasisFactories_(std::move(childPreBasisFactory)...)
337 {}
338
339 template<class GridView>
340 auto operator()(const GridView& gridView) const
341 {
342 // Use std::apply to unpack the tuple childPreBasisFactories_
343 return std::apply([&](const auto&... childPreBasisFactory) {
344 return this->makePreBasisFromChildPreBases(gridView, childPreBasisFactory(gridView)...);
345 }, childPreBasisFactories_);
346 }
347
348private:
349 std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
350};
351
352} // end namespace BasisFactory::Imp
353
354
355
366template<
367 typename... Args,
368 std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
369auto composite(Args&&... args)
370{
371 // We have to separate the last entry which is the IndexMergingStrategy
372 // and the preceding ones, which are the ChildPreBasisFactories
373
374 using ArgTuple = std::tuple<std::decay_t<Args>...>;
375
376 // Compute number of children and index of the IndexMergingStrategy argument
377 constexpr std::size_t children = Dune::SizeOf<Args...>::value-1;
378
379 // Use last type as IndexMergingStrategy
380 using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
381
382 // Index sequence for all but the last entry for partial tuple unpacking
383 auto childIndices = std::make_index_sequence<children>{};
384
385 // Unpack tuple only for those entries related to children
386 return applyPartial([](auto&&... childPreBasisFactory){
387 return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
388 },
389 std::forward_as_tuple(std::forward<Args>(args)...),
390 childIndices);
391}
392
404template<
405 typename... Args,
406 std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
407auto composite(Args&&... args)
408{
409 return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
410}
411
412} // end namespace BasisFactory
413
414// Backward compatibility
415namespace BasisBuilder {
416
417 using namespace BasisFactory;
418
419}
420
421
422
423} // end namespace Functions
424} // end namespace Dune
425
426
427#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
auto composite(Args &&... args)
Create a factory builder that can build a CompositePreBasis.
Definition: compositebasis.hh:369
typename std::enable_if< std::is_constructible< T, Args... >::value, int >::type enableIfConstructible
Helper to constrain forwarding constructors.
Definition: type_traits.hh:26
Definition: polynomial.hh:10
static constexpr bool isIndexMergingStrategy()
Definition: basistags.hh:23
Get last entry of type list.
Definition: utility.hh:222
Base class for index merging strategies to simplify detection.
Definition: basistags.hh:44
Lexicographic merging of direct children without blocking.
Definition: basistags.hh:80
Lexicographic merging of direct children with blocking (i.e. creating one block per direct child).
Definition: basistags.hh:148
A pre-basis for composite bases.
Definition: compositebasis.hh:53
SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={})
Mutable access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:249
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child pre-bases.
Definition: compositebasis.hh:71
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: compositebasis.hh:230
const SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={}) const
Const access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:242
std::size_t size_type
Type used for indices and size information.
Definition: compositebasis.hh:68
CompositeBasisNode< typename SPB::Node... > Node
Template mapping root tree path to type of created tree node.
Definition: compositebasis.hh:81
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: compositebasis.hh:165
CompositePreBasis(SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: compositebasis.hh:95
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: compositebasis.hh:219
CompositePreBasis(const GV &gv)
Constructor for given GridView.
Definition: compositebasis.hh:115
It indices(const Node &node, It it) const
Maps from subtree index set [0..size-1] to a globally unique multi index in global basis.
Definition: compositebasis.hh:256
size_type size() const
Same as size(prefix) with empty prefix.
Definition: compositebasis.hh:158
typename std::tuple_element_t< 0, SubPreBases >::GridView GridView
The grid view that the FE basis is defined on.
Definition: compositebasis.hh:65
static const std::size_t children
Definition: compositebasis.hh:74
std::tuple< SPB... > SubPreBases
Tuple of child pre-bases.
Definition: compositebasis.hh:58
Node makeNode() const
Create tree node.
Definition: compositebasis.hh:148
void initializeIndices()
Initialize the global indices.
Definition: compositebasis.hh:124
std::tuple_element_t< i, SubPreBases > SubPreBasis
Export individual child pre-bases by index.
Definition: compositebasis.hh:62
std::make_index_sequence< children > ChildIndices
Definition: compositebasis.hh:76
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: compositebasis.hh:138
static constexpr size_type multiIndexBufferSize
Definition: compositebasis.hh:85
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: compositebasis.hh:132
static constexpr size_type minMultiIndexSize
Definition: compositebasis.hh:84
static constexpr size_type maxMultiIndexSize
Definition: compositebasis.hh:83
Definition: nodes.hh:219