Skip to content
Snippets Groups Projects
nonplanarcosseratenergytest.cc 7.67 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include "config.h"
    
    
    #include <dune/foamgrid/foamgrid.hh>
    
    #include <dune/geometry/type.hh>
    #include <dune/geometry/quadraturerules.hh>
    
    #include <dune/functions/functionspacebases/interpolate.hh>
    #include <dune/functions/functionspacebases/lagrangebasis.hh>
    #include <dune/functions/functionspacebases/powerbasis.hh>
    
    #include <dune/gfe/cosseratvtkwriter.hh>
    
    #include <dune/gfe/assemblers/nonplanarcosseratshellenergy.hh>
    
    #include <dune/gfe/spaces/productmanifold.hh>
    #include <dune/gfe/spaces/realtuple.hh>
    #include <dune/gfe/spaces/rotation.hh>
    
    
    #include "multiindex.hh"
    #include "valuefactory.hh"
    
    using namespace Dune;
    
    static const int dim = 2;
    static const int dimworld = 3;
    
    using GridType = FoamGrid<dim,dimworld>;
    
    using TargetSpace = GFE::ProductManifold<RealTuple<double,dimworld>,Rotation<double,dimworld> >;
    
    
    //////////////////////////////////////////////////////////
    //   Make a test grid consisting of a single triangle
    //////////////////////////////////////////////////////////
    
    template <class GridType>
    std::unique_ptr<GridType> makeSingleElementGrid()
    {
    
      constexpr auto triangle = Dune::GeometryTypes::triangle;
      GridFactory<GridType> factory;
    
      //Create a triangle that is not parallel to the planes formed by the coordinate axes
      FieldVector<double,dimworld> vertex0{0,0,0};
      FieldVector<double,dimworld> vertex1{0,1,1};
      FieldVector<double,dimworld> vertex2{1,0,0};
      factory.insertVertex(vertex0);
      factory.insertVertex(vertex1);
      factory.insertVertex(vertex2);
    
      factory.insertElement(triangle, {0,1,2});
    
      return std::unique_ptr<GridType>(factory.createGrid());
    
    }
    
    
    //////////////////////////////////////////////////////////////////////////////////////
    //   Test energy computation for the same grid with different refinement levels
    //////////////////////////////////////////////////////////////////////////////////////
    
    template <class F1, class F2>
    double calculateEnergy(const int numLevels, const F1 referenceConfigurationFunction, const F2 configurationFunction)
    
      ParameterTree materialParameters;
      materialParameters["thickness"] = "0.1";
      materialParameters["mu"] = "3.8462e+05";
      materialParameters["lambda"] = "2.7149e+05";
      materialParameters["mu_c"] = "0";
      materialParameters["L_c"] = "1e-3";
      materialParameters["q"] = "2.5";
      materialParameters["kappa"] = "0.1";
      materialParameters["b1"] = "1";
      materialParameters["b2"] = "1";
      materialParameters["b3"] = "1";
    
      const std::unique_ptr<GridType> grid = makeSingleElementGrid<GridType>();
      grid->globalRefine(numLevels-1);
      GridType::LeafGridView gridView = grid->leafGridView();
    
      using FEBasis = Dune::Functions::LagrangeBasis<typename GridType::LeafGridView,2>;
      FEBasis feBasis(gridView);
    
      using namespace Dune::Functions::BasisFactory;
      using namespace Dune::TypeTree::Indices;
    
      auto deformationPowerBasis = makeBasis(
        gridView,
        power<dimworld>(
          lagrange<2>()
          ));
    
      BlockVector<FieldVector<double,3> > helperVector1(feBasis.size());
      Dune::Functions::interpolate(deformationPowerBasis, helperVector1, referenceConfigurationFunction);
      auto stressFreeConfiguration = Dune::Functions::makeDiscreteGlobalBasisFunction<FieldVector<double,dimworld> >(deformationPowerBasis, helperVector1);
    
      NonplanarCosseratShellEnergy<FEBasis, 3, double, decltype(stressFreeConfiguration)> nonplanarCosseratShellEnergy(materialParameters,
                                                                                                                       &stressFreeConfiguration,
                                                                                                                       nullptr,
                                                                                                                       nullptr,
                                                                                                                       nullptr);
      BlockVector<TargetSpace> sol(feBasis.size());
      TupleVector<std::vector<RealTuple<double,3> >,
          std::vector<Rotation<double,3> > > solTuple;
      solTuple[_0].resize(feBasis.size());
      solTuple[_1].resize(feBasis.size());
    
      BlockVector<FieldVector<double,3> > helperVector2(feBasis.size());
      Dune::Functions::interpolate(deformationPowerBasis, helperVector2, configurationFunction);
      for (std::size_t i = 0; i < feBasis.size(); i++) {
    
        sol[i][_0].globalCoordinates() = helperVector2[i];
    
    
        FieldVector<double,4> idRotation = {0, 0, 0, 1};     //set rotation = Id everywhere
        Rotation<double,dimworld> rotation(idRotation);
        FieldMatrix<double,dimworld,dimworld> rotationMatrix(0);
        rotation.matrix(rotationMatrix);
    
        sol[i][_1].set(rotationMatrix);
        solTuple[_0][i] = sol[i][_0];
        solTuple[_1][i] = sol[i][_1];
    
      }
      CosseratVTKWriter<GridType>::write<FEBasis>(feBasis, solTuple, "configuration_l" + std::to_string(numLevels));
    
      double energy = 0;
      // A view on the FE basis on a single element
      auto localView = feBasis.localView();
      // Loop over all elements
      for (const auto& element : elements(feBasis.gridView(), Dune::Partitions::interior)) {
        localView.bind(element);
        // Number of degrees of freedom on this element
        size_t nDofs = localView.tree().size();
        std::vector<TargetSpace> localSolution(nDofs);
        for (size_t i=0; i<nDofs; i++)
          localSolution[i] = sol[localView.index(i)[0]];
        energy += nonplanarCosseratShellEnergy.energy(localView, localSolution);
      }
      return energy;
    
    }
    
    int main(int argc, char** argv)
    {
    
      MPIHelper::instance(argc, argv);
      auto configurationId = [](FieldVector<double,dimworld> x){
                               return x;
                             };
      auto configurationStretchY = [](FieldVector<double,dimworld> x){
                                     auto out = x;
                                     out[1] *= 2;
                                     return out;
                                   };
    
      auto configurationTwist = [](FieldVector<double,dimworld> x){
                                  auto out = x;
                                  out[1] = x[2];
                                  out[2] = -x[1];
                                  return out;
                                };
    
      auto configurationCurved = [](FieldVector<double,dimworld> x){
                                   auto out = x;
                                   out[1] = x[2];
                                   out[2] = -x[1];
                                   return out;
                                 };
      auto configurationSquare = [](FieldVector<double,dimworld> x){
                                   auto out = x;
                                   out[1] += x[1]*x[1];
                                   return out;
                                 };
    
      auto configurationSin = [](FieldVector<double,dimworld> x){
                                auto out = x;
                                out[2] = sin(x[2]);
                                return out;
                              };
    
      double energyFine = calculateEnergy(2, configurationId, configurationStretchY);
      double energyCoarse = calculateEnergy(1, configurationId, configurationStretchY);
      assert(std::abs(energyFine - energyCoarse) < 1e-3);
    
      double energyForZeroDifference = calculateEnergy(1,configurationId,configurationId);
      assert(std::abs(energyForZeroDifference) < 1e-3);
    
      double energyForZeroDifference2 = calculateEnergy(1,configurationStretchY,configurationStretchY);
      assert(std::abs(energyForZeroDifference2) < 1e-3);
    
      double energyForZeroDifference3 = calculateEnergy(1,configurationTwist,configurationTwist);
      assert(std::abs(energyForZeroDifference3) < 1e-3);
    
      double energyForZeroDifference4 = calculateEnergy(1,configurationSquare,configurationSquare);
      assert(std::abs(energyForZeroDifference4) < 1e-3);
    
      double energyForZeroDifference5 = calculateEnergy(1,configurationSin,configurationSin);
      assert(std::abs(energyForZeroDifference5) < 1e-3);