DUNE-FUNCTIONS (unstable)

discreteglobalbasisfunction.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_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
4 #define DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
5 
6 #include <memory>
7 #include <optional>
8 
9 #include <dune/common/typetraits.hh>
10 
11 #include <dune/grid/utility/hierarchicsearch.hh>
12 
13 #include <dune/typetree/treecontainer.hh>
14 
15 #include <dune/functions/functionspacebases/hierarchicnodetorangemap.hh>
16 #include <dune/functions/functionspacebases/flatvectorview.hh>
17 #include <dune/functions/gridfunctions/gridviewentityset.hh>
18 #include <dune/functions/gridfunctions/gridfunction.hh>
19 #include <dune/functions/backends/concepts.hh>
20 #include <dune/functions/backends/istlvectorbackend.hh>
21 
22 namespace Dune {
23 namespace Functions {
24 
25 
26 namespace ImplDoc {
27 
28 template<typename B, typename V, typename NTRE>
29 class DiscreteGlobalBasisFunctionBase
30 {
31 public:
32  using Basis = B;
33  using Vector = V;
34 
35  // In order to make the cache work for proxy-references
36  // we have to use AutonomousValue<T> instead of std::decay_t<T>
37  using Coefficient = Dune::AutonomousValue<decltype(std::declval<Vector>()[std::declval<typename Basis::MultiIndex>()])>;
38 
39  using GridView = typename Basis::GridView;
40  using EntitySet = GridViewEntitySet<GridView, 0>;
41  using Tree = typename Basis::LocalView::Tree;
42  using NodeToRangeEntry = NTRE;
43 
44  using Domain = typename EntitySet::GlobalCoordinate;
45 
46  using LocalDomain = typename EntitySet::LocalCoordinate;
47  using Element = typename EntitySet::Element;
48 
49 protected:
50 
51  // This collects all data that is shared by all related
52  // global and local functions. This way we don't need to
53  // keep track of it individually.
54  struct Data
55  {
56  EntitySet entitySet;
57  std::shared_ptr<const Basis> basis;
58  std::shared_ptr<const Vector> coefficients;
59  std::shared_ptr<const NodeToRangeEntry> nodeToRangeEntry;
60  };
61 
62 public:
63  class LocalFunctionBase
64  {
65  using LocalView = typename Basis::LocalView;
66  using size_type = typename Tree::size_type;
67 
68  public:
69  using Domain = LocalDomain;
70  using Element = typename EntitySet::Element;
71 
72  protected:
73  LocalFunctionBase(const std::shared_ptr<const Data>& data)
74  : data_(data)
75  , localView_(data_->basis->localView())
76  {
77  localDoFs_.reserve(localView_.maxSize());
78  }
79 
86  LocalFunctionBase(const LocalFunctionBase& other)
87  : data_(other.data_)
88  , localView_(other.localView_)
89  {
90  localDoFs_.reserve(localView_.maxSize());
91  if (bound())
92  localDoFs_ = other.localDoFs_;
93  }
94 
102  LocalFunctionBase& operator=(const LocalFunctionBase& other)
103  {
104  data_ = other.data_;
105  localView_ = other.localView_;
106  if (bound())
107  localDoFs_ = other.localDoFs_;
108  return *this;
109  }
110 
111  public:
118  void bind(const Element& element)
119  {
120  localView_.bind(element);
121  // Use cache of full local view size. For a subspace basis,
122  // this may be larger than the number of local DOFs in the
123  // tree. In this case only cache entries associated to local
124  // DOFs in the subspace are filled. Cache entries associated
125  // to local DOFs which are not contained in the subspace will
126  // not be touched.
127  //
128  // Alternatively one could use a cache that exactly fits
129  // the size of the tree. However, this would require to
130  // subtract an offset from localIndex(i) on each cache
131  // access in operator().
132  localDoFs_.resize(localView_.size());
133  const auto& dofs = *data_->coefficients;
134  for (size_type i = 0; i < localView_.tree().size(); ++i)
135  {
136  // For a subspace basis the index-within-tree i
137  // is not the same as the localIndex within the
138  // full local view.
139  size_t localIndex = localView_.tree().localIndex(i);
140  localDoFs_[localIndex] = dofs[localView_.index(localIndex)];
141  }
142  }
143 
145  void unbind()
146  {
147  localView_.unbind();
148  }
149 
151  bool bound() const
152  {
153  return localView_.bound();
154  }
155 
157  const Element& localContext() const
158  {
159  return localView_.element();
160  }
161 
162  protected:
163 
164  template<class To, class From>
165  void assignWith(To& to, const From& from) const
166  {
167  auto from_flat = flatVectorView(from);
168  auto to_flat = flatVectorView(to);
169  assert(from_flat.size() == to_flat.size());
170  for (size_type i = 0; i < to_flat.size(); ++i)
171  to_flat[i] = from_flat[i];
172  }
173 
174  template<class Node, class TreePath, class Range>
175  decltype(auto) nodeToRangeEntry(const Node& node, const TreePath& treePath, Range& y) const
176  {
177  return (*data_->nodeToRangeEntry)(node, treePath, y);
178  }
179 
180  std::shared_ptr<const Data> data_;
181  LocalView localView_;
182  std::vector<Coefficient> localDoFs_;
183  };
184 
185 protected:
186  DiscreteGlobalBasisFunctionBase(const std::shared_ptr<const Data>& data)
187  : data_(data)
188  {
189  /* Nothing. */
190  }
191 
192 public:
193 
195  const Basis& basis() const
196  {
197  return *data_->basis;
198  }
199 
201  const Vector& dofs() const
202  {
203  return *data_->coefficients;
204  }
205 
207  const NodeToRangeEntry& nodeToRangeEntry() const
208  {
209  return *data_->nodeToRangeEntry;
210  }
211 
213  const EntitySet& entitySet() const
214  {
215  return data_->entitySet;
216  }
217 
218 protected:
219  std::shared_ptr<const Data> data_;
220 };
221 
222 } // namespace ImplDoc
223 
224 
225 
226 template<typename DGBF>
227 class DiscreteGlobalBasisFunctionDerivative;
228 
272 template<typename B, typename V,
273  typename NTRE = HierarchicNodeToRangeMap,
274  typename R = typename V::value_type>
276  : public ImplDoc::DiscreteGlobalBasisFunctionBase<B, V, NTRE>
277 {
278  using Base = ImplDoc::DiscreteGlobalBasisFunctionBase<B, V, NTRE>;
279  using Data = typename Base::Data;
280 
281 public:
282  using Basis = typename Base::Basis;
283  using Vector = typename Base::Vector;
284 
285  using Domain = typename Base::Domain;
286  using Range = R;
287 
288  using Traits = Imp::GridFunctionTraits<Range(Domain), typename Base::EntitySet, DefaultDerivativeTraits, 16>;
289 
290 private:
291 
292  template<class Node>
293  using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType;
294  template<class Node>
295  using NodeData = typename std::vector<LocalBasisRange<Node>>;
296  using PerNodeEvaluationBuffer = typename TypeTree::TreeContainer<NodeData, typename Base::Tree>;
297 
298 public:
299  class LocalFunction
300  : public Base::LocalFunctionBase
301  {
302  using LocalBase = typename Base::LocalFunctionBase;
303  using size_type = typename Base::Tree::size_type;
304  using LocalBase::nodeToRangeEntry;
305 
306  public:
307 
308  using GlobalFunction = DiscreteGlobalBasisFunction;
309  using Domain = typename LocalBase::Domain;
310  using Range = GlobalFunction::Range;
311  using Element = typename LocalBase::Element;
312 
314  LocalFunction(const DiscreteGlobalBasisFunction& globalFunction)
315  : LocalBase(globalFunction.data_)
316  , evaluationBuffer_(this->localView_.tree())
317  {
318  /* Nothing. */
319  }
320 
330  Range operator()(const Domain& x) const
331  {
332  Range y;
333  istlVectorBackend(y) = 0;
334 
335  TypeTree::forEachLeafNode(this->localView_.tree(), [&](auto&& node, auto&& treePath) {
336  const auto& fe = node.finiteElement();
337  const auto& localBasis = fe.localBasis();
338  auto& shapeFunctionValues = evaluationBuffer_[treePath];
339 
340  localBasis.evaluateFunction(x, shapeFunctionValues);
341 
342  // Compute linear combinations of basis function jacobian.
343  // Non-scalar coefficients of dimension coeffDim are handled by
344  // processing the coeffDim linear combinations independently
345  // and storing them as entries of an array.
346  using Value = LocalBasisRange< std::decay_t<decltype(node)> >;
347  static constexpr auto coeffDim = decltype(flatVectorView(this->localDoFs_[node.localIndex(0)]).size())::value;
348  auto values = std::array<Value, coeffDim>{};
349  istlVectorBackend(values) = 0;
350  for (size_type i = 0; i < localBasis.size(); ++i)
351  {
352  auto c = flatVectorView(this->localDoFs_[node.localIndex(i)]);
353  for (std::size_t j = 0; j < coeffDim; ++j)
354  values[j].axpy(c[j], shapeFunctionValues[i]);
355  }
356 
357  // Assign computed values to node entry of range.
358  // Types are matched using the lexicographic ordering provided by flatVectorView.
359  LocalBase::assignWith(nodeToRangeEntry(node, treePath, y), values);
360  });
361 
362  return y;
363  }
364 
367  {
369  if (lf.bound())
370  dlf.bind(lf.localContext());
371  return dlf;
372  }
373 
374  private:
375  mutable PerNodeEvaluationBuffer evaluationBuffer_;
376  };
377 
379  template<class B_T, class V_T, class NTRE_T>
380  DiscreteGlobalBasisFunction(B_T && basis, V_T && coefficients, NTRE_T&& nodeToRangeEntry)
381  : Base(std::make_shared<Data>(Data{{basis.gridView()}, wrap_or_move(std::forward<B_T>(basis)), wrap_or_move(std::forward<V_T>(coefficients)), wrap_or_move(std::forward<NTRE_T>(nodeToRangeEntry))}))
382  {}
383 
385  DiscreteGlobalBasisFunction(std::shared_ptr<const Basis> basis, std::shared_ptr<const V> coefficients, std::shared_ptr<const typename Base::NodeToRangeEntry> nodeToRangeEntry)
386  : Base(std::make_shared<Data>(Data{{basis->gridView()}, basis, coefficients, nodeToRangeEntry}))
387  {}
388 
394  Range operator() (const Domain& x) const
395  {
396  HierarchicSearch search(this->data_->basis->gridView().grid(), this->data_->basis->gridView().indexSet());
397 
398  const auto e = search.findEntity(x);
399  auto localThis = localFunction(*this);
400  localThis.bind(e);
401  return localThis(e.geometry().local(x));
402  }
403 
406  {
408  }
409 
418  friend LocalFunction localFunction(const DiscreteGlobalBasisFunction& t)
419  {
420  return LocalFunction(t);
421  }
422 };
423 
424 
449 template<typename R, typename B, typename V>
450 auto makeDiscreteGlobalBasisFunction(B&& basis, V&& vector)
451 {
452  using Basis = std::decay_t<B>;
453  using NTREM = HierarchicNodeToRangeMap;
454 
455  // Small helper functions to wrap vectors using istlVectorBackend
456  // if they do not already satisfy the VectorBackend interface.
457  auto toConstVectorBackend = [&](auto&& v) -> decltype(auto) {
458  if constexpr (models<Concept::ConstVectorBackend<Basis>, decltype(v)>()) {
459  return std::forward<decltype(v)>(v);
460  } else {
461  return istlVectorBackend(v);
462  }
463  };
464 
465  using Vector = std::decay_t<decltype(toConstVectorBackend(std::forward<V>(vector)))>;
467  std::forward<B>(basis),
468  toConstVectorBackend(std::forward<V>(vector)),
470 }
471 
472 
487 template<typename DGBF>
489  : public ImplDoc::DiscreteGlobalBasisFunctionBase<typename DGBF::Basis, typename DGBF::Vector, typename DGBF::NodeToRangeEntry>
490 {
491  using Base = ImplDoc::DiscreteGlobalBasisFunctionBase<typename DGBF::Basis, typename DGBF::Vector, typename DGBF::NodeToRangeEntry>;
492  using Data = typename Base::Data;
493 
494 public:
495  using DiscreteGlobalBasisFunction = DGBF;
496 
497  using Basis = typename Base::Basis;
498  using Vector = typename Base::Vector;
499 
500  using Domain = typename Base::Domain;
502 
503  using Traits = Imp::GridFunctionTraits<Range(Domain), typename Base::EntitySet, DefaultDerivativeTraits, 16>;
504 
505 private:
506 
507  template<class Node>
508  using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::JacobianType;
509  template<class Node>
510  using NodeData = typename std::vector< LocalBasisRange<Node> >;
511  using PerNodeEvaluationBuffer = typename TypeTree::TreeContainer<NodeData, typename Base::Tree>;
512 
513 public:
514 
523  : public Base::LocalFunctionBase
524  {
525  using LocalBase = typename Base::LocalFunctionBase;
526  using size_type = typename Base::Tree::size_type;
527  using LocalBase::nodeToRangeEntry;
528 
529  public:
531  using Domain = typename LocalBase::Domain;
532  using Range = GlobalFunction::Range;
533  using Element = typename LocalBase::Element;
534 
536  LocalFunction(const GlobalFunction& globalFunction)
537  : LocalBase(globalFunction.data_)
538  , evaluationBuffer_(this->localView_.tree())
539  {
540  /* Nothing. */
541  }
542 
549  void bind(const Element& element)
550  {
551  LocalBase::bind(element);
552  geometry_.emplace(element.geometry());
553  }
554 
556  void unbind()
557  {
558  geometry_.reset();
559  LocalBase::unbind();
560  }
561 
575  Range operator()(const Domain& x) const
576  {
577  Range y;
578  istlVectorBackend(y) = 0;
579 
580  const auto& jacobianInverse = geometry_->jacobianInverse(x);
581 
582  TypeTree::forEachLeafNode(this->localView_.tree(), [&](auto&& node, auto&& treePath) {
583  const auto& fe = node.finiteElement();
584  const auto& localBasis = fe.localBasis();
585  auto& shapeFunctionJacobians = evaluationBuffer_[treePath];
586 
587  localBasis.evaluateJacobian(x, shapeFunctionJacobians);
588 
589  // Compute linear combinations of basis function jacobian.
590  // Non-scalar coefficients of dimension coeffDim are handled by
591  // processing the coeffDim linear combinations independently
592  // and storing them as entries of an array.
593  using RefJacobian = LocalBasisRange< std::decay_t<decltype(node)> >;
594  static constexpr auto coeffDim = decltype(flatVectorView(this->localDoFs_[node.localIndex(0)]).size())::value;
595  auto refJacobians = std::array<RefJacobian, coeffDim>{};
596  istlVectorBackend(refJacobians) = 0;
597  for (size_type i = 0; i < localBasis.size(); ++i)
598  {
599  auto c = flatVectorView(this->localDoFs_[node.localIndex(i)]);
600  for (std::size_t j = 0; j < coeffDim; ++j)
601  refJacobians[j].axpy(c[j], shapeFunctionJacobians[i]);
602  }
603 
604  // Transform Jacobians form local to global coordinates.
605  using Jacobian = decltype(refJacobians[0] * jacobianInverse);
606  auto jacobians = std::array<Jacobian, coeffDim>{};
607  std::transform(
608  refJacobians.begin(), refJacobians.end(), jacobians.begin(),
609  [&](const auto& refJacobian) { return refJacobian * jacobianInverse; });
610 
611  // Assign computed Jacobians to node entry of range.
612  // Types are matched using the lexicographic ordering provided by flatVectorView.
613  LocalBase::assignWith(nodeToRangeEntry(node, treePath, y), jacobians);
614  });
615 
616  return y;
617  }
618 
620  friend typename Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction&)
621  {
622  DUNE_THROW(NotImplemented, "derivative of derivative is not implemented");
623  }
624 
625  private:
626  mutable PerNodeEvaluationBuffer evaluationBuffer_;
627  std::optional<typename Element::Geometry> geometry_;
628  };
629 
636  DiscreteGlobalBasisFunctionDerivative(const std::shared_ptr<const Data>& data)
637  : Base(data)
638  {
639  /* Nothing. */
640  }
641 
647  Range operator()(const Domain& x) const
648  {
649  HierarchicSearch search(this->data_->basis->gridView().grid(), this->data_->basis->gridView().indexSet());
650 
651  const auto e = search.findEntity(x);
652  auto localThis = localFunction(*this);
653  localThis.bind(e);
654  return localThis(e.geometry().local(x));
655  }
656 
657  friend typename Traits::DerivativeInterface derivative(const DiscreteGlobalBasisFunctionDerivative& f)
658  {
659  DUNE_THROW(NotImplemented, "derivative of derivative is not implemented");
660  }
661 
664  {
665  return LocalFunction(f);
666  }
667 };
668 
669 
670 } // namespace Functions
671 } // namespace Dune
672 
673 #endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
local function evaluating the derivative in reference coordinates
Definition: discreteglobalbasisfunction.hh:524
Range operator()(const Domain &x) const
Evaluate this local-function in coordinates x in the bound element.
Definition: discreteglobalbasisfunction.hh:575
friend Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction &)
Not implemented.
Definition: discreteglobalbasisfunction.hh:620
void unbind()
Unbind the local-function.
Definition: discreteglobalbasisfunction.hh:556
LocalFunction(const GlobalFunction &globalFunction)
Create a local function from the associated grid function.
Definition: discreteglobalbasisfunction.hh:536
void bind(const Element &element)
Bind LocalFunction to grid element.
Definition: discreteglobalbasisfunction.hh:549
Derivative of a DiscreteGlobalBasisFunction
Definition: discreteglobalbasisfunction.hh:490
Range operator()(const Domain &x) const
Evaluate the discrete grid-function derivative in global coordinates.
Definition: discreteglobalbasisfunction.hh:647
friend LocalFunction localFunction(const DiscreteGlobalBasisFunctionDerivative &f)
Construct local function from a DiscreteGlobalBasisFunctionDerivative
Definition: discreteglobalbasisfunction.hh:663
DiscreteGlobalBasisFunctionDerivative(const std::shared_ptr< const Data > &data)
create object from DiscreateGlobalBasisFunction data
Definition: discreteglobalbasisfunction.hh:636
A grid function induced by a global basis and a coefficient vector.
Definition: discreteglobalbasisfunction.hh:277
friend DiscreteGlobalBasisFunctionDerivative< DiscreteGlobalBasisFunction > derivative(const DiscreteGlobalBasisFunction &f)
Derivative of the DiscreteGlobalBasisFunction
Definition: discreteglobalbasisfunction.hh:405
DiscreteGlobalBasisFunction(B_T &&basis, V_T &&coefficients, NTRE_T &&nodeToRangeEntry)
Create a grid-function, by wrapping the arguments in std::shared_ptr.
Definition: discreteglobalbasisfunction.hh:380
DiscreteGlobalBasisFunction(std::shared_ptr< const Basis > basis, std::shared_ptr< const V > coefficients, std::shared_ptr< const typename Base::NodeToRangeEntry > nodeToRangeEntry)
Create a grid-function, by moving the arguments in std::shared_ptr.
Definition: discreteglobalbasisfunction.hh:385
friend LocalFunction localFunction(const DiscreteGlobalBasisFunction &t)
Construct local function from a DiscreteGlobalBasisFunction.
Definition: discreteglobalbasisfunction.hh:418
Range operator()(const Domain &x) const
Evaluate at a point given in world coordinates.
Definition: discreteglobalbasisfunction.hh:394
GridView::template Codim< codim >::Entity Element
Type of Elements contained in this EntitySet.
Definition: gridviewentityset.hh:32
Element::Geometry::LocalCoordinate LocalCoordinate
Type of local coordinates with respect to the Element.
Definition: gridviewentityset.hh:35
TrigonometricFunction< K, -cosFactor, sinFactor > derivative(const TrigonometricFunction< K, sinFactor, cosFactor > &f)
Obtain derivative of TrigonometricFunction function.
Definition: trigonometricfunction.hh:39
auto makeDiscreteGlobalBasisFunction(B &&basis, V &&vector)
Generate a DiscreteGlobalBasisFunction.
Definition: discreteglobalbasisfunction.hh:450
auto istlVectorBackend(Vector &v)
Return a vector backend wrapping non-const ISTL like containers.
Definition: istlvectorbackend.hh:346
Definition: polynomial.hh:13
Default implementation for derivative traits.
Definition: defaultderivativetraits.hh:37
A simple node to range map using the nested tree indices.
Definition: hierarchicnodetorangemap.hh:30
Helper class to deduce the signature of a callable.
Definition: signature.hh:56
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.80.0 (May 9, 22:29, 2024)