Skip to content
Snippets Groups Projects
localintegralstiffnesstest.cc 25.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • #include <config.h>
    
    // Includes for the ADOL-C automatic differentiation library
    // Need to come before (almost) all others.
    #include <adolc/adouble.h>
    #include <dune/fufem/utilities/adolcnamespaceinjections.hh>
    
    
    #include <dune/common/parametertree.hh>
    #include <dune/common/parallel/mpihelper.hh>
    #include <dune/common/test/testsuite.hh>
    #include <dune/common/timer.hh>
    
    #include <dune/grid/uggrid.hh>
    #include <dune/grid/utility/structuredgridfactory.hh>
    
    #include <dune/functions/functionspacebases/lagrangebasis.hh>
    #include <dune/functions/functionspacebases/compositebasis.hh>
    #include <dune/functions/functionspacebases/powerbasis.hh>
    #include <dune/functions/functionspacebases/interpolate.hh>
    #include <dune/functions/functionspacebases/subspacebasis.hh>
    
    #include <dune/gfe/localprojectedfefunction.hh>
    #include <dune/gfe/assemblers/localgeodesicfeadolcstiffness.hh>
    #include <dune/gfe/assemblers/mixedgfeassembler.hh>
    #include <dune/gfe/assemblers/sumenergy.hh>
    #include <dune/gfe/assemblers/geodesicfeassembler.hh>
    #include <dune/gfe/assemblers/localintegralenergy.hh>
    #include <dune/gfe/assemblers/localintegralstiffness.hh>
    #include <dune/gfe/densities/localdensity.hh>
    #include <dune/gfe/densities/bulkcosseratdensity.hh>
    #include <dune/gfe/densities/harmonicdensity.hh>
    #include <dune/gfe/spaces/realtuple.hh>
    
    // grid dimension
    const int dim = 3;
    
    using namespace Dune;
    using namespace Dune::Indices;
    using namespace Functions::BasisFactory;
    
    
    enum InterpolationType {Geodesic, ProjectionBased, Nonconforming};
    
    
    
    template <class GridView, InterpolationType interpolationType>
    int testHarmonicMapIntoSphere(TestSuite& test, const GridView& gridView)
    {
      using TargetSpace = UnitVector<double,dim>;
    
      // Finite element order
      const int order = 1;
    
      const static int blocksize = TargetSpace::TangentVector::dimension;
    
      using Correction = BlockVector<TargetSpace::TangentVector>;
      using Matrix = BCRSMatrix<FieldMatrix<double, blocksize, blocksize> >;
    
      //////////////////////////////////////////////////////////////////////////////////
      //  Construct all needed function space bases
      //////////////////////////////////////////////////////////////////////////////////
    
      auto tangentBasis = makeBasis(
        gridView,
        power<blocksize>(
          lagrange<order>()
          )
        );
    
      auto valueBasis = makeBasis(gridView, power<TargetSpace::CoordinateType::dimension>(lagrange<order>()));
    
      /////////////////////////////////////////////////////////////////////////
      //  Construct the configuration where to assemble the tangent problem
      /////////////////////////////////////////////////////////////////////////
    
      using CoefficientVector = std::vector<TargetSpace>;
      CoefficientVector x(tangentBasis.size());
    
      BlockVector<FieldVector<double,dim> > initialIterate;
      Functions::interpolate(valueBasis, initialIterate, [](FieldVector<double,dim> x)
                             -> FieldVector<double,dim> {
        // Interpret x[0] and x[1] as spherical coordinates
        auto phi = x[0];
        auto theta = x[1];
        return {sin(phi)*cos(theta), sin(phi)*sin(theta), cos(theta)};
      });
      for (size_t i = 0; i < x.size(); i++)
        x[i] = initialIterate[i];
    
      using ATargetSpace = typename TargetSpace::rebind<adouble>::other;
    
      // Select which type of geometric interpolation to use
      // TODO: Use the tangent basis here!
      using FEBasis = Functions::LagrangeBasis<GridView,order>;
      Functions::LagrangeBasis<GridView,order> feBasis(gridView);
    
      //////////////////////////////////////////////////////////////
      //  Set up the two assemblers
      //////////////////////////////////////////////////////////////
    
      std::shared_ptr<GeodesicFEAssembler<FEBasis,TargetSpace> > assemblerADOLC;
      std::shared_ptr<LocalGeodesicFEStiffness<FEBasis,TargetSpace> > localIntegralStiffness;
    
      using LocalCoordinate = typename GridView::template Codim<0>::Geometry::LocalCoordinate;
    
      auto harmonicDensity = std::make_shared<GFE::HarmonicDensity<LocalCoordinate,TargetSpace> >();
      auto harmonicDensityA = std::make_shared<GFE::HarmonicDensity<LocalCoordinate,ATargetSpace> >();
    
    
      if constexpr (interpolationType==Geodesic)
      {
        std::cout << "Using geodesic interpolation" << std::endl;
        using LocalInterpolationRule = LocalGeodesicFEFunction<dim,
            typename GridView::ctype,
            decltype(feBasis.localView().tree().finiteElement()),
            TargetSpace>;
    
        using ALocalInterpolationRule = LocalGeodesicFEFunction<dim,
            typename GridView::ctype,
            decltype(feBasis.localView().tree().finiteElement()),
            ATargetSpace>;
    
        // Assemble using the old assembler
    
        auto energy = std::make_shared<GFE::LocalIntegralEnergy<FEBasis, ALocalInterpolationRule,ATargetSpace> >(harmonicDensityA);
    
    
        auto localGFEADOLCStiffness = std::make_shared<LocalGeodesicFEADOLCStiffness<FEBasis,TargetSpace> >(energy);
        assemblerADOLC = std::make_shared<GeodesicFEAssembler<FEBasis,TargetSpace> >(feBasis, localGFEADOLCStiffness);
    
        // Assemble using the new assembler
        localIntegralStiffness = std::make_shared<GFE::LocalIntegralStiffness<FEBasis,LocalInterpolationRule,TargetSpace> >(harmonicDensity);
      }
      else
      {
    
        if (interpolationType==ProjectionBased)
          std::cout << "Using projection-based interpolation" << std::endl;
        else
          std::cout << "Using nonconforming interpolation" << std::endl;
    
    
        using LocalInterpolationRule = GFE::LocalProjectedFEFunction<dim,
            typename GridView::ctype,
            decltype(feBasis.localView().tree().finiteElement()),
    
            TargetSpace, interpolationType!=Nonconforming>;
    
    
        using ALocalInterpolationRule = GFE::LocalProjectedFEFunction<dim,
            typename GridView::ctype,
            decltype(feBasis.localView().tree().finiteElement()),
    
            ATargetSpace, interpolationType!=Nonconforming>;
    
    
        // Assemble using the old assembler
    
        auto energy = std::make_shared<GFE::LocalIntegralEnergy<FEBasis, ALocalInterpolationRule,ATargetSpace> >(harmonicDensityA);
    
    
        auto localGFEADOLCStiffness = std::make_shared<LocalGeodesicFEADOLCStiffness<FEBasis,TargetSpace> >(energy);
        assemblerADOLC = std::make_shared<GeodesicFEAssembler<FEBasis,TargetSpace> >(feBasis, localGFEADOLCStiffness);
    
        // Assemble using the new assembler
        localIntegralStiffness = std::make_shared<GFE::LocalIntegralStiffness<FEBasis,LocalInterpolationRule,TargetSpace> >(harmonicDensity);
      }
    
      // TODO: The assembler should really get the tangent basis.
      auto assemblerIntegralStiffness = std::make_shared<GeodesicFEAssembler<FEBasis,TargetSpace> >(feBasis, localIntegralStiffness);
    
      //////////////////////////////////////////////////////////////
      //  Assemble
      //////////////////////////////////////////////////////////////
    
      Correction gradient;
      Matrix hesseMatrix;
    
      Correction gradientSmart;
      Matrix hesseMatrixSmart;
    
      Timer assemblerTimer;
      assemblerADOLC->assembleGradientAndHessian(x, gradient, hesseMatrix,true);
      std::cout << "assemblerTimer took: " << assemblerTimer.elapsed() << std::endl;
    
      Timer assemblerSmartTimer;
      assemblerIntegralStiffness->assembleGradientAndHessian(x, gradientSmart, hesseMatrixSmart,true);
      std::cout << "assemblerSmartTimer took: " << assemblerSmartTimer.elapsed() << std::endl;
    
      //////////////////////////////////////////////////////////////
      //  Compare the results
      //////////////////////////////////////////////////////////////
    
      double gradientInfinityNorm = gradient.infinity_norm();
      double matrixFrobeniusNorm = hesseMatrix.frobenius_norm();
    
      double gradientSmartInfinityNorm = gradientSmart.infinity_norm();
      double matrixSmartFrobeniusNorm = hesseMatrixSmart.frobenius_norm();
    
      if (std::isnan(gradientInfinityNorm) || std::isnan(gradientSmartInfinityNorm) || std::abs(gradientInfinityNorm - gradientSmartInfinityNorm)/gradientInfinityNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Gradient max norm from localADOLCStiffness is " << gradientInfinityNorm
                  << ", from LocalIntegralStiffness is " << gradientSmartInfinityNorm << " :(" << std::endl;
        return 1;
      }
    
      if (std::isnan(matrixFrobeniusNorm) || std::isnan(matrixSmartFrobeniusNorm) || std::abs(matrixFrobeniusNorm - matrixSmartFrobeniusNorm)/matrixFrobeniusNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Matrix norm from localADOLCStiffness is " << matrixFrobeniusNorm
                  << ", from LocalIntegralStiffness is " << matrixSmartFrobeniusNorm << " :(" << std::endl;
        return 1;
      }
    
      // TODO: Use rangeFor
      for (auto rowIt = hesseMatrixSmart.begin(); rowIt != hesseMatrixSmart.end(); ++rowIt)
        for (auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
          for (size_t k = 0; k < blocksize; k++)
            for (size_t l = 0; l < blocksize; l++)
              if (std::abs((*colIt)[k][l]) > 1e-6 and std::abs(hesseMatrix[rowIt.index()][colIt.index()][k][l]) > 1e-6
                  and std::abs((*colIt)[k][l] - hesseMatrix[rowIt.index()][colIt.index()][k][l])/(*colIt)[k][l] > 1e-4) {
                std::cerr << "Matrix: Index " << " " << rowIt.index() << " " << colIt.index() << " " << k << " " << l  << " is wrong: " << hesseMatrix[rowIt.index()][colIt.index()][k][l] << " - " << (*colIt)[k][l] << std::endl;
                return 1;
              }
    
      return 0;
    }
    
    
    
    template <class GridView, InterpolationType interpolationType>
    int testCosseratBulkModel(TestSuite& test, const GridView& gridView)
    {
      // Order of the approximation spaces
      // Deliberately test with different orders, to find more bugs
      const int deformationOrder = 2;
      const int rotationOrder = 1;
    
      const static int deformationBlocksize = RealTuple<double,dim>::TangentVector::dimension;
      const static int orientationBlocksize = Rotation<double,dim>::TangentVector::dimension;
    
      using CorrectionType0 = BlockVector<FieldVector<double, deformationBlocksize> >;
      using CorrectionType1 = BlockVector<FieldVector<double, orientationBlocksize> >;
    
      using MatrixType00 = BCRSMatrix<FieldMatrix<double, deformationBlocksize, deformationBlocksize> >;
      using MatrixType01 = BCRSMatrix<FieldMatrix<double, deformationBlocksize, orientationBlocksize> >;
      using MatrixType10 = BCRSMatrix<FieldMatrix<double, orientationBlocksize, deformationBlocksize> >;
      using MatrixType11 = BCRSMatrix<FieldMatrix<double, orientationBlocksize, orientationBlocksize> >;
    
      using MatrixType = MultiTypeBlockMatrix<MultiTypeBlockVector<MatrixType00,MatrixType01>,
          MultiTypeBlockVector<MatrixType10,MatrixType11> >;
    
      //////////////////////////////////////////////////////////////////////////////////
      //  Construct all needed function space bases
      //////////////////////////////////////////////////////////////////////////////////
    
      const int dimRotation = Rotation<double,dim>::embeddedDim;
      auto compositeBasis = makeBasis(
        gridView,
        composite(
          power<dim>(
            lagrange<deformationOrder>()
            ),
          power<dimRotation>(
            lagrange<rotationOrder>()
            )
          ));
    
      using CompositeBasis = decltype(compositeBasis);
    
      /////////////////////////////////////////////////////////////////////////
      //  Construct the configuration where to assemble the tangent problem
      /////////////////////////////////////////////////////////////////////////
    
      using CoefficientVector = TupleVector<std::vector<RealTuple<double,dim> >,std::vector<Rotation<double,dim> > >;
      CoefficientVector x;
      x[_0].resize(compositeBasis.size({0}));
      x[_1].resize(compositeBasis.size({1}));
    
      MultiTypeBlockVector<BlockVector<FieldVector<double,dim> >,BlockVector<FieldVector<double,dimRotation> > > initialIterate;
      Functions::interpolate(Functions::subspaceBasis(compositeBasis, _0), initialIterate, [](FieldVector<double,dim> x){
        FieldVector<double,dim> y = {0.5*x[0]*x[0], 0.5*x[1] + 0.2*x[0], 4*std::abs(std::sin(x[2]))};
        return y;
      });
      for (size_t i = 0; i < x[_0].size(); i++)
        x[_0][i] = initialIterate[_0][i];
    
      Functions::interpolate(Functions::subspaceBasis(compositeBasis, _1), initialIterate, [](FieldVector<double,dim> x){
        // Just any rotation field, for testing
        FieldVector<double,4> y = {0.5*x[0], 0.7*x[1], 1.0*std::abs(std::sin(x[2])), 1.0 - 0.2*x[0]*x[1]};
        return y;
      });
      for (size_t i = 0; i < x[_1].size(); i++)
        x[_1][i] = Rotation<double,dim>(initialIterate[_1][i]);
    
      // Set of material parameters
      ParameterTree parameters;
      parameters["thickness"] = "0.1";
      parameters["mu"] = "1";
      parameters["lambda"] = "1";
      parameters["mu_c"] = "1";
      parameters["L_c"] = "0.1";
    
      parameters["curvatureType"] = "wryness";
    
      parameters["q"] = "2";
      parameters["kappa"] = "1";
      parameters["b1"] = "1";
      parameters["b2"] = "1";
      parameters["b3"] = "1";
    
      using RigidBodyMotion  = GFE::ProductManifold<RealTuple<double,dim>, Rotation<double,dim> >;
      using ARigidBodyMotion = GFE::ProductManifold<RealTuple<adouble,dim>, Rotation<adouble,dim> >;
    
      using LocalCoordinate = typename GridView::template Codim<0>::Geometry::LocalCoordinate;
    
      auto bulkCosseratDensity = std::make_shared<GFE::BulkCosseratDensity<LocalCoordinate,double> >(parameters);
      auto aBulkCosseratDensity = std::make_shared<GFE::BulkCosseratDensity<LocalCoordinate,adouble> >(parameters);
    
      // Select which type of geometric interpolation to use
      using DeformationFEBasis = Functions::LagrangeBasis<GridView,deformationOrder>;
      using OrientationFEBasis = Functions::LagrangeBasis<GridView,rotationOrder>;
    
      DeformationFEBasis deformationFEBasis(gridView);
      OrientationFEBasis orientationFEBasis(gridView);
    
      //////////////////////////////////////////////////////////////
      //  Set up the two assemblers
      //////////////////////////////////////////////////////////////
    
      std::shared_ptr<MixedGFEAssembler<CompositeBasis,RigidBodyMotion> > assemblerADOLC;
      std::shared_ptr<LocalGeodesicFEStiffness<CompositeBasis,RigidBodyMotion> > localIntegralStiffness;
    
      if constexpr (interpolationType==Geodesic)
      {
        std::cout << "Using geodesic interpolation" << std::endl;
    
        using LocalDeformationInterpolationRule = LocalGeodesicFEFunction<dim, typename GridView::ctype, decltype(deformationFEBasis.localView().tree().finiteElement()), RealTuple<double,dim> >;
        using LocalOrientationInterpolationRule = LocalGeodesicFEFunction<dim, typename GridView::ctype, decltype(orientationFEBasis.localView().tree().finiteElement()), Rotation<double,dim> >;
    
        using LocalInterpolationRule = std::tuple<LocalDeformationInterpolationRule,LocalOrientationInterpolationRule>;
    
        using ALocalDeformationInterpolationRule = LocalGeodesicFEFunction<dim, typename GridView::ctype, decltype(deformationFEBasis.localView().tree().finiteElement()), RealTuple<adouble,dim> >;
        using ALocalOrientationInterpolationRule = LocalGeodesicFEFunction<dim, typename GridView::ctype, decltype(orientationFEBasis.localView().tree().finiteElement()), Rotation<adouble,dim> >;
    
        using ALocalInterpolationRule = std::tuple<ALocalDeformationInterpolationRule,ALocalOrientationInterpolationRule>;
    
        // Assemble using the ADOL-C assembler
        auto energy = std::make_shared<GFE::LocalIntegralEnergy<CompositeBasis, ALocalInterpolationRule,ARigidBodyMotion> >(aBulkCosseratDensity);
    
        auto localGFEADOLCStiffness = std::make_shared<LocalGeodesicFEADOLCStiffness<CompositeBasis,RigidBodyMotion> >(energy);
    
        assemblerADOLC = std::make_shared<MixedGFEAssembler<CompositeBasis,RigidBodyMotion> >(compositeBasis, localGFEADOLCStiffness);
    
        // Assemble using the new assembler
    
        localIntegralStiffness = std::make_shared<GFE::LocalIntegralStiffness<CompositeBasis,LocalInterpolationRule,RigidBodyMotion> >(bulkCosseratDensity);
    
      }
      else
      {
        std::cout << "Using projection-based interpolation" << std::endl;
    
        using LocalDeformationInterpolationRule = GFE::LocalProjectedFEFunction<dim, typename GridView::ctype, decltype(deformationFEBasis.localView().tree().finiteElement()), RealTuple<double,dim> >;
        using LocalOrientationInterpolationRule = GFE::LocalProjectedFEFunction<dim, typename GridView::ctype, decltype(orientationFEBasis.localView().tree().finiteElement()), Rotation<double,dim> >;
    
        using LocalInterpolationRule = std::tuple<LocalDeformationInterpolationRule,LocalOrientationInterpolationRule>;
    
        using ALocalDeformationInterpolationRule = GFE::LocalProjectedFEFunction<dim, typename GridView::ctype, decltype(deformationFEBasis.localView().tree().finiteElement()), RealTuple<adouble,dim> >;
        using ALocalOrientationInterpolationRule = GFE::LocalProjectedFEFunction<dim, typename GridView::ctype, decltype(orientationFEBasis.localView().tree().finiteElement()), Rotation<adouble,dim> >;
    
        using ALocalInterpolationRule = std::tuple<ALocalDeformationInterpolationRule,ALocalOrientationInterpolationRule>;
    
        // Assemble using the ADOL-C assembler
        auto energy = std::make_shared<GFE::LocalIntegralEnergy<CompositeBasis, ALocalInterpolationRule,ARigidBodyMotion> >(aBulkCosseratDensity);
    
        auto localGFEADOLCStiffness = std::make_shared<LocalGeodesicFEADOLCStiffness<CompositeBasis,RigidBodyMotion> >(energy);
    
        assemblerADOLC = std::make_shared<MixedGFEAssembler<CompositeBasis,RigidBodyMotion> >(compositeBasis, localGFEADOLCStiffness);
    
        // Assemble using the new assembler
    
        localIntegralStiffness = std::make_shared<GFE::LocalIntegralStiffness<CompositeBasis,LocalInterpolationRule,RigidBodyMotion> >(bulkCosseratDensity);
    
      }
    
      MixedGFEAssembler<CompositeBasis,RigidBodyMotion> mixedAssemblerSmart(compositeBasis,
                                                                            localIntegralStiffness);
    
      //////////////////////////////////////////////////////////////
      //  Assemble
      //////////////////////////////////////////////////////////////
    
      CorrectionType0 gradient0;
      CorrectionType1 gradient1;
      MatrixType hesseMatrix;
    
      CorrectionType0 gradientSmart0;
      CorrectionType1 gradientSmart1;
      MatrixType hesseMatrixSmart;
    
      Timer assemblerTimer;
      assemblerADOLC->assembleGradientAndHessian(x[_0], x[_1], gradient0, gradient1, hesseMatrix,true);
      std::cout << "assemblerTimer took: " << assemblerTimer.elapsed() << std::endl;
    
      Timer assemblerSmartTimer;
      mixedAssemblerSmart.assembleGradientAndHessian(x[_0], x[_1], gradientSmart0, gradientSmart1, hesseMatrixSmart,true);
      std::cout << "assemblerSmartTimer took: " << assemblerSmartTimer.elapsed() << std::endl;
    
      //////////////////////////////////////////////////////////////
      //  Compare the results
      //////////////////////////////////////////////////////////////
    
      double gradient0InfinityNorm = gradient0.infinity_norm();
      double gradient1InfinityNorm = gradient1.infinity_norm();
      double matrix00FrobeniusNorm = hesseMatrix[_0][_0].frobenius_norm();
      double matrix01FrobeniusNorm = hesseMatrix[_0][_1].frobenius_norm();
      double matrix10FrobeniusNorm = hesseMatrix[_1][_0].frobenius_norm();
      double matrix11FrobeniusNorm = hesseMatrix[_1][_1].frobenius_norm();
    
      double gradientSmart0InfinityNorm = gradientSmart0.infinity_norm();
      double gradientSmart1InfinityNorm = gradientSmart1.infinity_norm();
      double matrixSmart00FrobeniusNorm = hesseMatrixSmart[_0][_0].frobenius_norm();
      double matrixSmart01FrobeniusNorm = hesseMatrixSmart[_0][_1].frobenius_norm();
      double matrixSmart10FrobeniusNorm = hesseMatrixSmart[_1][_0].frobenius_norm();
      double matrixSmart11FrobeniusNorm = hesseMatrixSmart[_1][_1].frobenius_norm();
    
      if (std::isnan(gradient0InfinityNorm) || std::isnan(gradientSmart0InfinityNorm) || std::abs(gradient0InfinityNorm - gradientSmart0InfinityNorm)/gradient0InfinityNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Gradient (deformation part) max norm from localADOLCStiffness is " << gradient0InfinityNorm << ", from localADOLCIntegralStiffness is " << gradientSmart0InfinityNorm << " :(" << std::endl;
        return 1;
      }
    
      if (std::isnan(gradient1InfinityNorm) || std::isnan(gradientSmart1InfinityNorm) || std::abs(gradient1InfinityNorm - gradientSmart1InfinityNorm)/gradient1InfinityNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Gradient (orientation part) max norm from localADOLCStiffness is " << gradient1InfinityNorm << ", from localADOLCIntegralStiffness is " << gradientSmart1InfinityNorm << " :(" << std::endl;
        return 1;
      }
    
      if (std::isnan(matrix00FrobeniusNorm) || std::isnan(matrixSmart00FrobeniusNorm) || std::abs(matrix00FrobeniusNorm - matrixSmart00FrobeniusNorm)/matrix00FrobeniusNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Matrix00 norm from localADOLCStiffness is " << matrix00FrobeniusNorm << ", from localADOLCIntegralStiffness is " << matrixSmart00FrobeniusNorm << " :(" << std::endl;
        return 1;
      }
    
      for (auto rowIt = hesseMatrixSmart[_0][_0].begin(); rowIt != hesseMatrixSmart[_0][_0].end(); ++rowIt)
        for (auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
          for (size_t k = 0; k < deformationBlocksize; k++)
            for (size_t l = 0; l < deformationBlocksize; l++)
              if (std::abs((*colIt)[k][l]) > 1e-6 and std::abs(hesseMatrix[_0][_0][rowIt.index()][colIt.index()][k][l]) > 1e-6
                  and std::abs((*colIt)[k][l] - hesseMatrix[_0][_0][rowIt.index()][colIt.index()][k][l])/(*colIt)[k][l] > 1e-4) {
                std::cerr << "Matrix00: Index " << " " << rowIt.index() << " " << colIt.index() << " " << k << " " << l  << " is wrong: " << hesseMatrix[_0][_0][rowIt.index()][colIt.index()][k][l] << " - " << (*colIt)[k][l] << std::endl;
                return 1;
              }
    
      if (std::isnan(matrix01FrobeniusNorm) || std::isnan(matrixSmart01FrobeniusNorm) || std::abs(matrix01FrobeniusNorm - matrixSmart01FrobeniusNorm)/matrix01FrobeniusNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Matrix01 norm from localADOLCStiffness is " << matrix01FrobeniusNorm << ", from localADOLCIntegralStiffness is " << matrixSmart01FrobeniusNorm << " :(" << std::endl;
        return 1;
      }
    
      for (auto rowIt = hesseMatrixSmart[_0][_1].begin(); rowIt != hesseMatrixSmart[_0][_1].end(); ++rowIt)
        for (auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
          for (size_t k = 0; k < deformationBlocksize; k++)
            for (size_t l = 0; l < deformationBlocksize; l++)
              if (std::abs((*colIt)[k][l]) > 1e-6 and std::abs(hesseMatrix[_0][_1][rowIt.index()][colIt.index()][k][l]) > 1e-6
                  and std::abs((*colIt)[k][l] - hesseMatrix[_0][_1][rowIt.index()][colIt.index()][k][l])/(*colIt)[k][l] > 1e-4) {
                std::cerr << "Matrix01 Index " << " " << rowIt.index() << " " << colIt.index() << " " << k << " " << l  << " is wrong: " << hesseMatrix[_0][_1][rowIt.index()][colIt.index()][k][l] << " - " << (*colIt)[k][l] << std::endl;
                return 1;
              }
    
      if (std::isnan(matrix10FrobeniusNorm) || std::isnan(matrixSmart10FrobeniusNorm) || std::abs(matrix10FrobeniusNorm - matrixSmart10FrobeniusNorm)/matrix10FrobeniusNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Matrix10 norm from localADOLCStiffness is " << matrix10FrobeniusNorm << ", from localADOLCIntegralStiffness is " << matrixSmart10FrobeniusNorm << " :(" << std::endl;
        return 1;
      }
    
      for (auto rowIt = hesseMatrixSmart[_1][_0].begin(); rowIt != hesseMatrixSmart[_1][_0].end(); ++rowIt)
        for (auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
          for (size_t k = 0; k < deformationBlocksize; k++)
            for (size_t l = 0; l < deformationBlocksize; l++)
              if (std::abs((*colIt)[k][l]) > 1e-6 and std::abs(hesseMatrix[_1][_0][rowIt.index()][colIt.index()][k][l]) > 1e-6
                  and std::abs((*colIt)[k][l] - hesseMatrix[_1][_0][rowIt.index()][colIt.index()][k][l])/(*colIt)[k][l] > 1e-4) {
                std::cerr << "Matrix10 Index " << " " << rowIt.index() << " " << colIt.index() << " " << k << " " << l  << " is wrong: " << hesseMatrix[_1][_0][rowIt.index()][colIt.index()][k][l] << " - " << (*colIt)[k][l] << std::endl;
                return 1;
              }
    
      if (std::isnan(matrix11FrobeniusNorm) || std::isnan(matrixSmart00FrobeniusNorm) || std::abs(matrix11FrobeniusNorm - matrixSmart11FrobeniusNorm)/matrix11FrobeniusNorm > 1e-3)
      {
        std::cerr << std::setprecision(9);
        std::cerr << "Matrix11 norm from localADOLCStiffness is " << matrix11FrobeniusNorm << ", from localADOLCIntegralStiffness is " << matrixSmart11FrobeniusNorm << " :(" << std::endl;
        return 1;
      }
    
      for (auto rowIt = hesseMatrixSmart[_1][_1].begin(); rowIt != hesseMatrixSmart[_1][_1].end(); ++rowIt)
        for (auto colIt = rowIt->begin(); colIt != rowIt->end(); ++colIt)
          for (size_t k = 0; k < deformationBlocksize; k++)
            for (size_t l = 0; l < deformationBlocksize; l++)
              if (std::abs((*colIt)[k][l]) > 1e-6 and std::abs(hesseMatrix[_1][_1][rowIt.index()][colIt.index()][k][l]) > 1e-6
                  and std::abs((*colIt)[k][l] - hesseMatrix[_1][_1][rowIt.index()][colIt.index()][k][l])/(*colIt)[k][l] > 1e-4) {
                std::cerr << "Matrix11 Index " << " " << rowIt.index() << " " << colIt.index() << " " << k << " " << l  << " is wrong: " << hesseMatrix[_1][_1][rowIt.index()][colIt.index()][k][l] << " - " << (*colIt)[k][l] << std::endl;
                return 1;
              }
    
      return 0;
    }
    
    
    int main (int argc, char *argv[])
    {
      MPIHelper::instance(argc, argv);
    
      TestSuite test;
    
      /////////////////////////////////////////
      //   Create the grid
      /////////////////////////////////////////
    
      // Create a grid with 2 elements, one element will get refined to create different element types, the other one stays a cube
      using GridType = UGGrid<dim>;
      auto grid = StructuredGridFactory<GridType>::createCubeGrid({0,0,0}, {1,1,1}, {2,1,1});
    
      //Refine once
      for (auto&& e : elements(grid->leafGridView())) {
        bool refineThisElement = false;
        for (int i = 0; i < e.geometry().corners(); i++) {
          refineThisElement = refineThisElement || (e.geometry().corner(i)[0] > 0.99);
        }
        grid->mark(refineThisElement ? 1 : 0, e);
      }
      grid->adapt();
      grid->loadBalance();
    
      using GridView = GridType::LeafGridView;
      auto gridView = grid->leafGridView();
    
      /////////////////////////////////////////////
      //  Test different energies
      /////////////////////////////////////////////
    
      // TODO: Use test framework
      testHarmonicMapIntoSphere<GridView,Geodesic>(test, gridView);
      testHarmonicMapIntoSphere<GridView,ProjectionBased>(test, gridView);
    
      testHarmonicMapIntoSphere<GridView,Nonconforming>(test, gridView);
    
    
      testCosseratBulkModel<GridView,Geodesic>(test, gridView);
      testCosseratBulkModel<GridView,ProjectionBased>(test, gridView);
    
      return test.exit();
    }