dune-functions  2.8.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 
26 namespace Dune {
27 namespace 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 
52 template<class MI, class IMS, class... SPB>
54 {
55 public:
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 
71  using IndexMergingStrategy = IMS;
72 
73 protected:
74  static const std::size_t children = sizeof...(SPB);
75 
76  using ChildIndices = std::make_index_sequence<children>;
77 
78 public:
79 
81  using Node = CompositeBasisNode<typename SPB::Node...>;
82 
84  using IndexSet = Impl::DefaultNodeIndexSet<CompositePreBasis>;
85 
87  using MultiIndex = MI;
88 
90  using SizePrefix = Dune::ReservedVector<size_type, MultiIndex::max_size()>;
91 
97  template<class... SFArgs,
98  disableCopyMove<CompositePreBasis, SFArgs...> = 0,
99  enableIfConstructible<std::tuple<SPB...>, SFArgs...> = 0>
100  CompositePreBasis(SFArgs&&... sfArgs) :
101  subPreBases_(std::forward<SFArgs>(sfArgs)...)
102  {
103  Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
104  static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
105  });
106  }
107 
110  {
111  Hybrid::forEach(ChildIndices(), [&](auto i) {
112  this->subPreBasis(i).initializeIndices();
113  });
114  }
115 
117  const GridView& gridView() const
118  {
119  return std::get<0>(subPreBases_).gridView();
120  }
121 
123  void update(const GridView& gv)
124  {
125  Hybrid::forEach(ChildIndices(), [&](auto i) {
126  this->subPreBasis(i).update(gv);
127  });
128  }
129 
133  Node makeNode() const
134  {
135  auto node = Node{};
136  Hybrid::forEach(ChildIndices(), [&](auto i) {
137  node.setChild(this->subPreBasis(i).makeNode(), i);
138  });
139  return node;
140  }
141 
149  [[deprecated("Warning: The IndexSet typedef and the makeIndexSet method are deprecated. "\
150  "As a replacement use the indices() method of the PreBasis directly.")]]
152  {
153  return IndexSet{*this};
154  }
155 
157  size_type size() const
158  {
159  return size({});
160  }
161 
163  size_type size(const SizePrefix& prefix) const
164  {
165  return size(prefix, IndexMergingStrategy{});
166  }
167 
168 private:
169 
171  {
172  if (prefix.size() == 0)
173  return children;
174 
175  return Hybrid::switchCases(ChildIndices(), prefix[0], [&] (auto i) {
176  typename SubPreBasis<i>::SizePrefix subPrefix;
177  for(std::size_t i=1; i<prefix.size(); ++i)
178  subPrefix.push_back(prefix[i]);
179  return this->subPreBasis(i).size(subPrefix);
180  }, []() {
181  return size_type(0);
182  });
183  }
184 
185  size_type size(const SizePrefix& prefix, BasisFactory::FlatLexicographic) const
186  {
187  size_type result = 0;
188  if (prefix.size() == 0)
189  Hybrid::forEach(ChildIndices(), [&](auto i) {
190  result += this->subPreBasis(i).size();
191  });
192  else {
193  size_type shiftedFirstDigit = prefix[0];
194  staticFindInRange<0, children>([&](auto i) {
195  auto firstDigitSize = this->subPreBasis(i).size();
196  if (shiftedFirstDigit < firstDigitSize)
197  {
198  typename SubPreBasis<i>::SizePrefix subPrefix;
199  subPrefix.push_back(shiftedFirstDigit);
200  for(std::size_t i=1; i<prefix.size(); ++i)
201  subPrefix.push_back(prefix[i]);
202  result = this->subPreBasis(i).size(subPrefix);
203  return true;
204  }
205  shiftedFirstDigit -= firstDigitSize;
206  return false;
207  });
208  }
209  return result;
210  }
211 
212 public:
213 
216  {
217  size_type r=0;
218  // Accumulate dimension() for all subprebases
219  Hybrid::forEach(ChildIndices(), [&](auto i) {
220  r += this->subPreBasis(i).dimension();
221  });
222  return r;
223  }
224 
227  {
228  size_type r=0;
229  // Accumulate maxNodeSize() for all subprebases
230  Hybrid::forEach(ChildIndices(), [&](auto i) {
231  r += this->subPreBasis(i).maxNodeSize();
232  });
233  return r;
234  }
235 
237  template<std::size_t i>
238  const SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {}) const
239  {
240  return std::get<i>(subPreBases_);
241  }
242 
244  template<std::size_t i>
245  SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {})
246  {
247  return std::get<i>(subPreBases_);
248  }
249 
251  template<typename It>
252  It indices(const Node& node, It it) const
253  {
254  return indices(node, it, IndexMergingStrategy{});
255  }
256 
257 private:
258 
259  template<typename It>
260  It indices(const Node& node, It multiIndices, BasisFactory::FlatLexicographic) const
261  {
262  size_type firstComponentOffset = 0;
263  // Loop over all children
264  Hybrid::forEach(ChildIndices(), [&](auto child){
265  size_type subTreeSize = node.child(child).size();
266  // Fill indices for current child into index buffer starting from current
267  // buffer position and shift first index component of any index for current
268  // child by suitable offset to get lexicographic indices.
269  Impl::preBasisIndices(subPreBasis(child), node.child(child), multiIndices);
270  for (std::size_t i = 0; i<subTreeSize; ++i)
271  multiIndices[i][0] += firstComponentOffset;
272  // Increment offset by the size for first index component of the current child
273  firstComponentOffset += subPreBasis(child).size({});
274  // Increment buffer iterator by the number of indices processed for current child
275  multiIndices += subTreeSize;
276  });
277  return multiIndices;
278  }
279 
280  static void multiIndexPushFront(MultiIndex& M, size_type M0)
281  {
282  M.resize(M.size()+1);
283  for(std::size_t i=M.size()-1; i>0; --i)
284  M[i] = M[i-1];
285  M[0] = M0;
286  }
287 
288  template<typename It>
289  It indices(const Node& node, It multiIndices, BasisFactory::BlockedLexicographic) const
290  {
291  // Loop over all children
292  Hybrid::forEach(ChildIndices(), [&](auto child){
293  size_type subTreeSize = node.child(child).size();
294  // Fill indices for current child into index buffer starting from current position
295  Impl::preBasisIndices(subPreBasis(child), node.child(child), multiIndices);
296  // Insert child index before first component of all indices of current child.
297  for (std::size_t i = 0; i<subTreeSize; ++i)
298  this->multiIndexPushFront(multiIndices[i], child);
299  // Increment buffer iterator by the number of indices processed for current child
300  multiIndices += subTreeSize;
301  });
302  return multiIndices;
303  }
304 
305  std::tuple<SPB...> subPreBases_;
306 };
307 
308 
309 
310 namespace BasisFactory {
311 
312 namespace Imp {
313 
314 template<class ST0>
315 constexpr std::size_t maxHelper(ST0&& i0)
316 {
317  return i0;
318 }
319 
320 template<class ST0, class... ST>
321 constexpr std::size_t maxHelper(ST0&& i0, ST&&... i)
322 {
323  return (i0 > maxHelper(i...)) ? i0 : maxHelper(i...);
324 }
325 
326 template<class IndexMergingStrategy, class... ChildPreBasisFactory>
327 class CompositePreBasisFactory
328 {
329  static const bool isBlocked = std::is_same<IndexMergingStrategy,BlockedLexicographic>::value or std::is_same<IndexMergingStrategy,BlockedInterleaved>::value;
330 
331  static const std::size_t maxChildIndexSize = maxHelper(ChildPreBasisFactory::requiredMultiIndexSize...);
332 
333  template<class MultiIndex, class GridView, class... ChildPreBasis>
334  auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
335  {
336  return CompositePreBasis<MultiIndex, IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
337  }
338 
339 public:
340 
341  static const std::size_t requiredMultiIndexSize = isBlocked ? (maxChildIndexSize+1) : maxChildIndexSize;
342 
343  CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
344  childPreBasisFactories_(childPreBasisFactory...)
345  {}
346 
347  CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
348  childPreBasisFactories_(std::move(childPreBasisFactory)...)
349  {}
350 
351  template<class MultiIndex, class GridView>
352  auto makePreBasis(const GridView& gridView) const
353  {
354  // Use std::apply to unpack the tuple childPreBasisFactories_
355  return std::apply([&](const auto&... childPreBasisFactory) {
356  return this->makePreBasisFromChildPreBases<MultiIndex>(gridView, childPreBasisFactory.template makePreBasis<MultiIndex>(gridView)...);
357  }, childPreBasisFactories_);
358  }
359 
360 private:
361  std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
362 };
363 
364 } // end namespace BasisFactory::Imp
365 
366 
367 
378 template<
379  typename... Args,
380  std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
381 auto composite(Args&&... args)
382 {
383  // We have to separate the last entry which is the IndexMergingStrategy
384  // and the preceding ones, which are the ChildPreBasisFactories
385 
386  using ArgTuple = std::tuple<std::decay_t<Args>...>;
387 
388  // Compute number of children and index of the IndexMergingStrategy argument
389  constexpr std::size_t children = Dune::SizeOf<Args...>::value-1;
390 
391  // Use last type as IndexMergingStrategy
392  using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
393 
394  // Index sequence for all but the last entry for partial tuple unpacking
395  auto childIndices = std::make_index_sequence<children>{};
396 
397  // Unpack tuple only for those entries related to children
398  return applyPartial([](auto&&... childPreBasisFactory){
399  return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
400  },
401  std::forward_as_tuple(std::forward<Args>(args)...),
402  childIndices);
403 }
404 
416 template<
417  typename... Args,
418  std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
419 auto composite(Args&&... args)
420 {
421  return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
422 }
423 
424 } // end namespace BasisFactory
425 
426 // Backward compatibility
427 namespace BasisBuilder {
428 
429  using namespace BasisFactory;
430 
431 }
432 
433 
434 
435 } // end namespace Functions
436 } // end namespace Dune
437 
438 
439 #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
auto composite(Args &&... args)
Create a factory builder that can build a CompositePreBasis.
Definition: compositebasis.hh:381
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:54
SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={})
Mutable access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:245
typename std::tuple_element_t< 0, SubPreBases >::GridView GridView
The grid view that the FE basis is defined on.
Definition: compositebasis.hh:65
Node makeNode() const
Create tree node.
Definition: compositebasis.hh:133
size_type size() const
Same as size(prefix) with empty prefix.
Definition: compositebasis.hh:157
static const std::size_t children
Definition: compositebasis.hh:74
Dune::ReservedVector< size_type, MultiIndex::max_size()> SizePrefix
Type used for prefixes handed to the size() method.
Definition: compositebasis.hh:90
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: compositebasis.hh:215
std::size_t size_type
Type used for indices and size information.
Definition: compositebasis.hh:68
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: compositebasis.hh:163
IndexSet makeIndexSet() const
Create tree node index set.
Definition: compositebasis.hh:151
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:123
CompositePreBasis(SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: compositebasis.hh:100
Impl::DefaultNodeIndexSet< CompositePreBasis > IndexSet
Type of created tree node index set.
Definition: compositebasis.hh:84
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child pre-bases.
Definition: compositebasis.hh:71
std::tuple_element_t< i, SubPreBases > SubPreBasis
Export individual child pre-bases by index.
Definition: compositebasis.hh:62
MI MultiIndex
Type used for global numbering of the basis vectors.
Definition: compositebasis.hh:87
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: compositebasis.hh:226
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: compositebasis.hh:117
CompositeBasisNode< typename SPB::Node... > Node
Template mapping root tree path to type of created tree node.
Definition: compositebasis.hh:81
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:252
std::tuple< SPB... > SubPreBases
Tuple of child pre-bases.
Definition: compositebasis.hh:58
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:238
void initializeIndices()
Initialize the global indices.
Definition: compositebasis.hh:109
Definition: functionspacebases/concepts.hh:182
Definition: nodes.hh:217