diff --git a/src/common/eigen_tools.hh b/src/common/eigen_tools.hh
index d7c03e8..6a01d09 100644
--- a/src/common/eigen_tools.hh
+++ b/src/common/eigen_tools.hh
@@ -1,205 +1,307 @@
 /**
  * @file   eigen_tools.hh
  *
  * @author Till Junge <till.junge@epfl.ch>
  *
  * @date   20 Sep 2017
  *
  * @brief  small tools to be used with Eigen
  *
  * Copyright © 2017 Till Junge
  *
  * µSpectre is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3, or (at
  * your option) any later version.
  *
  * µSpectre is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with GNU Emacs; see the file COPYING. If not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 #ifndef EIGEN_TOOLS_H
 #define EIGEN_TOOLS_H
 
 #include "common/common.hh"
 
 #include <unsupported/Eigen/CXX11/Tensor>
+#include <Eigen/Dense>
 
 #include <utility>
 #include <type_traits>
 
 namespace muSpectre {
 
   /* ---------------------------------------------------------------------- */
   namespace internal {
 
     //! Creates a Eigen::Sizes type for a Tensor defined by an order and dim
     template <Dim_t order, Dim_t dim, Dim_t... dims>
     struct SizesByOrderHelper {
       //! type to use
       using Sizes = typename SizesByOrderHelper<order-1, dim, dim, dims...>::Sizes;
     };
     //! Creates a Eigen::Sizes type for a Tensor defined by an order and dim
     template <Dim_t dim, Dim_t... dims>
     struct SizesByOrderHelper<0, dim, dims...> {
       //! type to use
       using Sizes = Eigen::Sizes<dims...>;
     };
 
   }  // internal
 
   //! Creates a Eigen::Sizes type for a Tensor defined by an order and dim
   template <Dim_t order, Dim_t dim>
   struct SizesByOrder {
     static_assert(order > 0, "works only for order greater than zero");
     //! `Eigen::Sizes`
     using Sizes = typename
       internal::SizesByOrderHelper<order-1, dim, dim>::Sizes;
   };
 
   /* ---------------------------------------------------------------------- */
   namespace internal {
 
     /* ---------------------------------------------------------------------- */
     //! Call a passed lambda with the unpacked sizes as arguments
     template<Dim_t order, typename Fun_t, Dim_t dim, Dim_t ... args>
     struct CallSizesHelper {
       //! applies the call
       static decltype(auto) call(Fun_t && fun) {
         static_assert(order > 0, "can't handle empty sizes b)");
         return CallSizesHelper<order-1, Fun_t, dim, dim, args...>::call
           (fun);
       }
     };
 
     /* ---------------------------------------------------------------------- */
     template<typename Fun_t, Dim_t dim, Dim_t ... args>
     //! Call a passed lambda with the unpacked sizes as arguments
     struct CallSizesHelper<0, Fun_t, dim, args...> {
       //! applies the call
       static decltype(auto) call(Fun_t && fun) {
         return fun(args...);
       }
     };
 
   }  // internal
 
   /**
    * takes a lambda and calls it with the proper `Eigen::Sizes`
    * unpacked as arguments. Is used to call constructors of a
    * `Eigen::Tensor` or map thereof in a context where the spatial
    * dimension is templated
    */
   template<Dim_t order, Dim_t dim, typename Fun_t>
   inline decltype(auto) call_sizes(Fun_t && fun) {
     static_assert(order > 1, "can't handle empty sizes");
     return internal::CallSizesHelper<order-1, Fun_t, dim, dim>::
       call(std::forward<Fun_t>(fun));
   }
 
 
   //compile-time square root
   static constexpr Dim_t ct_sqrt(Dim_t res, Dim_t l, Dim_t r){
     if(l == r){
       return r;
     } else {
       const auto mid = (r + l) / 2;
 
       if(mid * mid >= res){
         return ct_sqrt(res, l, mid);
       } else {
         return ct_sqrt(res, mid + 1, r);
       }
     }
   }
 
   static constexpr Dim_t ct_sqrt(Dim_t res){
     return ct_sqrt(res, 1, res);
   }
 
   namespace EigenCheck {
     /**
      * Structure to determine whether an expression can be evaluated
      * into a `Eigen::Matrix`, `Eigen::Array`, etc. and which helps
      * determine compile-time size
      */
     template <class Derived>
     struct is_matrix {
       //! raw type for testing
       using T = std::remove_reference_t<Derived>;
       //! evaluated test
       constexpr static bool value{std::is_same<typename Eigen::internal::traits<T>::XprKind,
                                                Eigen::MatrixXpr>::value};
     };
 
     /**
      * Helper class to check whether an `Eigen::Array` or
      * `Eigen::Matrix` is statically sized
      */
     template <class Derived>
     struct is_fixed {
       //! raw type for testing
       using T = std::remove_reference_t<Derived>;
       //! evaluated test
       constexpr static bool value{T::SizeAtCompileTime != Eigen::Dynamic};
     };
 
     /**
      * Helper class to check whether an `Eigen::Array` or `Eigen::Matrix` is a
      * static-size and square.
      */
     template <class Derived>
     struct is_square {
       //! raw type for testing
       using T = std::remove_reference_t<Derived>;
       //! true if the object is square and statically sized
       constexpr static bool value{
         (T::RowsAtCompileTime == T::ColsAtCompileTime) &&
           is_fixed<T>::value};
 
     };
 
     /**
      * computes the dimension from a second order tensor represented
      * square matrix or array
      */
     template <class Derived>
     struct tensor_dim {
       //! raw type for testing
       using T = std::remove_reference_t<Derived>;
       static_assert(is_matrix<T>::value, "The type of t is not understood as an Eigen::Matrix");
       static_assert(is_square<T>::value, "t's matrix isn't square");
       //! evaluated dimension
       constexpr static Dim_t value{T::RowsAtCompileTime};
     };
 
     //! computes the dimension from a fourth order tensor represented
     //! by a square matrix
     template <class Derived>
     struct tensor_4_dim {
       //! raw type for testing
       using T = std::remove_reference_t<Derived>;
       static_assert(is_matrix<T>::value, "The type of t is not understood as an Eigen::Matrix");
       static_assert(is_square<T>::value, "t's matrix isn't square");
       //! evaluated dimension
       constexpr static Dim_t value{ct_sqrt(T::RowsAtCompileTime)};
       static_assert(value*value == T::RowsAtCompileTime,
                     "This is not a fourth-order tensor mapped on a square "
                     "matrix");
     };
 
   };
 
 
+  namespace log_comp {
+    template <Dim_t dim>
+    using Mat_t = Eigen::Matrix<Real, dim, dim>;
+    template <Dim_t dim>
+    using Vec_t = Eigen::Matrix<Real, dim, 1>;
+
+    //! This is a static implementation of the explicit determination
+    //! of log(Tensor) following Jog, C.S. J Elasticity (2008) 93:
+    //! 141. https://doi.org/10.1007/s10659-008-9169-x
+    /* ---------------------------------------------------------------------- */
+    template <Dim_t dim, Dim_t i, Dim_t j = dim-1>
+    struct Proj {
+      static inline decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        static_assert(dim > 0, "only works for positive dimensions");
+        return 1./(eigs(i) -eigs(j))*(T-eigs(j)*Mat_t<dim>::Identity()) * Proj<dim, i, j-1>::compute(eigs, T);
+      }
+    };
+
+    // catch the case when there's nothing to do
+    template <Dim_t dim, Dim_t other>
+    struct Proj<dim,other,other> {
+      static inline decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        static_assert(dim > 0, "only works for positive dimensions");
+        return Proj<dim, other, other-1>::compute(eigs, T);
+      }
+    };
+
+    // catch the normal tail case
+    template <Dim_t dim, Dim_t i>
+    struct Proj<dim,i,0> {
+      static constexpr Dim_t j{0};
+      static inline decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        static_assert(dim > 0, "only works for positive dimensions");
+        return 1./(eigs(i) -eigs(j))*(T-eigs(j)*Mat_t<dim>::Identity());
+      }
+    };
+
+    // catch the tail case when the last dimension is i
+    template <Dim_t dim>
+    struct Proj<dim,0,1> {
+      static constexpr Dim_t i{0};
+      static constexpr Dim_t j{1};
+      static inline decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        static_assert(dim > 0, "only works for positive dimensions");
+        return 1./(eigs(i) -eigs(j))*(T-eigs(j)*Mat_t<dim>::Identity());
+      }
+    };
+
+    template <>
+    struct Proj<1, 0, 0> {
+      static constexpr Dim_t dim{1};
+      static constexpr Dim_t i{0};
+      static constexpr Dim_t j{0};
+
+      static inline decltype(auto) compute(const Vec_t<dim> & /*eigs*/, const Mat_t<dim> & /*T*/) {
+        return Mat_t<dim>::Identity();
+      }
+    };
+
+
+    template <Dim_t dim, Dim_t i>
+    inline decltype(auto) P(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+      return Proj<dim, i>::compute(eigs, T);
+    }
+
+    /* ---------------------------------------------------------------------- */
+    template  <Dim_t dim, Dim_t i = dim-1>
+    struct Summand {
+      static inline  decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        return std::log(eigs(i))*P<dim, i>(eigs, T) + Summand<dim, i-1>::compute(eigs, T);
+      }
+    };
+
+    template  <Dim_t dim>
+    struct Summand <dim, 0>{
+      static constexpr Dim_t i{0};
+      static inline  decltype(auto) compute(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+        return std::log(eigs(i))*P<dim, i>(eigs, T);
+      }
+    };
+
+    template <Dim_t dim>
+    inline decltype(auto) Sum(const Vec_t<dim> & eigs, const Mat_t<dim> & T) {
+      return Summand<dim>::compute(eigs, T);
+    }
+
+
+  }  // log_comp
+
+  /**
+   * computes the matrix logarithm efficiently for dim=1, 2, or 3 for
+   * a diagonizable tensor. For larger tensors, better use the direct
+   * eigenvalue/vector computation
+   */
+  template <Dim_t dim>
+  inline decltype(auto) logm(const log_comp::Mat_t<dim>& mat) {
+    using Mat = log_comp::Mat_t<dim>;
+    Eigen::SelfAdjointEigenSolver<Mat> Solver{};
+    Solver.computeDirect(mat, Eigen::EigenvaluesOnly);
+    return Mat{log_comp::Sum(Solver.eigenvalues(), mat)};
+  }
 
 }  // muSpectre
 
 
 #endif /* EIGEN_TOOLS_H */
diff --git a/src/materials/materials_toolbox.hh b/src/materials/materials_toolbox.hh
index 9fde2e1..403b681 100644
--- a/src/materials/materials_toolbox.hh
+++ b/src/materials/materials_toolbox.hh
@@ -1,393 +1,444 @@
 /**
  * @file   materials_toolbox.hh
  *
  * @author Till Junge <till.junge@epfl.ch>
  *
  * @date   02 Nov 2017
  *
  * @brief  collection of common continuum mechanics tools
  *
  * Copyright © 2017 Till Junge
  *
  * µSpectre is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3, or (at
  * your option) any later version.
  *
  * µSpectre is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with GNU Emacs; see the file COPYING. If not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 #ifndef MATERIALS_TOOLBOX_H
 #define MATERIALS_TOOLBOX_H
 
 #include "common/common.hh"
 #include "common/tensor_algebra.hh"
 #include "common/eigen_tools.hh"
 #include "common/T4_map_proxy.hh"
 
 #include <Eigen/Dense>
+#include <unsupported/Eigen/MatrixFunctions>
 
 #include <exception>
 #include <sstream>
 #include <iostream>
 #include <tuple>
 #include <type_traits>
 
 namespace muSpectre {
 
   namespace MatTB {
     /**
      * thrown when generic materials-related runtime errors occur
      * (mostly continuum mechanics problems)
      */
     class MaterialsToolboxError:public std::runtime_error{
     public:
       //! constructor
       explicit MaterialsToolboxError(const std::string& what)
         :std::runtime_error(what){}
       //! constructor
       explicit MaterialsToolboxError(const char * what)
         :std::runtime_error(what){}
     };
 
 
     /* ---------------------------------------------------------------------- */
     /**
      * Flag used to designate whether the material should compute both stress
      * and tangent moduli or only stress
      */
     enum class NeedTangent {
       yes, //!< compute both stress and tangent moduli
       no   //!< compute only stress
     };
 
     /**
      * struct used to determine the exact type of a tuple of references obtained
      * when a bunch of iterators over fiel_maps are dereferenced and their
      * results are concatenated into a tuple
      */
     template <class... T>
     struct ReferenceTuple {
       //! use this type
       using type = std::tuple<typename T::reference ...>;
     };
 
     /**
      * specialisation for tuples
      */
     //template <>
     template <class... T>
     struct ReferenceTuple<std::tuple<T...>> {
       //! use this type
       using type = typename ReferenceTuple<T...>::type;
     };
 
     /**
      * helper type for ReferenceTuple
      */
     template <class... T>
     using ReferenceTuple_t = typename ReferenceTuple<T...>::type;
 
     /* ---------------------------------------------------------------------- */
     namespace internal {
 
       /** Structure for functions returning one strain measure as a
        *  function of another
        **/
       template <StrainMeasure In, StrainMeasure Out = In>
       struct ConvertStrain {
         static_assert((In == StrainMeasure::Gradient) ||
                       (In == StrainMeasure::Infinitesimal),
                       "This situation makes me suspect that you are not using "
                       "MatTb as intended. Disable this assert only if you are "
                       "sure about what you are doing.");
 
         //! returns the converted strain
         template <class Strain_t>
         inline static decltype(auto)
         compute(Strain_t&& input) {
           // transparent case, in which no conversion is required:
           // just a perfect forwarding
           static_assert
             ((In == Out),
              "This particular strain conversion is not implemented");
           return std::forward<Strain_t>(input);
         }
       };
 
       /* ---------------------------------------------------------------------- */
       /** Specialisation for getting Green-Lagrange strain from the
           transformation gradient
+          E = ¹/₂ (C - I) = ¹/₂ (Fᵀ·F - I)
       **/
       template <>
       struct ConvertStrain<StrainMeasure::Gradient, StrainMeasure::GreenLagrange> {
 
         //! returns the converted strain
         template <class Strain_t>
         inline static decltype(auto)
         compute(Strain_t&& F) {
           return .5*(F.transpose()*F - Strain_t::PlainObject::Identity());
         }
       };
 
+      /* ---------------------------------------------------------------------- */
+      /** Specialisation for getting Left Cauchy-Green strain from the
+          transformation gradient
+          B = F·Fᵀ = V²
+      **/
+      template <>
+      struct ConvertStrain<StrainMeasure::Gradient, StrainMeasure::LCauchyGreen> {
+
+        //! returns the converted strain
+        template <class Strain_t>
+        inline static decltype(auto)
+        compute(Strain_t&& F) {
+          return F*F.transpose();
+        }
+      };
+
+      /* ---------------------------------------------------------------------- */
+      /** Specialisation for getting Right Cauchy-Green strain from the
+          transformation gradient
+          C = Fᵀ·F = U²
+      **/
+      template <>
+      struct ConvertStrain<StrainMeasure::Gradient, StrainMeasure::RCauchyGreen> {
+
+        //! returns the converted strain
+        template <class Strain_t>
+        inline static decltype(auto)
+        compute(Strain_t&& F) {
+          return F.transpose()*F;
+        }
+      };
+
+      /* ---------------------------------------------------------------------- */
+      /** Specialisation for getting logarithmic (Hencky) strain from the
+          transformation gradient
+          E₀ = ¹/₂ ln C = ¹/₂ ln (Fᵀ·F)
+      **/
+      template <>
+      struct ConvertStrain<StrainMeasure::Gradient, StrainMeasure::Log> {
+
+        //! returns the converted strain
+        template <class Strain_t>
+        inline static decltype(auto)
+        compute(Strain_t&& F) {
+          constexpr Dim_t dim{EigenCheck::tensor_dim<Strain_t>::value};
+          return (.5*logm(Eigen::Matrix<Real, dim, dim>{F.transpose()*F})).eval();
+        }
+      };
+
     }  // internal
 
     /* ---------------------------------------------------------------------- */
     //! set of functions returning one strain measure as a function of
     //! another
     template <StrainMeasure In, StrainMeasure Out,
               class Strain_t>
     decltype(auto) convert_strain(Strain_t && strain) {
       return internal::ConvertStrain<In, Out>::compute(std::move(strain));
     };
 
 
 
     /* ---------------------------------------------------------------------- */
     namespace internal {
 
       /** Structure for functions returning PK1 stress from other stress measures
        **/
       template <Dim_t Dim,
                 StressMeasure StressM,
                 StrainMeasure StrainM>
       struct PK1_stress {
 
         //! returns the converted stress
         template <class Strain_t, class Stress_t>
         inline static decltype(auto)
         compute(Strain_t && /*strain*/, Stress_t && /*stress*/) {
           // the following test always fails to generate a compile-time error
           static_assert((StressM == StressMeasure::Cauchy) &&
                         (StressM == StressMeasure::PK1),
                         "The requested Stress conversion is not implemented. "
                         "You either made a programming mistake or need to "
                         "implement it as a specialisation of this function. "
                         "See PK2stress<PK1,T1, T2> for an example.");
         }
 
         //! returns the converted stress and stiffness
         template <class Strain_t, class Stress_t, class Tangent_t>
         inline static decltype(auto)
         compute(Strain_t && /*strain*/, Stress_t && /*stress*/,
                 Tangent_t && /*stiffness*/) {
           // the following test always fails to generate a compile-time error
           static_assert((StressM == StressMeasure::Cauchy) &&
                         (StressM == StressMeasure::PK1),
                         "The requested Stress conversion is not implemented. "
                         "You either made a programming mistake or need to "
                         "implement it as a specialisation of this function. "
                         "See PK2stress<PK1,T1, T2> for an example.");
         }
       };
 
       /* ---------------------------------------------------------------------- */
       /** Specialisation for the transparent case, where we already
           have PK1 stress
        **/
       template <Dim_t Dim, StrainMeasure StrainM>
       struct PK1_stress<Dim, StressMeasure::PK1, StrainM>:
         public PK1_stress<Dim, StressMeasure::no_stress_,
                           StrainMeasure::no_strain_> {
 
         //! returns the converted stress
         template <class Strain_t, class Stress_t>
         inline static decltype(auto)
         compute(Strain_t && /*dummy*/, Stress_t && P) {
           return std::forward<Stress_t>(P);
         }
       };
 
       /* ---------------------------------------------------------------------- */
       /** Specialisation for the transparent case, where we already have PK1
           stress *and* stiffness is given with respect to the transformation
           gradient
        **/
       template <Dim_t Dim>
       struct PK1_stress<Dim, StressMeasure::PK1, StrainMeasure::Gradient>:
         public PK1_stress<Dim, StressMeasure::PK1,
                           StrainMeasure::no_strain_> {
 
         //! base class
         using Parent = PK1_stress<Dim, StressMeasure::PK1,
                                   StrainMeasure::no_strain_>;
         using Parent::compute;
 
         //! returns the converted stress and stiffness
         template <class Strain_t, class Stress_t, class Tangent_t>
         inline static decltype(auto)
         compute(Strain_t && /*dummy*/, Stress_t && P, Tangent_t && K) {
           return std::make_tuple(std::forward<Stress_t>(P),
                                  std::forward<Tangent_t>(K));
         }
       };
 
       /* ---------------------------------------------------------------------- */
       /**
        * Specialisation for the case where we get material stress (PK2)
        */
       template <Dim_t Dim, StrainMeasure StrainM>
       struct PK1_stress<Dim, StressMeasure::PK2, StrainM>:
         public PK1_stress<Dim, StressMeasure::no_stress_,
                           StrainMeasure::no_strain_> {
 
         //! returns the converted stress
         template <class Strain_t, class Stress_t>
         inline static decltype(auto)
         compute(Strain_t && F, Stress_t && S) {
           return F*S;
         }
       };
 
       /* ---------------------------------------------------------------------- */
       /**
        * Specialisation for the case where we get material stress (PK2) derived
        * with respect to Green-Lagrange strain
        */
       template <Dim_t Dim>
       struct PK1_stress<Dim, StressMeasure::PK2, StrainMeasure::GreenLagrange>:
         public PK1_stress<Dim, StressMeasure::PK2,
                           StrainMeasure::no_strain_> {
         //! base class
         using Parent = PK1_stress<Dim, StressMeasure::PK2,
                                   StrainMeasure::no_strain_>;
         using Parent::compute;
 
         //! returns the converted stress and stiffness
         template <class Strain_t, class Stress_t, class Tangent_t>
         inline static decltype(auto)
         compute(Strain_t && F, Stress_t && S, Tangent_t && C) {
           using T4 = typename std::remove_reference_t<Tangent_t>::PlainObject;
           using Tmap = T4MatMap<Real, Dim>;
           T4 K;
           Tmap Kmap{K.data()};
           K.setZero();
 
           for (int i = 0; i < Dim; ++i) {
             for (int m = 0; m < Dim; ++m) {
               for (int n = 0; n < Dim; ++n) {
                 get(Kmap,i,m,i,n) += S(m,n);
                 for (int j = 0; j < Dim; ++j) {
                   for (int r = 0; r < Dim; ++r) {
                     for (int s = 0; s < Dim; ++s) {
                       get(Kmap,i,m,j,n) += F(i,r)*get(C,r,m,n,s)*(F(j,s));
                     }
                   }
                 }
               }
             }
           }
           auto && P = compute(std::forward<Strain_t>(F),
                               std::forward<Stress_t>(S));
           return std::make_tuple(std::move(P), std::move(K));
         }
       };
 
     }  // internal
     /* ---------------------------------------------------------------------- */
     //! set of functions returning an expression for PK2 stress based on
     template <StressMeasure StressM, StrainMeasure StrainM,
               class Stress_t, class Strain_t>
     decltype(auto) PK1_stress(Strain_t && strain, Stress_t && stress) {
       constexpr Dim_t dim{EigenCheck::tensor_dim<Strain_t>::value};
       static_assert((dim == EigenCheck::tensor_dim<Stress_t>::value),
                     "Stress and strain tensors have differing dimensions");
       return internal::PK1_stress<dim, StressM, StrainM>::compute
         (std::forward<Strain_t>(strain),
          std::forward<Stress_t>(stress));
     };
 
     /* ---------------------------------------------------------------------- */
     //! set of functions returning an expression for PK2 stress based on
     template <StressMeasure StressM, StrainMeasure StrainM,
               class Stress_t, class Strain_t, class Tangent_t>
     decltype(auto) PK1_stress(Strain_t  && strain,
                               Stress_t  && stress,
                               Tangent_t && tangent) {
       constexpr Dim_t dim{EigenCheck::tensor_dim<Strain_t>::value};
       static_assert((dim == EigenCheck::tensor_dim<Stress_t>::value),
                     "Stress and strain tensors have differing dimensions");
       static_assert((dim == EigenCheck::tensor_4_dim<Tangent_t>::value),
                     "Stress and tangent tensors have differing dimensions");
 
       return internal::PK1_stress<dim, StressM, StrainM>::compute
         (std::forward<Strain_t>(strain),
          std::forward<Stress_t>(stress),
          std::forward<Tangent_t>(tangent));
     };
 
     //! static inline implementation of Hooke's law
     template <Dim_t Dim, class Strain_t, class Tangent_t>
     struct Hooke {
       /**
        * compute Lamé's first constant
        * @param young: Young's modulus
        * @param poisson: Poisson's ratio
        */
       inline static constexpr Real
       compute_lambda(const Real & young, const Real & poisson) {
         return young*poisson/((1+poisson)*(1-2*poisson));
       }
 
       /**
        * compute Lamé's second constant (i.e., shear modulus)
        * @param young: Young's modulus
        * @param poisson: Poisson's ratio
        */
       inline static constexpr Real
       compute_mu(const Real & young, const Real & poisson) {
         return young/(2*(1+poisson));
       }
 
       /**
        * compute the stiffness tensor
        * @param lambda: Lamé's first constant
        * @param mu: Lamé's second constant (i.e., shear modulus)
        */
       inline static Eigen::TensorFixedSize<Real, Eigen::Sizes<Dim, Dim, Dim, Dim>>
       compute_C(const Real & lambda, const Real & mu) {
         return lambda*Tensors::outer<Dim>(Tensors::I2<Dim>(),Tensors::I2<Dim>()) +
           2*mu*Tensors::I4S<Dim>();
       }
 
       /**
        * return stress
        * @param lambda: First Lamé's constant
        * @param mu: Second Lamé's constant (i.e. shear modulus)
        * @param E: Green-Lagrange or small strain tensor
        */
       template <class s_t>
       inline static decltype(auto)
       evaluate_stress(const Real & lambda, const Real & mu, s_t && E) {
         return E.trace()*lambda * Strain_t::Identity() + 2*mu*E;
       }
 
       /**
        * return stress and tangent stiffness
        * @param lambda: First Lamé's constant
        * @param mu: Second Lamé's constant (i.e. shear modulus)
        * @param E: Green-Lagrange or small strain tensor
        */
       template <class s_t>
       inline static decltype(auto)
       evaluate_stress(const Real & lambda, const Real & mu,
                       Tangent_t && C, s_t && E) {
         return std::make_tuple
           (std::move(evaluate_stress(lambda, mu, std::move(E))),
            std::move(C));
       }
     };
 
   }  // MatTB
 
 }  // muSpectre
 
 #endif /* MATERIALS_TOOLBOX_H */
diff --git a/tests/test_materials_toolbox.cc b/tests/test_materials_toolbox.cc
index 1a88e33..72e3bd2 100644
--- a/tests/test_materials_toolbox.cc
+++ b/tests/test_materials_toolbox.cc
@@ -1,173 +1,206 @@
 /**
  * @file   test_materials_toolbox.cc
  *
  * @author Till Junge <till.junge@altermail.ch>
  *
  * @date   05 Nov 2017
  *
  * @brief  Tests for the materials toolbox
  *
  * Copyright © 2017 Till Junge
  *
  * µSpectre is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License as
  * published by the Free Software Foundation, either version 3, or (at
  * your option) any later version.
  *
  * µSpectre is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with GNU Emacs; see the file COPYING. If not, write to the
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
 
 #include <Eigen/Dense>
 
 #include "tests.hh"
 #include "materials/materials_toolbox.hh"
 #include "common/T4_map_proxy.hh"
 #include "common/tensor_algebra.hh"
 #include "tests/test_goodies.hh"
 
 
 namespace muSpectre {
 
   BOOST_AUTO_TEST_SUITE(materials_toolbox)
 
   BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_strain_conversion, Fix,
                                    testGoodies::dimlist, Fix){
     constexpr Dim_t dim{Fix::dim};
     using T2 = Eigen::Matrix<Real, dim, dim>;
 
-    T2 F;
-    F.setRandom();
-    auto Eref = .5*(F.transpose()*F-T2::Identity());
+    T2 F{(T2::Random() -.5*T2::Ones())/20 + T2::Identity()};
 
-    auto E_tb = MatTB::convert_strain<StrainMeasure::Gradient,
+    // checking Green-Lagrange
+    T2 Eref = .5*(F.transpose()*F-T2::Identity());
+
+    T2 E_tb = MatTB::convert_strain<StrainMeasure::Gradient,
                                       StrainMeasure::GreenLagrange>
       (Eigen::Map<Eigen::Matrix<Real, dim, dim>>(F.data()));
 
-    auto error = (Eref-E_tb).norm();
+    Real error = (Eref-E_tb).norm();
+    BOOST_CHECK_LT(error, tol);
+
+    // checking Left Cauchy-Green
+    Eref = F*F.transpose();
+    E_tb = MatTB::convert_strain<StrainMeasure::Gradient,
+                                 StrainMeasure::LCauchyGreen>(F);
+
+    error = (Eref-E_tb).norm();
+    BOOST_CHECK_LT(error, tol);
+
+    // checking Right Cauchy-Green
+    Eref = F.transpose()*F;
+    E_tb = MatTB::convert_strain<StrainMeasure::Gradient,
+                                 StrainMeasure::RCauchyGreen>(F);
+
+    error = (Eref-E_tb).norm();
+    BOOST_CHECK_LT(error, tol);
+
+    // checking Hencky (logarithmic) strain
+    Eref = F.transpose()*F;
+    Eigen::SelfAdjointEigenSolver<T2> EigSolv(Eref);
+    Eref.setZero();
+    for (size_t i{0}; i < dim; ++i) {
+      auto && vec = EigSolv.eigenvectors().col(i);
+      auto && val = EigSolv.eigenvalues()(i);
+      Eref += .5*std::log(val) * vec*vec.transpose();
+    }
+
+    E_tb = MatTB::convert_strain<StrainMeasure::Gradient,
+                                 StrainMeasure::Log>(F);
+
+    error = (Eref-E_tb).norm();
     BOOST_CHECK_LT(error, tol);
 
     auto F_tb = MatTB::convert_strain<StrainMeasure::Gradient, StrainMeasure::Gradient>(F);
 
     error = (F-F_tb).norm();
     BOOST_CHECK_LT(error, tol);
   }
 
   BOOST_FIXTURE_TEST_CASE_TEMPLATE(dumb_tensor_mult_test, Fix,
                                    testGoodies::dimlist, Fix) {
     constexpr Dim_t dim{Fix::dim};
     using T4 = T4Mat<Real, dim>;
     T4 A,B, R1, R2;
     A.setRandom();
     B.setRandom();
     R1 = A*B;
     R2.setZero();
     for (Dim_t i = 0; i < dim; ++i) {
       for (Dim_t j = 0; j < dim; ++j) {
         for (Dim_t a = 0; a < dim; ++a) {
           for (Dim_t b = 0; b < dim; ++b) {
             for (Dim_t k = 0; k < dim; ++k) {
               for (Dim_t l = 0; l < dim; ++l) {
                 get(R2,i,j,k,l) += get(A, i,j,a,b)*get(B, a,b, k,l);
               }
             }
           }
         }
       }
     }
     auto error{(R1-R2).norm()};
     BOOST_CHECK_LT(error, tol);
   }
 
   BOOST_FIXTURE_TEST_CASE_TEMPLATE(test_PK1_stress, Fix,
                                    testGoodies::dimlist, Fix) {
     using namespace Matrices;
     constexpr Dim_t dim{Fix::dim};
     using T2 = Eigen::Matrix<Real, dim, dim>;
     using T4 = T4Mat<Real, dim>;
     testGoodies::RandRange<Real> rng;
     T2 F=T2::Identity()*2 ;
     //F.setRandom();
     T2 E_tb = MatTB::convert_strain<StrainMeasure::Gradient, StrainMeasure::GreenLagrange>
       (Eigen::Map<Eigen::Matrix<Real, dim, dim>>(F.data()));
     Real lambda = 3;//rng.randval(1, 2);
     Real mu = 4;//rng.randval(1,2);
     T4 J = Itrac<dim>();
     T2 I = I2<dim>();
     T4 I4 = Isymm<dim>();
     T4 C = lambda*J + 2*mu*I4;
     T2 S = tensmult(C, E_tb);
     T2 Sref = lambda*E_tb.trace()*I + 2*mu*E_tb;
 
     auto error{(Sref-S).norm()};
     BOOST_CHECK_LT(error, tol);
 
     T4 K = outer_under(I,S) + outer_under(F,I)*C*outer_under(F.transpose(),I);
 
     // See Curnier, 2000, "Méthodes numériques en mécanique des solides", p 252
     T4 Kref;
     Real Fkrkr = (F.array()*F.array()).sum();
     T2 Fkmkn = F.transpose()*F;
     T2 Fisjs = F*F.transpose();
     Kref.setZero();
     for (Dim_t i = 0; i < dim; ++i) {
       for (Dim_t j = 0; j < dim; ++j) {
         for (Dim_t m = 0; m < dim; ++m) {
           for (Dim_t n = 0; n < dim; ++n) {
             get(Kref, i, m, j, n) =
               (lambda*((Fkrkr-dim)/2 * I(i,j)*I(m,n) + F(i,m)*F(j,n)) +
                mu * (I(i,j)*Fkmkn(m,n) + Fisjs(i,j)*I(m,n) -
                      I(i,j) *I(m,n) + F(i,n)*F(j,m)));
           }
         }
       }
     }
     error = (Kref-K).norm();
     BOOST_CHECK_LT(error, tol);
 
     T2 P = MatTB::PK1_stress<StressMeasure::PK2, StrainMeasure::GreenLagrange>(F, S);
     T2 Pref = F*S;
     error = (P-Pref).norm();
     BOOST_CHECK_LT(error, tol);
 
     auto && stress_tgt = MatTB::PK1_stress<StressMeasure::PK2, StrainMeasure::GreenLagrange>(F, S, C);
     T2 P_t = std::move(std::get<0>(stress_tgt));
     T4 K_t = std::move(std::get<1>(stress_tgt));
     error = (P_t-Pref).norm();
     BOOST_CHECK_LT(error, tol);
 
     error = (K_t-Kref).norm();
     BOOST_CHECK_LT(error, tol);
 
     auto && stress_tgt_trivial =
       MatTB::PK1_stress<StressMeasure::PK1, StrainMeasure::Gradient>(F, P, K);
     T2 P_u = std::move(std::get<0>(stress_tgt_trivial));
     T4 K_u = std::move(std::get<1>(stress_tgt_trivial));
 
     error = (P_u-Pref).norm();
     BOOST_CHECK_LT(error, tol);
 
     error = (K_u-Kref).norm();
     BOOST_CHECK_LT(error, tol);
 
     T2 P_g;
     T4 K_g;
     std::tie(P_g, K_g) = testGoodies::objective_hooke_explicit(lambda, mu, F);
 
     error = (P_g-Pref).norm();
     BOOST_CHECK_LT(error, tol);
 
     error = (K_g-Kref).norm();
     BOOST_CHECK_LT(error, tol);
   }
 
   BOOST_AUTO_TEST_SUITE_END();
 
 }  // muSpectre