DUNE-FUNCTIONS (unstable)

compositebasis.hh
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/hybridutilities.hh>
10 #include <dune/common/reservedvector.hh>
11 #include <dune/common/typeutilities.hh>
12 #include <dune/common/hybridutilities.hh>
13 #include <dune/common/tupleutility.hh>
14 #include <dune/common/tuplevector.hh>
15 
16 #include <dune/functions/common/staticforloop.hh>
17 #include <dune/functions/common/type_traits.hh>
18 #include <dune/functions/common/utility.hh>
19 #include <dune/functions/functionspacebases/basistags.hh>
20 #include <dune/functions/functionspacebases/nodes.hh>
21 #include <dune/functions/functionspacebases/concepts.hh>
22 #include <dune/functions/functionspacebases/containerdescriptors.hh>
23 #include <dune/functions/functionspacebases/defaultglobalbasis.hh>
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 
51 template<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>;
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 
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 
148  Node makeNode() const
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 
158  size_type size() const
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 
170 private:
171 
172  template<class MultiIndex>
173  static void multiIndexPopFront(MultiIndex& M)
174  {
175  for(std::size_t i=0; i<M.size()-1; ++i)
176  M[i] = M[i+1];
177  M.resize(M.size()-1);
178  }
179 
180  template<class SizePrefix>
181  size_type size(SizePrefix prefix, BasisFactory::BlockedLexicographic) const
182  {
183  if (prefix.size() == 0)
184  return children;
185 
186  auto front = prefix.front();
187  multiIndexPopFront(prefix);
188  return Hybrid::switchCases(ChildIndices(), front, [&] (auto i) {
189  return this->subPreBasis(i).size(prefix);
190  }, []() {
191  return size_type(0);
192  });
193  }
194 
195  template<class SizePrefix>
196  size_type size(SizePrefix prefix, BasisFactory::FlatLexicographic) const
197  {
198  size_type result = 0;
199  if (prefix.size() == 0)
200  Hybrid::forEach(ChildIndices(), [&](auto i) {
201  result += this->subPreBasis(i).size();
202  });
203  else {
204  staticFindInRange<0, children>([&](auto i) {
205  auto firstDigitSize = this->subPreBasis(i).size();
206  if (prefix[0] < firstDigitSize)
207  {
208  result = this->subPreBasis(i).size(prefix);
209  return true;
210  }
211  prefix[0] -= firstDigitSize;
212  return false;
213  });
214  }
215  return result;
216  }
217 
218 public:
219 
222  {
223  size_type r=0;
224  // Accumulate dimension() for all subprebases
225  Hybrid::forEach(ChildIndices(), [&](auto i) {
226  r += this->subPreBasis(i).dimension();
227  });
228  return r;
229  }
230 
233  {
234  size_type r=0;
235  // Accumulate maxNodeSize() for all subprebases
236  Hybrid::forEach(ChildIndices(), [&](auto i) {
237  r += this->subPreBasis(i).maxNodeSize();
238  });
239  return r;
240  }
241 
243  template<std::size_t i>
244  const SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {}) const
245  {
246  return std::get<i>(subPreBases_);
247  }
248 
250  template<std::size_t i>
251  SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {})
252  {
253  return std::get<i>(subPreBases_);
254  }
255 
257  const auto& subPreBases() const
258  {
259  return subPreBases_;
260  }
261 
263  template<typename It>
264  It indices(const Node& node, It it) const
265  {
266  return indices(node, it, IndexMergingStrategy{});
267  }
268 
270  auto containerDescriptor() const
271  {
272  namespace CD = Dune::Functions::ContainerDescriptors;
273  if constexpr(std::is_same_v<IMS, BasisFactory::BlockedLexicographic>) {
274  return std::apply([&](auto const&... spb) {
275  return CD::makeDescriptor(Dune::Functions::containerDescriptor(spb)...);
276  }, subPreBases_);
277  }
278  else if constexpr(std::is_same_v<IMS, BasisFactory::FlatLexicographic>) {
279  return CD::Unknown{}; // Not yet implemented
280  }
281  else
282  return CD::Unknown{};
283  }
284 
285 private:
286 
287  template<typename It>
288  It indices(const Node& node, It multiIndices, BasisFactory::FlatLexicographic) const
289  {
290  size_type firstComponentOffset = 0;
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
295  // buffer position and shift first index component of any index for current
296  // child by suitable offset to get lexicographic indices.
297  subPreBasis(child).indices(node.child(child), multiIndices);
298  for (std::size_t i = 0; i<subTreeSize; ++i)
299  multiIndices[i][0] += firstComponentOffset;
300  // Increment offset by the size for first index component of the current child
301  firstComponentOffset += subPreBasis(child).size();
302  // Increment buffer iterator by the number of indices processed for current child
303  multiIndices += subTreeSize;
304  });
305  return multiIndices;
306  }
307 
308  template<class MultiIndex>
309  static void multiIndexPushFront(MultiIndex& M, size_type M0)
310  {
311  M.resize(M.size()+1);
312  for(std::size_t i=M.size()-1; i>0; --i)
313  M[i] = M[i-1];
314  M[0] = M0;
315  }
316 
317  template<typename It>
318  It indices(const Node& node, It multiIndices, BasisFactory::BlockedLexicographic) const
319  {
320  // Loop over all children
321  Hybrid::forEach(ChildIndices(), [&](auto child){
322  size_type subTreeSize = node.child(child).size();
323  // Fill indices for current child into index buffer starting from current position
324  subPreBasis(child).indices(node.child(child), multiIndices);
325  // Insert child index before first component of all indices of current child.
326  for (std::size_t i = 0; i<subTreeSize; ++i)
327  this->multiIndexPushFront(multiIndices[i], child);
328  // Increment buffer iterator by the number of indices processed for current child
329  multiIndices += subTreeSize;
330  });
331  return multiIndices;
332  }
333 
334  std::tuple<SPB...> subPreBases_;
335 };
336 
337 
338 
339 namespace BasisFactory {
340 
341 namespace Imp {
342 
343 template<class IndexMergingStrategy, class... ChildPreBasisFactory>
344 class CompositePreBasisFactory
345 {
346 
347  template<class GridView, class... ChildPreBasis>
348  auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
349  {
350  return CompositePreBasis<IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
351  }
352 
353 public:
354 
355  CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
356  childPreBasisFactories_(childPreBasisFactory...)
357  {}
358 
359  CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
360  childPreBasisFactories_(std::move(childPreBasisFactory)...)
361  {}
362 
363  template<class GridView>
364  auto operator()(const GridView& gridView) const
365  {
366  // Use std::apply to unpack the tuple childPreBasisFactories_
367  return std::apply([&](const auto&... childPreBasisFactory) {
368  return this->makePreBasisFromChildPreBases(gridView, childPreBasisFactory(gridView)...);
369  }, childPreBasisFactories_);
370  }
371 
372 private:
373  std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
374 };
375 
376 } // end namespace BasisFactory::Imp
377 
378 
379 
390 template<
391  typename... Args,
392  std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
393 auto composite(Args&&... args)
394 {
395  // We have to separate the last entry which is the IndexMergingStrategy
396  // and the preceding ones, which are the ChildPreBasisFactories
397 
398  using ArgTuple = std::tuple<std::decay_t<Args>...>;
399 
400  // Compute number of children and index of the IndexMergingStrategy argument
401  constexpr std::size_t children = sizeof...(Args) - 1;
402 
403  // Use last type as IndexMergingStrategy
404  using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
405 
406  // Index sequence for all but the last entry for partial tuple unpacking
407  auto childIndices = std::make_index_sequence<children>{};
408 
409  // Unpack tuple only for those entries related to children
410  return applyPartial([](auto&&... childPreBasisFactory){
411  return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
412  },
413  std::forward_as_tuple(std::forward<Args>(args)...),
414  childIndices);
415 }
416 
428 template<
429  typename... Args,
430  std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
431 auto composite(Args&&... args)
432 {
433  return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
434 }
435 
436 } // end namespace BasisFactory
437 
438 // Backward compatibility
439 namespace [[deprecated("Will be removed after Dune 2.10")]] BasisBuilder {
440 
441  using namespace BasisFactory;
442 
443 }
444 
445 
446 
447 } // end namespace Functions
448 } // end namespace Dune
449 
450 
451 #endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
A pre-basis for composite bases.
Definition: compositebasis.hh:53
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child pre-bases.
Definition: compositebasis.hh:71
SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={})
Mutable access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:251
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: compositebasis.hh:232
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:221
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:264
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
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
const auto & subPreBases() const
Const access to the stored prebases tuple.
Definition: compositebasis.hh:257
std::tuple_element_t< i, SubPreBases > SubPreBasis
Export individual child pre-bases by index.
Definition: compositebasis.hh:62
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:244
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: compositebasis.hh:138
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: compositebasis.hh:132
auto containerDescriptor() const
Return the associated container descriptor.
Definition: compositebasis.hh:270
auto composite(Args &&... args)
Create a factory builder that can build a CompositePreBasis.
Definition: compositebasis.hh:393
std::enable_if_t< std::is_constructible_v< T, Args... >, int > enableIfConstructible
Helper to constrain forwarding constructors.
Definition: type_traits.hh:27
Definition: polynomial.hh:13
Lexicographic merging of direct children without blocking.
Definition: basistags.hh:80
Base class for index merging strategies to simplify detection.
Definition: basistags.hh:44
Fallback container descriptor if nothing else fits.
Definition: containerdescriptors.hh:46
Get last entry of type list.
Definition: utility.hh:222
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 16, 22:29, 2024)