DUNE-FUNCTIONS (2.7)

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/std/utility.hh>
10#include <dune/common/std/apply.hh>
11#include <dune/common/hybridutilities.hh>
12#include <dune/common/reservedvector.hh>
13#include <dune/common/typeutilities.hh>
14#include <dune/common/hybridutilities.hh>
15#include <dune/common/tupleutility.hh>
16#include <dune/common/tuplevector.hh>
17
18#include <dune/typetree/compositenode.hh>
19#include <dune/typetree/utility.hh>
20
21#include <dune/functions/common/staticforloop.hh>
22#include <dune/functions/common/type_traits.hh>
23#include <dune/functions/common/utility.hh>
24#include <dune/functions/functionspacebases/basistags.hh>
25#include <dune/functions/functionspacebases/nodes.hh>
26#include <dune/functions/functionspacebases/concepts.hh>
27
28
29namespace Dune {
30namespace Functions {
31
32// *****************************************************************************
33// This is the reusable part of the composite bases. It contains
34//
35// CompositePreBasis
36// CompositeNodeIndexSet
37//
38// The pre-basis allows to create the others and is the owner of possible shared
39// state. These components do _not_ depend on the global basis or index
40// set and can be used without a global basis.
41// *****************************************************************************
42
43
44template<class PB, class IMS>
45class CompositeNodeIndexSet;
46
59template<class MI, class IMS, class... SPB>
61{
62public:
63
65 using SubPreBases = std::tuple<SPB...>;
66
68 template<std::size_t i>
69 using SubPreBasis = std::tuple_element_t<i, SubPreBases>;
70
72 using GridView = typename std::tuple_element_t<0, SubPreBases>::GridView;
73
75 using size_type = std::size_t;
76
79
80protected:
81 static const std::size_t children = sizeof...(SPB);
82
83 template<class, class>
84 friend class CompositeNodeIndexSet;
85
86 using ChildIndices = std::make_index_sequence<children>;
87
88 template<class Indices>
89 struct Types;
90
91 template<std::size_t... indices>
92 struct Types<Dune::Std::index_sequence<indices...>>
93 {
94 template<std::size_t i>
95 using SubNode = typename std::tuple_element_t<i, SubPreBases>::Node;
96
97 template<std::size_t i>
98 using SubIndexSet = typename std::tuple_element_t<i, SubPreBases>::IndexSet;
99
100 using SubIndexSets = std::tuple<SubIndexSet<indices>...>;
101
102 using Node = CompositeBasisNode<SubNode<indices>...>;
103 };
104
105 using SubIndexSets = typename Types<ChildIndices>::SubIndexSets;
106
107public:
108
110 using Node = typename Types<ChildIndices>::Node;
111
113 using IndexSet = CompositeNodeIndexSet<CompositePreBasis, IMS>;
114
116 using MultiIndex = MI;
117
119 using SizePrefix = Dune::ReservedVector<size_type, MultiIndex::max_size()>;
120
126 template<class... SFArgs,
127 disableCopyMove<CompositePreBasis, SFArgs...> = 0,
128 enableIfConstructible<std::tuple<SPB...>, SFArgs...> = 0>
129 CompositePreBasis(SFArgs&&... sfArgs) :
130 subPreBases_(std::forward<SFArgs>(sfArgs)...)
131 {
132 Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
133 static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
134 });
135 }
136
139 {
140 Hybrid::forEach(ChildIndices(), [&](auto i) {
141 this->subPreBasis(i).initializeIndices();
142 });
143 }
144
146 const GridView& gridView() const
147 {
148 return std::get<0>(subPreBases_).gridView();
149 }
150
152 void update(const GridView& gv)
153 {
154 Hybrid::forEach(ChildIndices(), [&](auto i) {
155 this->subPreBasis(i).update(gv);
156 });
157 }
158
163 {
164 auto node = Node{};
165 Hybrid::forEach(ChildIndices(), [&](auto i) {
166 node.setChild(this->subPreBasis(i).makeNode(), i);
167 });
168 return node;
169 }
170
178 {
179 return IndexSet{*this,
180 unpackIntegerSequence([&](auto... i) {
181 return std::make_tuple(this->subPreBasis(i).makeIndexSet()...);
182 }, ChildIndices())};
183 }
184
187 {
188 return size({});
189 }
190
192 size_type size(const SizePrefix& prefix) const
193 {
194 return size(prefix, IndexMergingStrategy{});
195 }
196
197private:
198
200 {
201 if (prefix.size() == 0)
202 return children;
203
204 return Hybrid::switchCases(ChildIndices(), prefix[0], [&] (auto i) {
205 typename SubPreBasis<i>::SizePrefix subPrefix;
206 for(std::size_t i=1; i<prefix.size(); ++i)
207 subPrefix.push_back(prefix[i]);
208 return this->subPreBasis(i).size(subPrefix);
209 }, []() {
210 return size_type(0);
211 });
212 }
213
214 size_type size(const SizePrefix& prefix, BasisFactory::FlatLexicographic) const
215 {
216 size_type result = 0;
217 if (prefix.size() == 0)
218 Hybrid::forEach(ChildIndices(), [&](auto i) {
219 result += this->subPreBasis(i).size();
220 });
221 else {
222 size_type shiftedFirstDigit = prefix[0];
223 staticFindInRange<0, children>([&](auto i) {
224 auto firstDigitSize = this->subPreBasis(i).size();
225 if (shiftedFirstDigit < firstDigitSize)
226 {
227 typename SubPreBasis<i>::SizePrefix subPrefix;
228 subPrefix.push_back(shiftedFirstDigit);
229 for(std::size_t i=1; i<prefix.size(); ++i)
230 subPrefix.push_back(prefix[i]);
231 result = this->subPreBasis(i).size(subPrefix);
232 return true;
233 }
234 shiftedFirstDigit -= firstDigitSize;
235 return false;
236 });
237 }
238 return result;
239 }
240
241public:
242
245 {
246 size_type r=0;
247 // Accumulate dimension() for all subprebases
248 Hybrid::forEach(ChildIndices(), [&](auto i) {
249 r += this->subPreBasis(i).dimension();
250 });
251 return r;
252 }
253
256 {
257 size_type r=0;
258 // Accumulate maxNodeSize() for all subprebases
259 Hybrid::forEach(ChildIndices(), [&](auto i) {
260 r += this->subPreBasis(i).maxNodeSize();
261 });
262 return r;
263 }
264
266 template<std::size_t i>
267 const SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {}) const
268 {
269 return std::get<i>(subPreBases_);
270 }
271
273 template<std::size_t i>
274 SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {})
275 {
276 return std::get<i>(subPreBases_);
277 }
278
279private:
280 std::tuple<SPB...> subPreBases_;
281};
282
283
284
285template<class PB, class IMS>
286class CompositeNodeIndexSet
287{
288public:
289
290 using size_type = std::size_t;
291 using PreBasis = PB;
292 using MultiIndex = typename PreBasis::MultiIndex;
293 using Node = typename PreBasis::Node;
294
295protected:
296
297 using IndexMergingStrategy = IMS;
298 using SubIndexSets = typename PreBasis::SubIndexSets;
299 using ChildIndices = typename PreBasis::ChildIndices;
300
301public:
302
303 CompositeNodeIndexSet(const PreBasis & preBasis, SubIndexSets&& subNodeIndexSets) :
304 preBasis_(&preBasis),
305 subNodeIndexSetTuple_(std::move(subNodeIndexSets)),
306 node_(nullptr)
307 {}
308
309 void bind(const Node& node)
310 {
311 node_ = &node;
312 Hybrid::forEach(ChildIndices(), [&](auto i) {
313 Hybrid::elementAt(subNodeIndexSetTuple_, i).bind(node.child(i));
314 });
315 }
316
317 void unbind()
318 {
319 node_ = nullptr;
320 Hybrid::forEach(ChildIndices(), [&](auto i) {
321 Hybrid::elementAt(subNodeIndexSetTuple_, i).unbind();
322 });
323 }
324
325 size_type size() const
326 {
327 return node_->size();
328 }
329
331 template<typename It>
332 It indices(It it) const
333 {
334 return indices(it, IndexMergingStrategy{});
335 }
336
337 template<typename It>
338 It indices(It multiIndices, BasisFactory::FlatLexicographic) const
339 {
340 size_type firstComponentOffset = 0;
341 // Loop over all children
342 Hybrid::forEach(ChildIndices(), [&](auto child){
343 const auto& subNodeIndexSet = Hybrid::elementAt(subNodeIndexSetTuple_, child);
344 const auto& subPreBasis = preBasis_->subPreBasis(child);
345 size_type subTreeSize = subNodeIndexSet.size();
346 // Fill indices for current child into index buffer starting from current
347 // buffer position and shift first index component of any index for current
348 // child by suitable offset to get lexicographic indices.
349 subNodeIndexSet.indices(multiIndices);
350 for (std::size_t i = 0; i<subTreeSize; ++i)
351 multiIndices[i][0] += firstComponentOffset;
352 // Increment offset by the size for first index component of the current child
353 firstComponentOffset += subPreBasis.size({});
354 // Increment buffer iterator by the number of indices processed for current child
355 multiIndices += subTreeSize;
356 });
357 return multiIndices;
358 }
359
360 static void multiIndexPushFront(MultiIndex& M, size_type M0)
361 {
362 M.resize(M.size()+1);
363 for(std::size_t i=M.size()-1; i>0; --i)
364 M[i] = M[i-1];
365 M[0] = M0;
366 }
367
368 template<typename It>
369 It indices(It multiIndices, BasisFactory::BlockedLexicographic) const
370 {
371 // Loop over all children
372 Hybrid::forEach(ChildIndices(), [&](auto child){
373 const auto& subNodeIndexSet = Hybrid::elementAt(subNodeIndexSetTuple_, child);
374 size_type subTreeSize = subNodeIndexSet.size();
375 // Fill indices for current child into index buffer starting from current position
376 subNodeIndexSet.indices(multiIndices);
377 // Insert child index before first component of all indices of current child.
378 for (std::size_t i = 0; i<subTreeSize; ++i)
379 this->multiIndexPushFront(multiIndices[i], child);
380 // Increment buffer iterator by the number of indices processed for current child
381 multiIndices += subTreeSize;
382 });
383 return multiIndices;
384 }
385
386private:
387 const PreBasis* preBasis_;
388 SubIndexSets subNodeIndexSetTuple_;
389 const Node* node_;
390};
391
392
393
394namespace BasisFactory {
395
396namespace Imp {
397
398template<class ST0>
399constexpr std::size_t maxHelper(ST0&& i0)
400{
401 return i0;
402}
403
404template<class ST0, class... ST>
405constexpr std::size_t maxHelper(ST0&& i0, ST&&... i)
406{
407 return (i0 > maxHelper(i...)) ? i0 : maxHelper(i...);
408}
409
410template<class IndexMergingStrategy, class... ChildPreBasisFactory>
411class CompositePreBasisFactory
412{
413 static const bool isBlocked = std::is_same<IndexMergingStrategy,BlockedLexicographic>::value or std::is_same<IndexMergingStrategy,BlockedInterleaved>::value;
414
415 static const std::size_t maxChildIndexSize = maxHelper(ChildPreBasisFactory::requiredMultiIndexSize...);
416
417 template<class MultiIndex, class GridView, class... ChildPreBasis>
418 auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
419 {
420 return CompositePreBasis<MultiIndex, IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
421 }
422
423public:
424
425 static const std::size_t requiredMultiIndexSize = isBlocked ? (maxChildIndexSize+1) : maxChildIndexSize;
426
427 CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
428 childPreBasisFactories_(childPreBasisFactory...)
429 {}
430
431 CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
432 childPreBasisFactories_(std::move(childPreBasisFactory)...)
433 {}
434
435 template<class MultiIndex, class GridView>
436 auto makePreBasis(const GridView& gridView) const
437 {
438 // Use Std::apply to unpack the tuple childPreBasisFactories_
439 return Std::apply([&](const auto&... childPreBasisFactory) {
440 return this->makePreBasisFromChildPreBases<MultiIndex>(gridView, childPreBasisFactory.template makePreBasis<MultiIndex>(gridView)...);
441 }, childPreBasisFactories_);
442 }
443
444private:
445 std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
446};
447
448} // end namespace BasisFactory::Imp
449
450
451
462template<
463 typename... Args,
464 std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
465auto composite(Args&&... args)
466{
467 // We have to separate the last entry which is the IndexMergingStrategy
468 // and the preceding ones, which are the ChildPreBasisFactories
469
470 using ArgTuple = std::tuple<std::decay_t<Args>...>;
471
472 // Compute number of children and index of the IndexMergingStrategy argument
473 constexpr std::size_t children = Dune::SizeOf<Args...>::value-1;
474
475 // Use last type as IndexMergingStrategy
476 using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
477
478 // Index sequence for all but the last entry for partial tuple unpacking
479 auto childIndices = std::make_index_sequence<children>{};
480
481 // Unpack tuple only for those entries related to children
482 return applyPartial([](auto&&... childPreBasisFactory){
483 return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
484 },
485 std::forward_as_tuple(std::forward<Args>(args)...),
486 childIndices);
487}
488
500template<
501 typename... Args,
502 std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
503auto composite(Args&&... args)
504{
505 return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
506}
507
508} // end namespace BasisFactory
509
510// Backward compatibility
511namespace BasisBuilder {
512
513 using namespace BasisFactory;
514
515}
516
517
518
519} // end namespace Functions
520} // end namespace Dune
521
522
523#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
A pre-basis for composite bases.
Definition: compositebasis.hh:61
typename std::tuple_element_t< 0, SubPreBases >::GridView GridView
The grid view that the FE basis is defined on.
Definition: compositebasis.hh:72
Node makeNode() const
Create tree node.
Definition: compositebasis.hh:162
size_type size() const
Same as size(prefix) with empty prefix.
Definition: compositebasis.hh:186
typename Types< ChildIndices >::Node Node
Template mapping root tree path to type of created tree node.
Definition: compositebasis.hh:110
Dune::ReservedVector< size_type, MultiIndex::max_size()> SizePrefix
Type used for prefixes handed to the size() method.
Definition: compositebasis.hh:119
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: compositebasis.hh:244
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:267
std::size_t size_type
Type used for indices and size information.
Definition: compositebasis.hh:75
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: compositebasis.hh:192
IndexSet makeIndexSet() const
Create tree node index set.
Definition: compositebasis.hh:177
CompositeNodeIndexSet< CompositePreBasis, IMS > IndexSet
Template mapping root tree path to type of created tree node index set.
Definition: compositebasis.hh:113
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: compositebasis.hh:152
CompositePreBasis(SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: compositebasis.hh:129
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child pre-bases.
Definition: compositebasis.hh:78
std::tuple_element_t< i, SubPreBases > SubPreBasis
Export individual child pre-bases by index.
Definition: compositebasis.hh:69
MI MultiIndex
Type used for global numbering of the basis vectors.
Definition: compositebasis.hh:116
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: compositebasis.hh:255
SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={})
Mutable access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:274
std::tuple< SPB... > SubPreBases
Tuple of child pre-bases.
Definition: compositebasis.hh:65
void initializeIndices()
Initialize the global indices.
Definition: compositebasis.hh:138
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: compositebasis.hh:146
auto composite(Args &&... args)
Create a factory builder that can build a CompositePreBasis.
Definition: compositebasis.hh:465
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
Lexicographic merging of direct children with blocking (i.e. creating one block per direct child).
Definition: basistags.hh:148
Base class for index merging strategies to simplify detection.
Definition: basistags.hh:44
Get last entry of type list.
Definition: utility.hh:222
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 15, 22:36, 2024)