From 5d742221e0e16b84241aca0ee274cfb9376bb4ad Mon Sep 17 00:00:00 2001 From: Lisa Julia Nebel <lisa_julia.nebel@tu-dresden.de> Date: Wed, 7 Oct 2020 13:29:34 +0200 Subject: [PATCH] Add localintegralenergy.hh and neumannenergy.hh, they assemble the energy for a single element and work with a CompositeBasis These classes work similarly to Dune::Elasticity::LocalIntegralEnergy and Dune::Elasticity::NeumannEnergy, where the ones in Dune::Elasticity with a power basis (for the displacement function) and Dune::GFE::LocalIntegralEnergy / Dune::GFE::NeumannEnergy work with a CompositeBasis (for the displacement AND the rotation), so the indices to access the different parts of the basis are different. --- dune/gfe/localintegralenergy.hh | 105 ++++++++++++++++++++++++++++++++ dune/gfe/neumannenergy.hh | 103 +++++++++++++++++++++++++++++++ 2 files changed, 208 insertions(+) create mode 100644 dune/gfe/localintegralenergy.hh create mode 100644 dune/gfe/neumannenergy.hh diff --git a/dune/gfe/localintegralenergy.hh b/dune/gfe/localintegralenergy.hh new file mode 100644 index 00000000..e6d85ef1 --- /dev/null +++ b/dune/gfe/localintegralenergy.hh @@ -0,0 +1,105 @@ +#ifndef DUNE_GFE_LOCALINTEGRALENERGY_HH +#define DUNE_GFE_LOCALINTEGRALENERGY_HH + +#include <dune/common/fmatrix.hh> +#include <dune/common/fmatrixev.hh> + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/gfe/localenergy.hh> +#include <dune/gfe/realtuple.hh> +#include <dune/gfe/rigidbodymotion.hh> + +#include <dune/elasticity/materials/localdensity.hh> + +namespace Dune::GFE { + + /** + \brief Assembles the elastic energy for a single element integrating the localdensity over one element. + + This class works similarly to the class Dune::Elasticity::LocalIntegralEnergy, where Dune::Elasticity::LocalIntegralEnergy extends + Dune::Elasticity::LocalEnergy and Dune::GFE::LocalIntegralEnergy extends Dune::GFE::LocalEnergy. + */ +template<class Basis, class... TargetSpaces> +class LocalIntegralEnergy + : public Dune::GFE::LocalEnergy<Basis,TargetSpaces...> +{ + using LocalView = typename Basis::LocalView; + using GridView = typename LocalView::GridView; + using DT = typename GridView::Grid::ctype; + using RT = typename Dune::GFE::LocalEnergy<Basis,TargetSpaces...>::RT; + + enum {gridDim=GridView::dimension}; + +public: + + /** \brief Constructor with a local energy density + */ + LocalIntegralEnergy(const std::shared_ptr<Dune::Elasticity::LocalDensity<gridDim,RT,DT>>& ld) + : localDensity_(ld) + {} + + /** \brief Assemble the energy for a single element */ + RT energy(const typename Basis::LocalView& localView, + const std::vector<TargetSpaces>&... localSolutions) const + { + static_assert(sizeof...(TargetSpaces) > 0, "LocalIntegralEnergy needs at least one TargetSpace!"); + + using TargetSpace = typename std::tuple_element<0, std::tuple<TargetSpaces...> >::type; + static_assert( (std::is_same<TargetSpace, RigidBodyMotion<RT,gridDim>>::value) + or (std::is_same<TargetSpace, RealTuple<RT,gridDim>>::value), "The first TargetSpace of LocalIntegralEnergy needs to be RigidBodyMotion or RealTuple!" ); + + const std::vector<TargetSpace>& localSolution = std::get<0>(std::forward_as_tuple(localSolutions...)); + + using namespace Dune::Indices; + // powerBasis: grab the finite element of the first child + const auto& localFiniteElement = localView.tree().child(_0,0).finiteElement(); + const auto& element = localView.element(); + + RT energy = 0; + + // store gradients of shape functions and base functions + std::vector<FieldMatrix<DT,1,gridDim> > referenceGradients(localFiniteElement.size()); + std::vector<FieldVector<DT,gridDim> > gradients(localFiniteElement.size()); + + int quadOrder = (element.type().isSimplex()) ? localFiniteElement.localBasis().order() + : localFiniteElement.localBasis().order() * gridDim; + + const auto& quad = Dune::QuadratureRules<DT, gridDim>::rule(element.type(), quadOrder); + + for (const auto& qp : quad) + { + const DT integrationElement = element.geometry().integrationElement(qp.position()); + + const auto jacobianInverseTransposed = element.geometry().jacobianInverseTransposed(qp.position()); + + // Global position + auto x = element.geometry().global(qp.position()); + + // Get gradients of shape functions + localFiniteElement.localBasis().evaluateJacobian(qp.position(), referenceGradients); + + // compute gradients of base functions + for (size_t i=0; i<gradients.size(); ++i) + jacobianInverseTransposed.mv(referenceGradients[i][0], gradients[i]); + + // Deformation gradient + FieldMatrix<RT,gridDim,gridDim> deformationGradient(0); + for (size_t i=0; i<gradients.size(); i++) + for (int j=0; j<gridDim; j++) + deformationGradient[j].axpy(localSolution[i][j], gradients[i]); + // Integrate the energy density + energy += qp.weight() * integrationElement * (*localDensity_)(x, deformationGradient); + } + + return energy; + } + +protected: + const std::shared_ptr<Dune::Elasticity::LocalDensity<gridDim,RT,DT>> localDensity_ = nullptr; + +}; + +} // namespace Dune::GFE + +#endif //#ifndef DUNE_GFE_LOCALINTEGRALENERGY_HH diff --git a/dune/gfe/neumannenergy.hh b/dune/gfe/neumannenergy.hh new file mode 100644 index 00000000..dd8f61b1 --- /dev/null +++ b/dune/gfe/neumannenergy.hh @@ -0,0 +1,103 @@ +#ifndef DUNE_GFE_NEUMANNENERGY_HH +#define DUNE_GFE_NEUMANNENERGY_HH + +#include <dune/geometry/quadraturerules.hh> + +#include <dune/fufem/functions/virtualgridfunction.hh> +#include <dune/fufem/boundarypatch.hh> + +#include <dune/elasticity/assemblers/localenergy.hh> + +namespace Dune::GFE { + /** + \brief Assembles the Neumann energy for a single element on the Neumann Boundary using the Neumann Function. + + This class works similarly to the class Dune::Elasticity::NeumannEnergy, where Dune::Elasticity::NeumannEnergy extends + Dune::Elasticity::LocalEnergy and Dune::GFE::NeumannEnergy extends Dune::GFE::LocalEnergy. + */ +template<class Basis, class... TargetSpaces> +class NeumannEnergy + : public Dune::GFE::LocalEnergy<Basis,TargetSpaces...> +{ + using LocalView = typename Basis::LocalView; + using GridView = typename LocalView::GridView; + using DT = typename GridView::Grid::ctype; + using RT = typename Dune::GFE::LocalEnergy<Basis,TargetSpaces...>::RT; + + enum {dim=GridView::dimension}; + +public: + + /** \brief Constructor with a set of material parameters + * \param parameters The material parameters + */ + NeumannEnergy(const std::shared_ptr<BoundaryPatch<GridView>>& neumannBoundary, + std::function<Dune::FieldVector<double,dim>(Dune::FieldVector<DT,dim>)> neumannFunction) + : neumannBoundary_(neumannBoundary), + neumannFunction_(neumannFunction) + {} + + /** \brief Assemble the energy for a single element */ + RT energy(const typename Basis::LocalView& localView, + const std::vector<TargetSpaces>&... localSolutions) const + { + static_assert(sizeof...(TargetSpaces) > 0, "NeumannEnergy needs at least one TargetSpace!"); + + using namespace Dune::Indices; + using TargetSpace = typename std::tuple_element<0, std::tuple<TargetSpaces...> >::type; + const std::vector<TargetSpace>& localSolution = std::get<0>(std::forward_as_tuple(localSolutions...)); + + const auto& localFiniteElement = localView.tree().child(_0,0).finiteElement(); + const auto& element = localView.element(); + + RT energy = 0; + + for (auto&& intersection : intersections(neumannBoundary_->gridView(), element)) { + + if (not neumannBoundary_ or not neumannBoundary_->contains(intersection)) + continue; + + int quadOrder = localFiniteElement.localBasis().order(); + + const auto& quad = Dune::QuadratureRules<DT, dim-1>::rule(intersection.type(), quadOrder); + + for (size_t pt=0; pt<quad.size(); pt++) { + + // Local position of the quadrature point + const Dune::FieldVector<DT,dim>& quadPos = intersection.geometryInInside().global(quad[pt].position()); + + const auto integrationElement = intersection.geometry().integrationElement(quad[pt].position()); + + // The value of the local function + std::vector<Dune::FieldVector<DT,1> > shapeFunctionValues; + localFiniteElement.localBasis().evaluateFunction(quadPos, shapeFunctionValues); + + Dune::FieldVector<RT,dim> value(0); + for (size_t i=0; i<localFiniteElement.size(); i++) + for (int j=0; j<dim; j++) + value[j] += shapeFunctionValues[i] * localSolution[i][j]; + + // Value of the Neumann data at the current position + auto neumannValue = neumannFunction_( intersection.geometry().global(quad[pt].position()) ); + + // Only translational dofs are affected by the Neumann force + for (size_t i=0; i<neumannValue.size(); i++) + energy += (neumannValue[i] * value[i]) * quad[pt].weight() * integrationElement; + + } + + } + + return energy; + } + +private: + /** \brief The Neumann boundary */ + const std::shared_ptr<BoundaryPatch<GridView>> neumannBoundary_; + + /** \brief The function implementing the Neumann data */ + std::function<Dune::FieldVector<double,dim>(Dune::FieldVector<DT,dim>)> neumannFunction_; +}; +} // namespace Dune::GFE + +#endif //#ifndef DUNE_GFE_NEUMANNENERGY_HH -- GitLab