DUNE-FUNCTIONS (unstable)

dynamicpowerbasis.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_DYNAMICPOWERBASIS_HH
8#define DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DYNAMICPOWERBASIS_HH
9
10#include <dune/common/reservedvector.hh>
11#include <dune/common/typeutilities.hh>
12#include <dune/common/indices.hh>
13
14#include <dune/common/typetree/nodeconcepts.hh>
15
16#include <dune/functions/common/utility.hh>
17#include <dune/functions/common/type_traits.hh>
18#include <dune/functions/functionspacebases/basistags.hh>
20#include <dune/functions/functionspacebases/nodes.hh>
21#include <dune/functions/functionspacebases/concepts.hh>
22
23
24
25namespace Dune {
26namespace Functions {
27
28
29// *****************************************************************************
30// This is the reusable part of the dynamic power bases. It contains
31//
32// DynamicPowerPreBasis
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
48template<class IMS, class SPB>
50{
51 static const bool isBlocked = std::is_same_v<IMS,BasisFactory::BlockedLexicographic> or std::is_same_v<IMS,BasisFactory::BlockedInterleaved>;
52
53public:
54
56 using SubPreBasis = SPB;
57
59 using GridView = typename SPB::GridView;
60
62 using size_type = std::size_t;
63
66
68 using Node = DynamicPowerBasisNode<typename SubPreBasis::Node>;
69
70 static constexpr size_type maxMultiIndexSize = SubPreBasis::maxMultiIndexSize + isBlocked;
71 static constexpr size_type minMultiIndexSize = SubPreBasis::minMultiIndexSize + isBlocked;
72 static constexpr size_type multiIndexBufferSize = SubPreBasis::multiIndexBufferSize + isBlocked;
73
79 template<class... SFArgs,
80 disableCopyMove<DynamicPowerPreBasis, SFArgs...> = 0,
81 enableIfConstructible<SubPreBasis, SFArgs...> = 0>
82 explicit DynamicPowerPreBasis(std::size_t c, SFArgs&&... sfArgs) :
83 children_(c),
84 subPreBasis_(std::forward<SFArgs>(sfArgs)...)
85 {
86 static_assert(models<Concept::PreBasis<GridView>, SubPreBasis>(), "Subprebasis passed to DynamicPowerPreBasis does not model the PreBasis concept.");
87 }
88
91 {
92 subPreBasis_.initializeIndices();
93 }
94
96 const GridView& gridView() const
97 {
98 return subPreBasis_.gridView();
99 }
100
102 void update(const GridView& gv)
103 {
104 subPreBasis_.update(gv);
105 }
106
111 {
112 auto node = Node{children_};
113 for (std::size_t i=0; i<children_; ++i)
114 node.setChild(i, subPreBasis_.makeNode());
115 return node;
116 }
117
118 std::size_t children() const
119 {
120 return children_;
121 }
122
125 {
126 return size(Dune::ReservedVector<size_type, multiIndexBufferSize>{});
127 }
128
130 template<class SizePrefix>
131 size_type size(const SizePrefix& prefix) const
132 {
133 return sizeImpl(prefix, children_, IndexMergingStrategy{});
134 }
135
136protected:
137
138 template<class SizePrefix, class Children>
139 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::FlatInterleaved) const
140 {
141 // The root index size is the root index size of a single subnode
142 // multiplied by the number of subnodes, because we enumerate all
143 // child indices in a row.
144 if (prefix.size() == 0)
145 return children*subPreBasis_.size();
146
147 // The FlatInterleaved index merging strategy only changes the first
148 // index digit. Hence, we have to reconstruct the corresponding digit
149 // for the subtree and can then return the corresponding size of the subtree.
150 prefix[0] = prefix[0] / children;
151 return subPreBasis_.size(prefix);
152 }
153
154 template<class SizePrefix, class Children>
155 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::FlatLexicographic) const
156 {
157 // The size at the index tree root is the size of at the index tree
158 // root of a single subnode multiplied by the number of subnodes,
159 // because we enumerate all child indices in a row.
160 if (prefix.size() == 0)
161 return children*subPreBasis_.size();
162
163 // The first prefix entry refers to one of the (root index size)
164 // subindex trees. Hence, we have to first compute the corresponding
165 // prefix entry for a single subnode subnode. Then we can append
166 // the other prefix entries unmodified, because the index tree
167 // looks the same after the first level.
168
169 // The FlatLexicographic index merging strategy only changes the first
170 // index digit. Hence, we have to reconstruct the corresponding digit
171 // for the subtree and can then return the corresponding size of the subtree.
172 prefix[0] = prefix[0] % subPreBasis_.size();
173 return subPreBasis_.size(prefix);
174 }
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, class Children>
185 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::BlockedLexicographic) const
186 {
187 if (prefix.size() == 0)
188 return children;
189 multiIndexPopFront(prefix);
190 return subPreBasis_.size(prefix);
191 }
192
193 template<class SizePrefix, class Children>
194 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::BlockedInterleaved) const
195 {
196 if (prefix.size() == 0)
197 return subPreBasis_.size();
198
199 // Remember last index, remove it and check if the remaining
200 // prefix refers to a leaf in the subPreBasis index tree.
201 // If yes, then the full prefix must also refer to a
202 // leaf in the merged index tree. If not, then restore the full
203 // prefix and proceed.
204 auto tail = prefix.back();
205 prefix.pop_back();
206 if (subPreBasis_.size(prefix) == 0)
207 return 0;
208 prefix.push_back(tail);
209
210 // Now check if the full prefix refers to a leaf in the subPreBasis
211 // index tree.
212 // If yes, then it has exactly 'children' appended children in the subtree.
213 // If not, then the index tree looks the same in the merged subtree and we
214 // can forward the result.
215 auto subSize = subPreBasis_.size(prefix);
216 if (subSize == 0)
217 return children;
218 return subSize;
219 }
220
221public:
222
225 {
226 return subPreBasis_.dimension() * children_;
227 }
228
231 {
232 return subPreBasis_.maxNodeSize() * children_;
233 }
234
237 {
238 return subPreBasis_;
239 }
240
243 {
244 return subPreBasis_;
245 }
246
248 template<class NodeType, typename It>
249 requires Dune::TypeTree::Concept::UniformInnerTreeNode<NodeType>
250 It indices(const NodeType& node, It it) const
251 {
252 return indicesImpl(node, it, children_, IndexMergingStrategy{});
253 }
254
257 {
258 return containerDescriptorImpl(children_);
259 }
260
261protected:
262
263 template<class NodeType, typename It, class Children>
264 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::FlatInterleaved) const
265 {
266 using namespace Dune::Indices;
267 size_type subTreeSize = node.child(_0).size();
268 // Fill indices for first child at the beginning.
269 auto next = subPreBasis().indices(node.child(_0), multiIndices);
270 // Multiply first component of all indices for first child by
271 // number of children to stretch the index range for interleaving.
272 for (std::size_t i = 0; i<subTreeSize; ++i)
273 multiIndices[i][0] *= children;
274 for (std::size_t child = 1; child<children; ++child)
275 {
276 for (std::size_t i = 0; i<subTreeSize; ++i)
277 {
278 // Copy indices from first child for all other children
279 // and shift them by child index to interleave indices.
280 // multiIndices[child*subTreeSize+i] = multiIndices[i];
281 // multiIndices[child*subTreeSize+i][0] = multiIndices[i][0]+child;
282 (*next) = multiIndices[i];
283 (*next)[0] = multiIndices[i][0]+child;
284 ++next;
285 }
286 }
287 return next;
288 }
289
290 template<class NodeType, typename It, class Children>
291 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::FlatLexicographic) const
292 {
293 using namespace Dune::Indices;
294 size_type subTreeSize = node.child(_0).size();
295 size_type firstIndexEntrySize = subPreBasis().size();
296 // Fill indices for first child at the beginning.
297 auto next = subPreBasis().indices(node.child(_0), multiIndices);
298 for (std::size_t child = 1; child<children_; ++child)
299 {
300 for (std::size_t i = 0; i<subTreeSize; ++i)
301 {
302 // Copy indices from first child for all other children
303 // and shift them by suitable offset to get lexicographic indices.
304 // multiIndices[child*subTreeSize+i] = multiIndices[i];
305 // multiIndices[child*subTreeSize+i][0] += child*firstIndexEntrySize;
306 (*next) = multiIndices[i];
307 (*next)[0] += child*firstIndexEntrySize;
308 ++next;
309 }
310 }
311 return next;
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<class NodeType, typename It, class Children>
324 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::BlockedLexicographic) const
325 {
326 using namespace Dune::Indices;
327 size_type subTreeSize = node.child(_0).size();
328 // Fill indices for first child at the beginning.
329 auto next = subPreBasis().indices(node.child(_0), multiIndices);
330 // Insert 0 before first component of all indices for first child.
331 for (std::size_t i = 0; i<subTreeSize; ++i)
332 multiIndexPushFront(multiIndices[i], 0);
333 for (std::size_t child = 1; child<children_; ++child)
334 {
335 for (std::size_t i = 0; i<subTreeSize; ++i)
336 {
337 // Copy indices from first child for all other children and overwrite
338 // zero in first component as inserted above by child index.
339 // multiIndices[child*subTreeSize+i] = multiIndices[i];
340 // multiIndices[child*subTreeSize+i][0] = child;
341 (*next) = multiIndices[i];
342 (*next)[0] = child;
343 ++next;
344 }
345 }
346 return next;
347 }
348
349 template<class NodeType, typename It, class Children>
350 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::BlockedInterleaved) const
351 {
352 using namespace Dune::Indices;
353 size_type subTreeSize = node.child(_0).size();
354 // Fill indices for first child at the beginning.
355 auto next = subPreBasis().indices(node.child(_0), multiIndices);
356 // Append 0 after last component of all indices for first child.
357 for (std::size_t i = 0; i<subTreeSize; ++i)
358 multiIndices[i].push_back(0);
359 for (std::size_t child = 1; child<children_; ++child)
360 {
361 for (std::size_t i = 0; i<subTreeSize; ++i)
362 {
363 // Copy indices from first child for all other children and overwrite
364 // zero in last component as appended above by child index.
365 (*next) = multiIndices[i];
366 (*next).back() = child;
367 ++next;
368 }
369 }
370 return next;
371 }
372
373 template<class Children>
374 auto containerDescriptorImpl(Children children) const
375 {
376 auto subTree = Dune::Functions::containerDescriptor(subPreBasis_);
377 if constexpr(std::is_same_v<IMS, BasisFactory::FlatInterleaved>)
378 return ContainerDescriptors::Impl::flatInterleavedN(children,std::move(subTree));
379 else if constexpr(std::is_same_v<IMS, BasisFactory::FlatLexicographic>)
380 return ContainerDescriptors::Impl::flatLexicographicN(children,std::move(subTree));
381 else if constexpr(std::is_same_v<IMS, BasisFactory::BlockedLexicographic>)
382 return ContainerDescriptors::makeUniformDescriptor(children,std::move(subTree));
383 else if constexpr(std::is_same_v<IMS, BasisFactory::BlockedInterleaved>)
384 return ContainerDescriptors::Impl::appendToTree(children,std::move(subTree));
385 else
386 return ContainerDescriptors::Unknown{};
387 }
388
389protected:
390 std::size_t children_;
391 SubPreBasis subPreBasis_;
392};
393
394
395
396namespace BasisFactory {
397
409template<class ChildPreBasisFactory, class IndexMergingStrategy>
410auto power(ChildPreBasisFactory&& childPreBasisFactory, std::size_t k, const IndexMergingStrategy&)
411{
412 return [childPreBasisFactory,k](const auto& gridView) {
413 auto childPreBasis = childPreBasisFactory(gridView);
415 };
416}
417
428template<class ChildPreBasisFactory>
429[[deprecated("Using the method `power` without an explicit index merging strategy"
430 " will change its meaning after the release of dune-functions 2.11."
431 " Previously, the default merging strategy was `BlockedInterleaved`,"
432 " but this will change to `FlatInterleaved`."
433 " Change the call to `power(..., blockedInterleaved())` to retain the old behavior.")]]
434auto power(ChildPreBasisFactory&& childPreBasisFactory, std::size_t k)
435{
436 return [childPreBasisFactory,k](const auto& gridView) {
437 auto childPreBasis = childPreBasisFactory(gridView);
439 };
440}
441
442} // end namespace BasisFactory
443
444} // end namespace Functions
445} // end namespace Dune
446
447
448#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DYNAMICPOWERBASIS_HH
A pre-basis for dynamic power bases.
Definition: dynamicpowerbasis.hh:50
std::size_t size_type
Type used for indices and size information.
Definition: dynamicpowerbasis.hh:62
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child factories.
Definition: dynamicpowerbasis.hh:65
DynamicPowerPreBasis(std::size_t c, SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: dynamicpowerbasis.hh:82
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: dynamicpowerbasis.hh:224
void initializeIndices()
Initialize the global indices.
Definition: dynamicpowerbasis.hh:90
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: dynamicpowerbasis.hh:102
auto containerDescriptor() const
Return the associated container descriptor.
Definition: dynamicpowerbasis.hh:256
size_type size() const
Same as size(prefix) with empty prefix.
Definition: dynamicpowerbasis.hh:124
SubPreBasis & subPreBasis()
Mutable access to the stored prebasis of the factor in the power space.
Definition: dynamicpowerbasis.hh:242
It indices(const NodeType &node, It it) const
Maps from subtree index set [0..size-1] to a globally unique multi index in global basis.
Definition: dynamicpowerbasis.hh:250
SPB SubPreBasis
The child pre-basis.
Definition: dynamicpowerbasis.hh:56
Node makeNode() const
Create tree node.
Definition: dynamicpowerbasis.hh:110
const SubPreBasis & subPreBasis() const
Const access to the stored prebasis of the factor in the power space.
Definition: dynamicpowerbasis.hh:236
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: dynamicpowerbasis.hh:230
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: dynamicpowerbasis.hh:131
DynamicPowerBasisNode< typename SubPreBasis::Node > Node
Template mapping root tree path to type of created tree node.
Definition: dynamicpowerbasis.hh:68
typename SPB::GridView GridView
The grid view that the FE basis is defined on.
Definition: dynamicpowerbasis.hh:59
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: dynamicpowerbasis.hh:96
Lightweight representation of (hierarchical) size and block structure extracted from a basis to descr...
auto containerDescriptor(const PreBasis &preBasis)
Return the container descriptor of the pre-basis, if defined, otherwise ContainerDescriptor::Unknown.
Definition: containerdescriptors.hh:58
auto power(ChildPreBasisFactory &&childPreBasisFactory, std::size_t k)
Create a factory builder that can build a PowerPreBasis.
Definition: dynamicpowerbasis.hh:434
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
Interleaved merging of direct children without blocking.
Definition: basistags.hh:118
Base class for index merging strategies to simplify detection.
Definition: basistags.hh:48
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Jan 10, 23:35, 2026)