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
4// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
5// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
6
7#ifndef DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
8#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
9
10#include <tuple>
11#include <utility>
12
13#include <dune/common/hybridutilities.hh>
14#include <dune/common/reservedvector.hh>
15#include <dune/common/typeutilities.hh>
16#include <dune/common/hybridutilities.hh>
17#include <dune/common/tupleutility.hh>
18#include <dune/common/tuplevector.hh>
19
20#include <dune/functions/common/staticforloop.hh>
21#include <dune/functions/common/type_traits.hh>
22#include <dune/functions/common/utility.hh>
23#include <dune/functions/functionspacebases/basistags.hh>
24#include <dune/functions/functionspacebases/nodes.hh>
25#include <dune/functions/functionspacebases/concepts.hh>
26#include <dune/functions/functionspacebases/containerdescriptors.hh>
27#include <dune/functions/functionspacebases/defaultglobalbasis.hh>
28
29
30namespace Dune {
31namespace Functions {
32
33// *****************************************************************************
34// This is the reusable part of the composite bases. It contains
35//
36// CompositePreBasis
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 and local view
40// and can be used without a global basis.
41// *****************************************************************************
42
43
55template<class IMS, class... SPB>
57{
58 static const bool isBlocked = std::is_same_v<IMS,BasisFactory::BlockedLexicographic> or std::is_same_v<IMS,BasisFactory::BlockedInterleaved>;
59public:
60
62 using SubPreBases = std::tuple<SPB...>;
63
65 template<std::size_t i>
66 using SubPreBasis = std::tuple_element_t<i, SubPreBases>;
67
69 using GridView = typename std::tuple_element_t<0, SubPreBases>::GridView;
70
72 using size_type = std::size_t;
73
76
77protected:
78 static const std::size_t children = sizeof...(SPB);
79
80 using ChildIndices = std::make_index_sequence<children>;
81
82public:
83
85 using Node = CompositeBasisNode<typename SPB::Node...>;
86
87 static constexpr size_type maxMultiIndexSize = std::max({SPB::maxMultiIndexSize...}) + isBlocked;
88 static constexpr size_type minMultiIndexSize = std::min({SPB::minMultiIndexSize...}) + isBlocked;
89 static constexpr size_type multiIndexBufferSize = std::max({SPB::multiIndexBufferSize...}) + isBlocked;
90
96 template<class... SFArgs,
97 disableCopyMove<CompositePreBasis, SFArgs...> = 0,
98 enableIfConstructible<std::tuple<SPB...>, SFArgs...> = 0>
99 CompositePreBasis(SFArgs&&... sfArgs) :
100 subPreBases_(std::forward<SFArgs>(sfArgs)...)
101 {
102 Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
103 static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
104 });
105 }
106
113 template<class GV,
114 std::enable_if_t<std::conjunction_v<
115 std::bool_constant<(children > 1)>, // Avoid ambiguous constructor if there's only one child
116 std::is_same<GV, GridView>,
117 std::is_constructible<SPB, GridView>...
118 >, int> = 0>
119 CompositePreBasis(const GV& gv) :
120 subPreBases_(SPB(gv)...)
121 {
122 Hybrid::forEach(subPreBases_, [&](const auto& subPreBasis){
123 static_assert(models<Concept::PreBasis<GridView>, std::decay_t<decltype(subPreBasis)>>(), "Subprebases passed to CompositePreBasis does not model the PreBasis concept.");
124 });
125 }
126
129 {
130 Hybrid::forEach(ChildIndices(), [&](auto i) {
131 this->subPreBasis(i).initializeIndices();
132 });
133 }
134
136 const GridView& gridView() const
137 {
138 return std::get<0>(subPreBases_).gridView();
139 }
140
142 void update(const GridView& gv)
143 {
144 Hybrid::forEach(ChildIndices(), [&](auto i) {
145 this->subPreBasis(i).update(gv);
146 });
147 }
148
153 {
154 auto node = Node{};
155 Hybrid::forEach(ChildIndices(), [&](auto i) {
156 node.setChild(this->subPreBasis(i).makeNode(), i);
157 });
158 return node;
159 }
160
163 {
164 return size(Dune::ReservedVector<size_type, multiIndexBufferSize>{});
165 }
166
168 template<class SizePrefix>
169 size_type size(const SizePrefix& prefix) const
170 {
171 return size(prefix, IndexMergingStrategy{});
172 }
173
174private:
175
176 template<class MultiIndex>
177 static void multiIndexPopFront(MultiIndex& M)
178 {
179 for(std::size_t i=0; i<M.size()-1; ++i)
180 M[i] = M[i+1];
181 M.resize(M.size()-1);
182 }
183
184 template<class SizePrefix>
185 size_type size(SizePrefix prefix, BasisFactory::BlockedLexicographic) const
186 {
187 if (prefix.size() == 0)
188 return children;
189
190 auto front = prefix.front();
191 multiIndexPopFront(prefix);
192 return Hybrid::switchCases(ChildIndices(), front, [&] (auto i) {
193 return this->subPreBasis(i).size(prefix);
194 }, []() {
195 return size_type(0);
196 });
197 }
198
199 template<class SizePrefix>
200 size_type size(SizePrefix prefix, BasisFactory::FlatLexicographic) const
201 {
202 size_type result = 0;
203 if (prefix.size() == 0)
204 Hybrid::forEach(ChildIndices(), [&](auto i) {
205 result += this->subPreBasis(i).size();
206 });
207 else {
208 staticFindInRange<0, children>([&](auto i) {
209 auto firstDigitSize = this->subPreBasis(i).size();
210 if (prefix[0] < firstDigitSize)
211 {
212 result = this->subPreBasis(i).size(prefix);
213 return true;
214 }
215 prefix[0] -= firstDigitSize;
216 return false;
217 });
218 }
219 return result;
220 }
221
222public:
223
226 {
227 size_type r=0;
228 // Accumulate dimension() for all subprebases
229 Hybrid::forEach(ChildIndices(), [&](auto i) {
230 r += this->subPreBasis(i).dimension();
231 });
232 return r;
233 }
234
237 {
238 size_type r=0;
239 // Accumulate maxNodeSize() for all subprebases
240 Hybrid::forEach(ChildIndices(), [&](auto i) {
241 r += this->subPreBasis(i).maxNodeSize();
242 });
243 return r;
244 }
245
247 template<std::size_t i>
248 const SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {}) const
249 {
250 return std::get<i>(subPreBases_);
251 }
252
254 template<std::size_t i>
255 SubPreBasis<i>& subPreBasis(Dune::index_constant<i> = {})
256 {
257 return std::get<i>(subPreBases_);
258 }
259
261 const auto& subPreBases() const
262 {
263 return subPreBases_;
264 }
265
267 template<typename It>
268 It indices(const Node& node, It it) const
269 {
270 return indices(node, it, IndexMergingStrategy{});
271 }
272
275 {
276 namespace CD = Dune::Functions::ContainerDescriptors;
277 if constexpr(std::is_same_v<IMS, BasisFactory::BlockedLexicographic>) {
278 return std::apply([&](auto const&... spb) {
279 return CD::makeDescriptor(Dune::Functions::containerDescriptor(spb)...);
280 }, subPreBases_);
281 }
282 else if constexpr(std::is_same_v<IMS, BasisFactory::FlatLexicographic>) {
283 return CD::Unknown{}; // Not yet implemented
284 }
285 else
286 return CD::Unknown{};
287 }
288
289private:
290
291 template<typename It>
292 It indices(const Node& node, It multiIndices, BasisFactory::FlatLexicographic) const
293 {
294 size_type firstComponentOffset = 0;
295 // Loop over all children
296 Hybrid::forEach(ChildIndices(), [&](auto child){
297 size_type subTreeSize = node.child(child).size();
298 // Fill indices for current child into index buffer starting from current
299 // buffer position and shift first index component of any index for current
300 // child by suitable offset to get lexicographic indices.
301 subPreBasis(child).indices(node.child(child), multiIndices);
302 for (std::size_t i = 0; i<subTreeSize; ++i)
303 multiIndices[i][0] += firstComponentOffset;
304 // Increment offset by the size for first index component of the current child
305 firstComponentOffset += subPreBasis(child).size();
306 // Increment buffer iterator by the number of indices processed for current child
307 multiIndices += subTreeSize;
308 });
309 return multiIndices;
310 }
311
312 template<class MultiIndex>
313 static void multiIndexPushFront(MultiIndex& M, size_type M0)
314 {
315 M.resize(M.size()+1);
316 for(std::size_t i=M.size()-1; i>0; --i)
317 M[i] = M[i-1];
318 M[0] = M0;
319 }
320
321 template<typename It>
322 It indices(const Node& node, It multiIndices, BasisFactory::BlockedLexicographic) const
323 {
324 // Loop over all children
325 Hybrid::forEach(ChildIndices(), [&](auto child){
326 size_type subTreeSize = node.child(child).size();
327 // Fill indices for current child into index buffer starting from current position
328 subPreBasis(child).indices(node.child(child), multiIndices);
329 // Insert child index before first component of all indices of current child.
330 for (std::size_t i = 0; i<subTreeSize; ++i)
331 this->multiIndexPushFront(multiIndices[i], child);
332 // Increment buffer iterator by the number of indices processed for current child
333 multiIndices += subTreeSize;
334 });
335 return multiIndices;
336 }
337
338 std::tuple<SPB...> subPreBases_;
339};
340
341
342
343namespace BasisFactory {
344
345namespace Imp {
346
347template<class IndexMergingStrategy, class... ChildPreBasisFactory>
348class CompositePreBasisFactory
349{
350
351 template<class GridView, class... ChildPreBasis>
352 auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
353 {
354 return CompositePreBasis<IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
355 }
356
357public:
358
359 CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
360 childPreBasisFactories_(childPreBasisFactory...)
361 {}
362
363 CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
364 childPreBasisFactories_(std::move(childPreBasisFactory)...)
365 {}
366
367 template<class GridView>
368 auto operator()(const GridView& gridView) const
369 {
370 // Use std::apply to unpack the tuple childPreBasisFactories_
371 return std::apply([&](const auto&... childPreBasisFactory) {
372 return this->makePreBasisFromChildPreBases(gridView, childPreBasisFactory(gridView)...);
373 }, childPreBasisFactories_);
374 }
375
376private:
377 std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
378};
379
380} // end namespace BasisFactory::Imp
381
382
383
394template<
395 typename... Args,
396 std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
397auto composite(Args&&... args)
398{
399 // We have to separate the last entry which is the IndexMergingStrategy
400 // and the preceding ones, which are the ChildPreBasisFactories
401
402 using ArgTuple = std::tuple<std::decay_t<Args>...>;
403
404 // Compute number of children and index of the IndexMergingStrategy argument
405 constexpr std::size_t children = sizeof...(Args) - 1;
406
407 // Use last type as IndexMergingStrategy
408 using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
409
410 // Index sequence for all but the last entry for partial tuple unpacking
411 auto childIndices = std::make_index_sequence<children>{};
412
413 // Unpack tuple only for those entries related to children
414 return applyPartial([](auto&&... childPreBasisFactory){
415 return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
416 },
417 std::forward_as_tuple(std::forward<Args>(args)...),
418 childIndices);
419}
420
432template<
433 typename... Args,
434 std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
435auto composite(Args&&... args)
436{
437 return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
438}
439
440} // end namespace BasisFactory
441
442// Backward compatibility
443namespace [[deprecated("Will be removed after Dune 2.10")]] BasisBuilder {
444
445 using namespace BasisFactory;
446
447}
448
449
450
451} // end namespace Functions
452} // end namespace Dune
453
454
455#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_COMPOSITEBASIS_HH
A pre-basis for composite bases.
Definition: compositebasis.hh:57
SubPreBasis< i > & subPreBasis(Dune::index_constant< i >={})
Mutable access to the stored prebasis of the factor in the power space.
Definition: compositebasis.hh:255
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child pre-bases.
Definition: compositebasis.hh:75
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: compositebasis.hh:236
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:248
std::size_t size_type
Type used for indices and size information.
Definition: compositebasis.hh:72
CompositeBasisNode< typename SPB::Node... > Node
Template mapping root tree path to type of created tree node.
Definition: compositebasis.hh:85
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: compositebasis.hh:169
CompositePreBasis(SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: compositebasis.hh:99
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: compositebasis.hh:225
CompositePreBasis(const GV &gv)
Constructor for given GridView.
Definition: compositebasis.hh:119
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:268
size_type size() const
Same as size(prefix) with empty prefix.
Definition: compositebasis.hh:162
typename std::tuple_element_t< 0, SubPreBases >::GridView GridView
The grid view that the FE basis is defined on.
Definition: compositebasis.hh:69
std::tuple< SPB... > SubPreBases
Tuple of child pre-bases.
Definition: compositebasis.hh:62
Node makeNode() const
Create tree node.
Definition: compositebasis.hh:152
void initializeIndices()
Initialize the global indices.
Definition: compositebasis.hh:128
std::tuple_element_t< i, SubPreBases > SubPreBasis
Export individual child pre-bases by index.
Definition: compositebasis.hh:66
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: compositebasis.hh:142
const auto & subPreBases() const
Const access to the stored prebases tuple.
Definition: compositebasis.hh:261
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: compositebasis.hh:136
auto containerDescriptor() const
Return the associated container descriptor.
Definition: compositebasis.hh:274
auto composite(Args &&... args)
Create a factory builder that can build a CompositePreBasis.
Definition: compositebasis.hh:397
std::enable_if_t< std::is_constructible_v< T, Args... >, int > enableIfConstructible
Helper to constrain forwarding constructors.
Definition: type_traits.hh:31
Definition: polynomial.hh:17
Lexicographic merging of direct children without blocking.
Definition: basistags.hh:84
Base class for index merging strategies to simplify detection.
Definition: basistags.hh:48
Fallback container descriptor if nothing else fits.
Definition: containerdescriptors.hh:50
Get last entry of type list.
Definition: utility.hh:226
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Aug 13, 22:30, 2024)