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 std::apply([&](auto const&... spb) {
284 return CD::Impl::flatLexicographic(Dune::Functions::containerDescriptor(spb)...);
285 }, subPreBases_);
286 }
287 else
288 return CD::Unknown{};
289 }
290
291private:
292
293 template<typename It>
294 It indices(const Node& node, It multiIndices, BasisFactory::FlatLexicographic) const
295 {
296 size_type firstComponentOffset = 0;
297 // Loop over all children
298 Hybrid::forEach(ChildIndices(), [&](auto child){
299 size_type subTreeSize = node.child(child).size();
300 // Fill indices for current child into index buffer starting from current
301 // buffer position and shift first index component of any index for current
302 // child by suitable offset to get lexicographic indices.
303 subPreBasis(child).indices(node.child(child), multiIndices);
304 for (std::size_t i = 0; i<subTreeSize; ++i)
305 multiIndices[i][0] += firstComponentOffset;
306 // Increment offset by the size for first index component of the current child
307 firstComponentOffset += subPreBasis(child).size();
308 // Increment buffer iterator by the number of indices processed for current child
309 multiIndices += subTreeSize;
310 });
311 return multiIndices;
312 }
313
314 template<class MultiIndex>
315 static void multiIndexPushFront(MultiIndex& M, size_type M0)
316 {
317 M.resize(M.size()+1);
318 for(std::size_t i=M.size()-1; i>0; --i)
319 M[i] = M[i-1];
320 M[0] = M0;
321 }
322
323 template<typename It>
324 It indices(const Node& node, It multiIndices, BasisFactory::BlockedLexicographic) const
325 {
326 // Loop over all children
327 Hybrid::forEach(ChildIndices(), [&](auto child){
328 size_type subTreeSize = node.child(child).size();
329 // Fill indices for current child into index buffer starting from current position
330 subPreBasis(child).indices(node.child(child), multiIndices);
331 // Insert child index before first component of all indices of current child.
332 for (std::size_t i = 0; i<subTreeSize; ++i)
333 this->multiIndexPushFront(multiIndices[i], child);
334 // Increment buffer iterator by the number of indices processed for current child
335 multiIndices += subTreeSize;
336 });
337 return multiIndices;
338 }
339
340 std::tuple<SPB...> subPreBases_;
341};
342
343
344
345namespace BasisFactory {
346
347namespace Imp {
348
349template<class IndexMergingStrategy, class... ChildPreBasisFactory>
350class CompositePreBasisFactory
351{
352
353 template<class GridView, class... ChildPreBasis>
354 auto makePreBasisFromChildPreBases(const GridView&, ChildPreBasis&&... childPreBasis) const
355 {
356 return CompositePreBasis<IndexMergingStrategy, std::decay_t<ChildPreBasis>...>(std::forward<ChildPreBasis>(childPreBasis)...);
357 }
358
359public:
360
361 CompositePreBasisFactory(const ChildPreBasisFactory&... childPreBasisFactory) :
362 childPreBasisFactories_(childPreBasisFactory...)
363 {}
364
365 CompositePreBasisFactory(ChildPreBasisFactory&&... childPreBasisFactory) :
366 childPreBasisFactories_(std::move(childPreBasisFactory)...)
367 {}
368
369 template<class GridView>
370 auto operator()(const GridView& gridView) const
371 {
372 // Use std::apply to unpack the tuple childPreBasisFactories_
373 return std::apply([&](const auto&... childPreBasisFactory) {
374 return this->makePreBasisFromChildPreBases(gridView, childPreBasisFactory(gridView)...);
375 }, childPreBasisFactories_);
376 }
377
378private:
379 std::tuple<ChildPreBasisFactory...> childPreBasisFactories_;
380};
381
382} // end namespace BasisFactory::Imp
383
384
385
396template<
397 typename... Args,
398 std::enable_if_t<Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
399auto composite(Args&&... args)
400{
401 // We have to separate the last entry which is the IndexMergingStrategy
402 // and the preceding ones, which are the ChildPreBasisFactories
403
404 using ArgTuple = std::tuple<std::decay_t<Args>...>;
405
406 // Compute number of children and index of the IndexMergingStrategy argument
407 constexpr std::size_t children = sizeof...(Args) - 1;
408
409 // Use last type as IndexMergingStrategy
410 using IndexMergingStrategy = std::tuple_element_t<children, ArgTuple>;
411
412 // Index sequence for all but the last entry for partial tuple unpacking
413 auto childIndices = std::make_index_sequence<children>{};
414
415 // Unpack tuple only for those entries related to children
416 return applyPartial([](auto&&... childPreBasisFactory){
417 return Imp::CompositePreBasisFactory<IndexMergingStrategy, std::decay_t<decltype(childPreBasisFactory)>...>(std::forward<decltype(childPreBasisFactory)>(childPreBasisFactory)...);
418 },
419 std::forward_as_tuple(std::forward<Args>(args)...),
420 childIndices);
421}
422
434template<
435 typename... Args,
436 std::enable_if_t<not Concept::isIndexMergingStrategy<typename LastType<Args...>::type>(),int> = 0>
437auto composite(Args&&... args)
438{
439 return Imp::CompositePreBasisFactory<BasisFactory::BlockedLexicographic, std::decay_t<Args>...>(std::forward<Args>(args)...);
440}
441
442} // end namespace BasisFactory
443
444// Backward compatibility
445namespace [[deprecated("Will be removed after Dune 2.10")]] BasisBuilder {
446
447 using namespace BasisFactory;
448
449}
450
451
452
453} // end namespace Functions
454} // end namespace Dune
455
456
457#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:399
constexpr FlatLexicographic flatLexicographic()
Creates a lexicographic merging of direct children without blocking.
Definition: basistags.hh:192
std::enable_if_t< std::is_constructible_v< T, Args... >, int > enableIfConstructible
Helper to constrain forwarding constructors.
Definition: type_traits.hh:31
Definition: monomialset.hh:19
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:52
Get last entry of type list.
Definition: utility.hh:226
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Mar 12, 23:28, 2025)