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/functions/common/utility.hh>
15#include <dune/functions/common/type_traits.hh>
16#include <dune/functions/functionspacebases/basistags.hh>
17#include <dune/functions/functionspacebases/containerdescriptors.hh>
18#include <dune/functions/functionspacebases/nodes.hh>
19#include <dune/functions/functionspacebases/concepts.hh>
20
21
22
23namespace Dune {
24namespace Functions {
25
26
27// *****************************************************************************
28// This is the reusable part of the dynamic power bases. It contains
29//
30// DynamicPowerPreBasis
31//
32// The pre-basis allows to create the others and is the owner of possible shared
33// state. These components do _not_ depend on the global basis and local view
34// and can be used without a global basis.
35// *****************************************************************************
36
46template<class IMS, class SPB>
48{
49 static const bool isBlocked = std::is_same_v<IMS,BasisFactory::BlockedLexicographic> or std::is_same_v<IMS,BasisFactory::BlockedInterleaved>;
50
51public:
52
54 using SubPreBasis = SPB;
55
57 using GridView = typename SPB::GridView;
58
60 using size_type = std::size_t;
61
64
66 using Node = DynamicPowerBasisNode<typename SubPreBasis::Node>;
67
68 static constexpr size_type maxMultiIndexSize = SubPreBasis::maxMultiIndexSize + isBlocked;
69 static constexpr size_type minMultiIndexSize = SubPreBasis::minMultiIndexSize + isBlocked;
70 static constexpr size_type multiIndexBufferSize = SubPreBasis::multiIndexBufferSize + isBlocked;
71
77 template<class... SFArgs,
78 disableCopyMove<DynamicPowerPreBasis, SFArgs...> = 0,
79 enableIfConstructible<SubPreBasis, SFArgs...> = 0>
80 explicit DynamicPowerPreBasis(std::size_t c, SFArgs&&... sfArgs) :
81 children_(c),
82 subPreBasis_(std::forward<SFArgs>(sfArgs)...)
83 {
84 static_assert(models<Concept::PreBasis<GridView>, SubPreBasis>(), "Subprebasis passed to DynamicPowerPreBasis does not model the PreBasis concept.");
85 }
86
89 {
90 subPreBasis_.initializeIndices();
91 }
92
94 const GridView& gridView() const
95 {
96 return subPreBasis_.gridView();
97 }
98
100 void update(const GridView& gv)
101 {
102 subPreBasis_.update(gv);
103 }
104
109 {
110 auto node = Node{children_};
111 for (std::size_t i=0; i<children_; ++i)
112 node.setChild(i, subPreBasis_.makeNode());
113 return node;
114 }
115
116 std::size_t children() const
117 {
118 return children_;
119 }
120
123 {
124 return size(Dune::ReservedVector<size_type, multiIndexBufferSize>{});
125 }
126
128 template<class SizePrefix>
129 size_type size(const SizePrefix& prefix) const
130 {
131 return sizeImpl(prefix, children_, IndexMergingStrategy{});
132 }
133
134protected:
135
136 template<class SizePrefix, class Children>
137 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::FlatInterleaved) const
138 {
139 // The root index size is the root index size of a single subnode
140 // multiplied by the number of subnodes, because we enumerate all
141 // child indices in a row.
142 if (prefix.size() == 0)
143 return children*subPreBasis_.size();
144
145 // The FlatInterleaved index merging strategy only changes the first
146 // index digit. Hence, we have to reconstruct the corresponding digit
147 // for the subtree and can then return the corresponding size of the subtree.
148 prefix[0] = prefix[0] / children;
149 return subPreBasis_.size(prefix);
150 }
151
152 template<class SizePrefix, class Children>
153 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::FlatLexicographic) const
154 {
155 // The size at the index tree root is the size of at the index tree
156 // root of a single subnode multiplied by the number of subnodes,
157 // because we enumerate all child indices in a row.
158 if (prefix.size() == 0)
159 return children*subPreBasis_.size();
160
161 // The first prefix entry refers to one of the (root index size)
162 // subindex trees. Hence, we have to first compute the corresponding
163 // prefix entry for a single subnode subnode. Then we can append
164 // the other prefix entries unmodified, because the index tree
165 // looks the same after the first level.
166
167 // The FlatLexicographic index merging strategy only changes the first
168 // index digit. Hence, we have to reconstruct the corresponding digit
169 // for the subtree and can then return the corresponding size of the subtree.
170 prefix[0] = prefix[0] % subPreBasis_.size();
171 return subPreBasis_.size(prefix);
172 }
173
174 template<class MultiIndex>
175 static void multiIndexPopFront(MultiIndex& M)
176 {
177 for(std::size_t i=0; i<M.size()-1; ++i)
178 M[i] = M[i+1];
179 M.resize(M.size()-1);
180 }
181
182 template<class SizePrefix, class Children>
183 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::BlockedLexicographic) const
184 {
185 if (prefix.size() == 0)
186 return children;
187 multiIndexPopFront(prefix);
188 return subPreBasis_.size(prefix);
189 }
190
191 template<class SizePrefix, class Children>
192 size_type sizeImpl(SizePrefix prefix, Children children, BasisFactory::BlockedInterleaved) const
193 {
194 if (prefix.size() == 0)
195 return subPreBasis_.size();
196
197 // Remember last index, remove it and check if the remaining
198 // prefix refers to a leaf in the subPreBasis index tree.
199 // If yes, then the full prefix must also refer to a
200 // leaf in the merged index tree. If not, then restore the full
201 // prefix and proceed.
202 auto tail = prefix.back();
203 prefix.pop_back();
204 if (subPreBasis_.size(prefix) == 0)
205 return 0;
206 prefix.push_back(tail);
207
208 // Now check if the full prefix refers to a leaf in the subPreBasis
209 // index tree.
210 // If yes, then it has exactly 'children' appended children in the subtree.
211 // If not, then the index tree looks the same in the merged subtree and we
212 // can forward the result.
213 auto subSize = subPreBasis_.size(prefix);
214 if (subSize == 0)
215 return children;
216 return subSize;
217 }
218
219public:
220
223 {
224 return subPreBasis_.dimension() * children_;
225 }
226
229 {
230 return subPreBasis_.maxNodeSize() * children_;
231 }
232
235 {
236 return subPreBasis_;
237 }
238
241 {
242 return subPreBasis_;
243 }
244
246 template<class NodeType, typename It,
247 std::enable_if_t<NodeType::isPower, int> = 0>
248 It indices(const NodeType& node, It it) const
249 {
250 return indicesImpl(node, it, children_, IndexMergingStrategy{});
251 }
252
255 {
256 return containerDescriptorImpl(children_);
257 }
258
259protected:
260
261 template<class NodeType, typename It, class Children>
262 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::FlatInterleaved) const
263 {
264 using namespace Dune::Indices;
265 size_type subTreeSize = node.child(_0).size();
266 // Fill indices for first child at the beginning.
267 auto next = subPreBasis().indices(node.child(_0), multiIndices);
268 // Multiply first component of all indices for first child by
269 // number of children to stretch the index range for interleaving.
270 for (std::size_t i = 0; i<subTreeSize; ++i)
271 multiIndices[i][0] *= children;
272 for (std::size_t child = 1; child<children; ++child)
273 {
274 for (std::size_t i = 0; i<subTreeSize; ++i)
275 {
276 // Copy indices from first child for all other children
277 // and shift them by child index to interleave indices.
278 // multiIndices[child*subTreeSize+i] = multiIndices[i];
279 // multiIndices[child*subTreeSize+i][0] = multiIndices[i][0]+child;
280 (*next) = multiIndices[i];
281 (*next)[0] = multiIndices[i][0]+child;
282 ++next;
283 }
284 }
285 return next;
286 }
287
288 template<class NodeType, typename It, class Children>
289 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::FlatLexicographic) const
290 {
291 using namespace Dune::Indices;
292 size_type subTreeSize = node.child(_0).size();
293 size_type firstIndexEntrySize = subPreBasis().size();
294 // Fill indices for first child at the beginning.
295 auto next = subPreBasis().indices(node.child(_0), multiIndices);
296 for (std::size_t child = 1; child<children_; ++child)
297 {
298 for (std::size_t i = 0; i<subTreeSize; ++i)
299 {
300 // Copy indices from first child for all other children
301 // and shift them by suitable offset to get lexicographic indices.
302 // multiIndices[child*subTreeSize+i] = multiIndices[i];
303 // multiIndices[child*subTreeSize+i][0] += child*firstIndexEntrySize;
304 (*next) = multiIndices[i];
305 (*next)[0] += child*firstIndexEntrySize;
306 ++next;
307 }
308 }
309 return next;
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<class NodeType, typename It, class Children>
322 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::BlockedLexicographic) const
323 {
324 using namespace Dune::Indices;
325 size_type subTreeSize = node.child(_0).size();
326 // Fill indices for first child at the beginning.
327 auto next = subPreBasis().indices(node.child(_0), multiIndices);
328 // Insert 0 before first component of all indices for first child.
329 for (std::size_t i = 0; i<subTreeSize; ++i)
330 multiIndexPushFront(multiIndices[i], 0);
331 for (std::size_t child = 1; child<children_; ++child)
332 {
333 for (std::size_t i = 0; i<subTreeSize; ++i)
334 {
335 // Copy indices from first child for all other children and overwrite
336 // zero in first component as inserted above by child index.
337 // multiIndices[child*subTreeSize+i] = multiIndices[i];
338 // multiIndices[child*subTreeSize+i][0] = child;
339 (*next) = multiIndices[i];
340 (*next)[0] = child;
341 ++next;
342 }
343 }
344 return next;
345 }
346
347 template<class NodeType, typename It, class Children>
348 It indicesImpl(const NodeType& node, It multiIndices, Children children, BasisFactory::BlockedInterleaved) const
349 {
350 using namespace Dune::Indices;
351 size_type subTreeSize = node.child(_0).size();
352 // Fill indices for first child at the beginning.
353 auto next = subPreBasis().indices(node.child(_0), multiIndices);
354 // Append 0 after last component of all indices for first child.
355 for (std::size_t i = 0; i<subTreeSize; ++i)
356 multiIndices[i].push_back(0);
357 for (std::size_t child = 1; child<children_; ++child)
358 {
359 for (std::size_t i = 0; i<subTreeSize; ++i)
360 {
361 // Copy indices from first child for all other children and overwrite
362 // zero in last component as appended above by child index.
363 (*next) = multiIndices[i];
364 (*next).back() = child;
365 ++next;
366 }
367 }
368 return next;
369 }
370
371 template<class Children>
372 auto containerDescriptorImpl(Children children) const
373 {
374 auto subTree = Dune::Functions::containerDescriptor(subPreBasis_);
375 if constexpr(std::is_same_v<IMS, BasisFactory::FlatInterleaved>)
376 return ContainerDescriptors::Unknown{}; // Not yet implemented
377 else if constexpr(std::is_same_v<IMS, BasisFactory::FlatLexicographic>)
378 return ContainerDescriptors::Unknown{}; // Not yet implemented
379 else if constexpr(std::is_same_v<IMS, BasisFactory::BlockedLexicographic>)
380 return ContainerDescriptors::makeUniformDescriptor(children,std::move(subTree));
381 else if constexpr(std::is_same_v<IMS, BasisFactory::BlockedInterleaved>)
382 return ContainerDescriptors::Unknown{}; // Not yet implemented
383 else
384 return ContainerDescriptors::Unknown{};
385 }
386
387protected:
388 std::size_t children_;
389 SubPreBasis subPreBasis_;
390};
391
392
393
394namespace BasisFactory {
395
408template<class ChildPreBasisFactory, class IndexMergingStrategy>
409auto power(ChildPreBasisFactory&& childPreBasisFactory, std::size_t k, const IndexMergingStrategy&)
410{
411 return [childPreBasisFactory,k](const auto& gridView) {
412 auto childPreBasis = childPreBasisFactory(gridView);
414 };
415}
416
427template<class ChildPreBasisFactory>
428auto power(ChildPreBasisFactory&& childPreBasisFactory, std::size_t k)
429{
430 return [childPreBasisFactory,k](const auto& gridView) {
431 auto childPreBasis = childPreBasisFactory(gridView);
433 };
434}
435
436} // end namespace BasisFactory
437
438} // end namespace Functions
439} // end namespace Dune
440
441
442#endif // DUNE_FUNCTIONS_FUNCTIONSPACEBASES_DYNAMICPOWERBASIS_HH
A pre-basis for dynamic power bases.
Definition: dynamicpowerbasis.hh:48
std::size_t size_type
Type used for indices and size information.
Definition: dynamicpowerbasis.hh:60
IMS IndexMergingStrategy
Strategy used to merge the global indices of the child factories.
Definition: dynamicpowerbasis.hh:63
DynamicPowerPreBasis(std::size_t c, SFArgs &&... sfArgs)
Constructor for given child pre-basis objects.
Definition: dynamicpowerbasis.hh:80
size_type dimension() const
Get the total dimension of the space spanned by this basis.
Definition: dynamicpowerbasis.hh:222
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:248
void initializeIndices()
Initialize the global indices.
Definition: dynamicpowerbasis.hh:88
void update(const GridView &gv)
Update the stored grid view, to be called if the grid has changed.
Definition: dynamicpowerbasis.hh:100
auto containerDescriptor() const
Return the associated container descriptor.
Definition: dynamicpowerbasis.hh:254
size_type size() const
Same as size(prefix) with empty prefix.
Definition: dynamicpowerbasis.hh:122
SubPreBasis & subPreBasis()
Mutable access to the stored prebasis of the factor in the power space.
Definition: dynamicpowerbasis.hh:240
SPB SubPreBasis
The child pre-basis.
Definition: dynamicpowerbasis.hh:54
Node makeNode() const
Create tree node.
Definition: dynamicpowerbasis.hh:108
const SubPreBasis & subPreBasis() const
Const access to the stored prebasis of the factor in the power space.
Definition: dynamicpowerbasis.hh:234
size_type maxNodeSize() const
Get the maximal number of DOFs associated to node for any element.
Definition: dynamicpowerbasis.hh:228
size_type size(const SizePrefix &prefix) const
Return number of possible values for next position in multi index.
Definition: dynamicpowerbasis.hh:129
DynamicPowerBasisNode< typename SubPreBasis::Node > Node
Template mapping root tree path to type of created tree node.
Definition: dynamicpowerbasis.hh:66
typename SPB::GridView GridView
The grid view that the FE basis is defined on.
Definition: dynamicpowerbasis.hh:57
const GridView & gridView() const
Obtain the grid view that the basis is defined on.
Definition: dynamicpowerbasis.hh:94
auto power(ChildPreBasisFactory &&childPreBasisFactory, std::size_t k)
Create a factory builder that can build a PowerPreBasis.
Definition: dynamicpowerbasis.hh:428
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
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  |  generated with Hugo v0.111.3 (Aug 14, 22:29, 2024)