/usr/include/dune/functions/gridfunctions/discreteglobalbasisfunction.hh is in libdune-functions-dev 2.5.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
#define DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
#include <memory>
#include <dune/common/shared_ptr.hh>
#include <dune/functions/functionspacebases/defaultnodetorangemap.hh>
#include <dune/functions/functionspacebases/flatvectorbackend.hh>
#include <dune/functions/gridfunctions/gridviewentityset.hh>
#include <dune/functions/gridfunctions/gridfunction.hh>
#include <dune/functions/common/treedata.hh>
namespace Dune {
namespace Functions {
/**
* \brief A grid function induced by a global basis and a coefficient vector
*
* \ingroup FunctionImplementations
*
* This implements the grid function interface by combining a given global
* basis and a coefficient vector. The part of the spanned space that should
* be covered by the function is determined by a tree path that specifies the
* corresponding local ansatz tree.
*
* This class supports mapping of subtrees to multi-component ranges,
* vector-valued shape functions, and implicit product spaces given
* by vector-valued coefficients. The mapping of these to the range
* type is done via the following multistage procedure:
*
* 1.Each leaf node N in the local ansatz subtree is associated to an entry
* RE of the range-type via the given node-to-range-entry-map.
*
* Now let C be the coefficient block for a single basis function and
* V the value of this basis function at the evaluation point. Notice
* that both may be scalar, vector, matrix, or general container valued.
*
* 2.Each entry of C is associated with a flat index j via FlatVectorBackend.
* This is normally a lexicographic index. The total scalar dimension according
* to those flat indices is dim(C).
* 3.Each entry of V is associated with a flat index k via FlatVectorBackend.
* This is normally a lexicographic index. The total scalar dimension according
* to those flat indices dim(V).
* 4.Each entry of RE is associated with a flat index k via FlatVectorBackend.
* This is normally a lexicographic index. The total scalar dimension according
* to those flat indices dim(RE).
* 5.Via those flat indices we now interpret C,V, and RE as vectors and compute the diadic
* product (C x V). The entries of this product are mapped to the flat indices for
* RE lexicographically. I.e. we set
*
* RE[j*dim(V)+k] = C[j] * V[k]
*
* Hence the range entry RE must have dim(RE) = dim(C)*dim(V).
*
* \tparam B Type of lobal basis
* \tparam TP Type of tree path specifying the requested subtree of ansatz functions
* \tparam V Type of coefficient vectors
* \tparam NTRE Type of node-to-range-entry-map that associates each leaf node in the local ansatz subtree with an entry in the range type
* \tparam R Range type of this function
*/
template<typename B, typename TP, typename V,
typename NTRE = DefaultNodeToRangeMap<typename std::decay<decltype(std::declval<B>().localView().tree().child(std::declval<TP>()))>::type>,
typename R = typename V::value_type>
class DiscreteGlobalBasisFunction
{
public:
using Basis = B;
using TreePath = TP;
using Vector = V;
using GridView = typename Basis::GridView;
using EntitySet = GridViewEntitySet<GridView, 0>;
using Tree = typename Basis::LocalView::Tree;
using SubTree = typename TypeTree::ChildForTreePath<Tree, TreePath>;
using NodeToRangeEntry = NTRE;
using Domain = typename EntitySet::GlobalCoordinate;
using Range = R;
using LocalDomain = typename EntitySet::LocalCoordinate;
using Element = typename EntitySet::Element;
using Traits = Imp::GridFunctionTraits<Range(Domain), EntitySet, DefaultDerivativeTraits, 16>;
class LocalFunction
{
using LocalBasisView = typename Basis::LocalView;
using LocalIndexSet = typename Basis::LocalIndexSet;
using size_type = typename SubTree::size_type;
template<class Node>
using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType;
template<class Node>
using NodeData = typename std::vector<LocalBasisRange<Node>>;
using ShapeFunctionValueContainer = TreeData<SubTree, NodeData, true>;
struct LocalEvaluateVisitor
: public TypeTree::TreeVisitor
, public TypeTree::DynamicTraversal
{
LocalEvaluateVisitor(const LocalDomain& x, Range& y, const LocalIndexSet& localIndexSet, const Vector& coefficients, const NodeToRangeEntry& nodeToRangeEntry, ShapeFunctionValueContainer& shapeFunctionValueContainer):
x_(x),
y_(y),
localIndexSet_(localIndexSet),
coefficients_(coefficients),
nodeToRangeEntry_(nodeToRangeEntry),
shapeFunctionValueContainer_(shapeFunctionValueContainer)
{}
template<typename Node, typename TreePath>
void leaf(Node& node, TreePath treePath)
{
using LocalBasisRange = typename Node::FiniteElement::Traits::LocalBasisType::Traits::RangeType;
using MultiIndex = typename LocalIndexSet::MultiIndex;
using CoefficientBlock = typename std::decay<decltype(std::declval<Vector>()[std::declval<MultiIndex>()])>::type;
using RangeBlock = typename std::decay<decltype(nodeToRangeEntry_(node, y_))>::type;
auto&& fe = node.finiteElement();
auto&& localBasis = fe.localBasis();
auto&& shapeFunctionValues = shapeFunctionValueContainer_[node];
localBasis.evaluateFunction(x_, shapeFunctionValues);
// Get range entry associated to this node
auto&& re = nodeToRangeEntry_(node, y_);
for (size_type i = 0; i < localBasis.size(); ++i)
{
auto&& multiIndex = localIndexSet_.index(node.localIndex(i));
// Get coefficient associated to i-th shape function
auto&& c = coefficients_[multiIndex];
// Get value of i-th shape function
auto&& v = shapeFunctionValues[i];
// Notice that the range entry re, the coefficient c, and the shape functions
// value v may all be scalar, vector, matrix, or general container valued.
// The matching of their entries is done via the multistage procedure described
// in the class documentation of DiscreteGlobalBasisFunction.
auto dimC = FlatVectorBackend<CoefficientBlock>::size(c);
auto dimV = FlatVectorBackend<LocalBasisRange>::size(v);
assert(dimC*dimV == FlatVectorBackend<RangeBlock>::size(re));
for(size_type j=0; j<dimC; ++j)
{
auto&& c_j = FlatVectorBackend<CoefficientBlock>::getEntry(c, j);
for(size_type k=0; k<dimV; ++k)
{
auto&& v_k = FlatVectorBackend<LocalBasisRange>::getEntry(v, k);
FlatVectorBackend<RangeBlock>::getEntry(re, j*dimV + k) += c_j*v_k;
}
}
}
}
const LocalDomain& x_;
Range& y_;
const LocalIndexSet& localIndexSet_;
const Vector& coefficients_;
const NodeToRangeEntry& nodeToRangeEntry_;
ShapeFunctionValueContainer& shapeFunctionValueContainer_;
};
public:
using GlobalFunction = DiscreteGlobalBasisFunction;
using Domain = LocalDomain;
using Range = GlobalFunction::Range;
using Element = GlobalFunction::Element;
LocalFunction(const DiscreteGlobalBasisFunction& globalFunction)
: globalFunction_(&globalFunction)
, localBasisView_(globalFunction.basis().localView())
, localIndexSet_(globalFunction.basis().localIndexSet())
{
// Here we assume that the tree can be accessed, traversed,
// and queried for tree indices even in unbound state.
subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath());
shapeFunctionValueContainer_.init(*subTree_);
// localDoFs_.reserve(localBasisView_.maxSize());
}
LocalFunction(const LocalFunction& other)
: globalFunction_(other.globalFunction_)
, localBasisView_(globalFunction_->basis().localView())
, localIndexSet_(globalFunction_->basis().localIndexSet())
{
// Here we assume that the tree can be accessed, traversed,
// and queried for tree indices even in unbound state.
subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath());
shapeFunctionValueContainer_.init(*subTree_);
}
LocalFunction operator=(const LocalFunction& other)
{
globalFunction_ = other.globalFunction_;
localBasisView_ = other.localBasisView_;
localIndexSet_ = other.localIndexSet_;
subTree_ = &TypeTree::child(localBasisView_.tree(), globalFunction_->treePath());
// Here we assume that the tree can be accessed, traversed,
// and queried for tree indices even in unbound state.
shapeFunctionValueContainer_.init(*subTree_);
}
/**
* \brief Bind LocalFunction to grid element.
*
* You must call this method before evaluate()
* and after changes to the coefficient vector.
*/
void bind(const Element& element)
{
localBasisView_.bind(element);
localIndexSet_.bind(localBasisView_);
// Read dofs associated to bound element
// localDoFs_.resize(subTree.size());
// for (size_type i = 0; i < subTree.size(); ++i)
// localDoFs_[i] = globalFunction_->dofs()[localIndexSet_.index(i)];
}
void unbind()
{
localIndexSet_.unbind();
localBasisView_.unbind();
}
/**
* \brief Evaluate LocalFunction at bound element.
*
* The result of this method is undefined if you did
* not call bind() beforehand or changed the coefficient
* vector after the last call to bind(). In the latter case
* you have to call bind() again in order to make operator()
* usable.
*/
Range operator()(const Domain& x) const
{
auto y = Range(0);
LocalEvaluateVisitor localEvaluateVisitor(x, y, localIndexSet_, globalFunction_->dofs(), globalFunction_->nodeToRangeEntry(), shapeFunctionValueContainer_);
TypeTree::applyToTree(*subTree_, localEvaluateVisitor);
return y;
}
const Element& localContext() const
{
return localBasisView_.element();
}
friend typename Traits::LocalFunctionTraits::DerivativeInterface derivative(const LocalFunction& t)
{
DUNE_THROW(NotImplemented,"not implemented");
}
private:
const DiscreteGlobalBasisFunction* globalFunction_;
LocalBasisView localBasisView_;
LocalIndexSet localIndexSet_;
mutable ShapeFunctionValueContainer shapeFunctionValueContainer_;
// std::vector<typename V::value_type> localDoFs_;
const SubTree* subTree_;
};
DiscreteGlobalBasisFunction(const Basis & basis, const TreePath& treePath, const V & coefficients, const NodeToRangeEntry& nodeToRangeEntry) :
entitySet_(basis.gridView()),
basis_(stackobject_to_shared_ptr(basis)),
treePath_(treePath),
coefficients_(stackobject_to_shared_ptr(coefficients)),
nodeToRangeEntry_(stackobject_to_shared_ptr(nodeToRangeEntry))
{}
DiscreteGlobalBasisFunction(std::shared_ptr<const Basis> basis, const TreePath& treePath, std::shared_ptr<const V> coefficients, std::shared_ptr<const NodeToRangeEntry> nodeToRangeEntry) :
entitySet_(basis->gridView()),
basis_(basis),
treePath_(treePath),
coefficients_(coefficients),
nodeToRangeEntry_(nodeToRangeEntry)
{}
const Basis& basis() const
{
return *basis_;
}
const TreePath& treePath() const
{
return treePath_;
}
const V& dofs() const
{
return *coefficients_;
}
const NodeToRangeEntry& nodeToRangeEntry() const
{
return *nodeToRangeEntry_;
}
// TODO: Implement this using hierarchic search
Range operator() (const Domain& x) const
{
DUNE_THROW(NotImplemented,"not implemented");
}
friend typename Traits::DerivativeInterface derivative(const DiscreteGlobalBasisFunction& t)
{
DUNE_THROW(NotImplemented,"not implemented");
}
friend LocalFunction localFunction(const DiscreteGlobalBasisFunction& t)
{
return LocalFunction(t);
}
/**
* \brief Get associated EntitySet
*/
const EntitySet& entitySet() const
{
return entitySet_;
}
private:
EntitySet entitySet_;
std::shared_ptr<const Basis> basis_;
const TreePath treePath_;
std::shared_ptr<const V> coefficients_;
std::shared_ptr<const NodeToRangeEntry> nodeToRangeEntry_;
};
template<typename R, typename B, typename TP, typename V>
auto makeDiscreteGlobalBasisFunction(B&& basis, const TP& treePath, V&& vector)
{
using Basis = std::decay_t<B>;
using Vector = std::decay_t<V>;
using NTREM = DefaultNodeToRangeMap<typename TypeTree::ChildForTreePath<typename Basis::LocalView::Tree, TP>>;
auto nodeToRangeEntryPtr = std::make_shared<NTREM>(makeDefaultNodeToRangeMap(basis, treePath));
auto basisPtr = Dune::wrap_or_move(std::forward<B>(basis));
auto vectorPtr = Dune::wrap_or_move(std::forward<V>(vector));
return DiscreteGlobalBasisFunction<Basis, TP, Vector, NTREM, R>(basisPtr, treePath, vectorPtr, nodeToRangeEntryPtr);
}
template<typename R, typename B, typename V>
auto makeDiscreteGlobalBasisFunction(B&& basis, V&& vector)
{
return makeDiscreteGlobalBasisFunction<R>(std::forward<B>(basis), TypeTree::hybridTreePath(), std::forward<V>(vector));
}
} // namespace Functions
} // namespace Dune
#endif // DUNE_FUNCTIONS_GRIDFUNCTIONS_DISCRETEGLOBALBASISFUNCTIONS_HH
|