diff --git a/dune/gfe/assemblers/localintegralenergy.hh b/dune/gfe/assemblers/localintegralenergy.hh index 6316fe823fcf46fe411d7e3b3bf7db97575d28cf..b10d519db2b8e18660ed5431e16553d775223676 100644 --- a/dune/gfe/assemblers/localintegralenergy.hh +++ b/dune/gfe/assemblers/localintegralenergy.hh @@ -2,6 +2,7 @@ #define DUNE_GFE_ASSEMBLERS_LOCALINTEGRALENERGY_HH #include <dune/common/fmatrix.hh> +#include <dune/common/version.hh> #include <dune/geometry/quadraturerules.hh> @@ -11,6 +12,34 @@ namespace Dune::GFE { +#if ! DUNE_VERSION_GTE(DUNE_LOCALFUNCTIONS, 2, 10) + namespace Impl + { + template <class Basis> + class LocalFiniteElementFactory + { + public: + static auto get(const typename Basis::LocalView& localView) + -> decltype(localView.tree().child(0).finiteElement()) + { + return localView.tree().child(0).finiteElement(); + } + }; + + /** \brief Specialize for scalar bases, here we cannot call tree().child() */ + template <class GridView, int order> + class LocalFiniteElementFactory<Dune::Functions::LagrangeBasis<GridView,order> > + { + public: + static auto get(const typename Dune::Functions::LagrangeBasis<GridView,order>::LocalView& localView) + -> decltype(localView.tree().finiteElement()) + { + return localView.tree().finiteElement(); + } + }; + } +#endif + /** \brief An energy given as an integral over a density * * \tparam Basis The scalar finite element basis used to construct the interpolation rule @@ -44,9 +73,27 @@ namespace Dune::GFE { { RT energy = 0; - if constexpr (not Impl::LocalEnergyTypes<TargetSpace>::isProductManifold) + if constexpr (Basis::LocalView::Tree::isLeaf || Basis::LocalView::Tree::isPower) { - const auto& localFiniteElement = localView.tree().finiteElement(); +#if DUNE_VERSION_GTE(DUNE_LOCALFUNCTIONS, 2, 10) + // Get an appropriate scalar local finite element, to construct the interpolation rule with + // TODO: This is not a good design, for several reasons: + // * The interpolation rule could want to have state beyond what we know here. + // It should therefore be constructed outside of the LocalIntegralEnergy class + // * I don't really see why Basis should be allowed to be scalar-valued + // to begin with, but a lot of code still currently does that. + auto lfeGetter = [&localView]() + { + if constexpr (Basis::LocalView::Tree::isPower) + return localView.tree().child(0).finiteElement(); + else + return localView.tree().finiteElement(); + }; + + const auto& localFiniteElement = lfeGetter(); +#else + const auto& localFiniteElement = Impl::LocalFiniteElementFactory<Basis>::get(localView); +#endif LocalInterpolationRule localInterpolationRule(localFiniteElement,localConfiguration); int quadOrder = (localFiniteElement.type().isSimplex()) @@ -97,6 +144,11 @@ namespace Dune::GFE { } } } + else + { + // You need a scalar basis or a power basis when calling this method. + std::abort(); + } return energy; } @@ -106,7 +158,7 @@ namespace Dune::GFE { { RT energy = 0; - if constexpr (Impl::LocalEnergyTypes<TargetSpace>::isProductManifold) + if constexpr (Impl::LocalEnergyTypes<TargetSpace>::isProductManifold && Basis::LocalView::Tree::isComposite) { static_assert(TargetSpace::size() == 2, "LocalIntegralEnergy only implemented for product spaces with two factors!"); @@ -177,6 +229,8 @@ namespace Dune::GFE { derivative); } } + else + DUNE_THROW(Dune::NotImplemented, "Non-product manifold or non-composite basis"); return energy; } diff --git a/test/localadolcstiffnesstest.cc b/test/localadolcstiffnesstest.cc index 2cd55096f12f9d347cbd5e45b62939032f921b20..b8cefbd4d6d5ee9601d6b4133e528df4b818f1bd 100644 --- a/test/localadolcstiffnesstest.cc +++ b/test/localadolcstiffnesstest.cc @@ -37,11 +37,11 @@ typedef double FDType; #include <dune/functions/functionspacebases/interpolate.hh> #include <dune/functions/functionspacebases/powerbasis.hh> -#include <dune/gfe/assemblers/localgeodesicfestiffness.hh> #include <dune/gfe/localgeodesicfefunction.hh> -#include <dune/gfe/assemblers/cosseratenergystiffness.hh> +#include <dune/gfe/assemblers/localintegralenergy.hh> #include <dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh> #include <dune/gfe/assemblers/localgeodesicfefdstiffness.hh> +#include <dune/gfe/densities/planarcosseratshelldensity.hh> #include <dune/gfe/spaces/productmanifold.hh> #include <dune/gfe/spaces/realtuple.hh> #include <dune/gfe/spaces/rotation.hh> @@ -104,12 +104,25 @@ int main (int argc, char *argv[]) try typedef GridType::LeafGridView GridView; GridView gridView = grid.leafGridView(); + /////////////////////////////////////////////// + // Construct the basis for the tangent spaces + /////////////////////////////////////////////// typedef Functions::LagrangeBasis<GridView,1> FEBasis; FEBasis feBasis(gridView); - // ///////////////////////////////////////// - // Read Dirichlet values - // ///////////////////////////////////////// + using namespace Functions::BasisFactory; + + const int dimRotation = Rotation<double,3>::TangentVector::dimension; + + auto tangentBasis = makeBasis( + gridView, + power<3+dimRotation>( + lagrange<1>() + ) + ); + + using TangentBasis = decltype(tangentBasis); + // ////////////////////////// // Initial iterate @@ -139,7 +152,6 @@ int main (int argc, char *argv[]) try }; std::vector<FieldVector<double,3> > v; - using namespace Functions::BasisFactory; auto powerBasis = makeBasis( gridView, @@ -165,29 +177,45 @@ int main (int argc, char *argv[]) try materialParameters["L_c"] = "1"; materialParameters["q"] = "2"; materialParameters["kappa"] = "1"; - materialParameters["b1"] = "1"; - materialParameters["b2"] = "1"; - materialParameters["b3"] = "1"; - /////////////////////////////////////////////////////////////////////// - // Assemblers for the Riemannian derivatives - /////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + // Assembler using ADOL-C + ////////////////////////////////////////////////////// + + // The 'active' target spaces, i.e., the number type is replaced by adouble + using ATargetSpace = typename TargetSpace::template rebind<adouble>::other; - // Assembler using ADOL-C - auto cosseratLocalEnergy = std::make_shared<CosseratEnergyLocalStiffness<FEBasis, 3,adouble> >(materialParameters); + // Select geometric finite element interpolation method + using AInterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, ATargetSpace>; - LocalGeodesicFEADOLCStiffness<FEBasis, - TargetSpace> localGFEADOLCStiffness(cosseratLocalEnergy); + auto activeDensity = std::make_shared<GFE::PlanarCosseratShellDensity<GridType::Codim<0>::Entity::Geometry::LocalCoordinate, adouble> >(materialParameters); - // Assembler using finite differences - CosseratEnergyLocalStiffness<FEBasis, 3,FDType> - cosseratEnergyFDLocalStiffness(materialParameters); - LocalGeodesicFEFDStiffness<FEBasis, + auto activeCosseratLocalEnergy = std::make_shared<GFE::LocalIntegralEnergy<TangentBasis,AInterpolationRule,ATargetSpace> >(activeDensity); + + // The actual assembler + LocalGeodesicFEADOLCStiffness<TangentBasis, + TargetSpace> localGFEADOLCStiffness(activeCosseratLocalEnergy); + + ////////////////////////////////////////////////////// + // Assembler using finite differences + ////////////////////////////////////////////////////// + + // Select geometric finite element interpolation method + using InterpolationRule = LocalGeodesicFEFunction<dim, double, FEBasis::LocalView::Tree::FiniteElement, TargetSpace>; + + auto cosseratDensity = std::make_shared<GFE::PlanarCosseratShellDensity<GridType::Codim<0>::Entity::Geometry::LocalCoordinate, double> >(materialParameters); + + auto cosseratLocalEnergy = std::make_shared<GFE::LocalIntegralEnergy<TangentBasis,InterpolationRule,TargetSpace> >(cosseratDensity); + + // The actual assembler + LocalGeodesicFEFDStiffness<TangentBasis, TargetSpace, - FDType> localGFEFDStiffness(&cosseratEnergyFDLocalStiffness); + FDType> localGFEFDStiffness(cosseratLocalEnergy.get()); - // Compute and compare matrices + //////////////////////////////////////////////////////// + // Compute and compare tangent matrices + //////////////////////////////////////////////////////// for (const auto& element : Dune::elements(gridView)) { std::cout << " ++++ element " << gridView.indexSet().index(element) << " ++++" << std::endl; @@ -195,6 +223,9 @@ int main (int argc, char *argv[]) try auto localView = feBasis.localView(); localView.bind(element); + auto tangentLocalView = tangentBasis.localView(); + tangentLocalView.bind(element); + const int numOfBaseFct = localView.size(); // Extract local configuration @@ -210,12 +241,12 @@ int main (int argc, char *argv[]) try Matrix<double> localRiemannianADHessian; Matrix<double> localRiemannianFDHessian; - localGFEADOLCStiffness.assembleGradientAndHessian(localView, + localGFEADOLCStiffness.assembleGradientAndHessian(tangentLocalView, localSolution, localRiemannianADGradient, localRiemannianADHessian); - localGFEFDStiffness.assembleGradientAndHessian(localView, + localGFEFDStiffness.assembleGradientAndHessian(tangentLocalView, localSolution, localRiemannianFDGradient, localRiemannianFDHessian);