diff --git a/src/scheme/HypoelasticSolver.cpp b/src/scheme/HypoelasticSolver.cpp
index 6036a30f69fce9a6849c46d0f3382fa8b5d8c54e..54b61b70a7d31444afe7347adffd57919a66bbe3 100644
--- a/src/scheme/HypoelasticSolver.cpp
+++ b/src/scheme/HypoelasticSolver.cpp
@@ -63,14 +63,17 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
 {
  private:
   using Rdxd = TinyMatrix<Dimension>;
+  using R3x3 = TinyMatrix<3>;
   using Rd   = TinyVector<Dimension>;
+  using R3   = TinyVector<3>;
 
   using MeshType     = Mesh<Connectivity<Dimension>>;
   using MeshDataType = MeshData<Dimension>;
 
-  using DiscreteScalarFunction = DiscreteFunctionP0<Dimension, const double>;
-  using DiscreteVectorFunction = DiscreteFunctionP0<Dimension, const Rd>;
-  using DiscreteTensorFunction = DiscreteFunctionP0<Dimension, const Rdxd>;
+  using DiscreteScalarFunction   = DiscreteFunctionP0<Dimension, const double>;
+  using DiscreteVectorFunction   = DiscreteFunctionP0<Dimension, const Rd>;
+  using DiscreteTensorFunction   = DiscreteFunctionP0<Dimension, const Rdxd>;
+  using DiscreteTensorFunction3d = DiscreteFunctionP0<Dimension, const R3x3>;
 
   class FixedBoundaryCondition;
   class PressureBoundaryCondition;
@@ -86,6 +89,86 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
 
   using BoundaryConditionList = std::vector<BoundaryCondition>;
 
+  R3x3
+  to3D(const Rdxd tensor) const
+  {
+    R3x3 tensor3d = zero;
+    for (size_t i = 0; i < Dimension; i++) {
+      for (size_t j = 0; j < Dimension; j++) {
+        tensor3d(i, j) = tensor(i, j);
+      }
+    }
+    return tensor3d;
+  }
+
+  R3
+  to3D(const Rd vector) const
+  {
+    R3 vector3d = zero;
+    for (size_t i = 0; i < Dimension; i++) {
+      vector3d[i] = vector[i];
+    }
+    return vector3d;
+  }
+
+  CellValue<const R3x3>
+  to3D(const MeshType& mesh, const CellValue<Rdxd>& tensor) const
+  {
+    CellValue<R3x3> tensor3d{mesh.connectivity()};
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { tensor3d[j] = to3D(tensor[j]); });
+    return tensor3d;
+  }
+
+  CellValue<const R3>
+  to3D(const MeshType& mesh, const CellValue<Rd> vector) const
+  {
+    CellValue<R3> vector3d{mesh.connectivity()};
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { vector3d[j] = to3D(vector[j]); });
+    return vector3d;
+  }
+
+  Rdxd
+  toDimension(const R3x3 tensor3d) const
+  {
+    Rdxd tensor = zero;
+    for (size_t i = 0; i < Dimension; i++) {
+      for (size_t j = 0; j < Dimension; j++) {
+        tensor(i, j) = tensor3d(i, j);
+      }
+    }
+    return tensor;
+  }
+
+  Rd
+  toDimension(const R3 vector3d) const
+  {
+    Rd vector = zero;
+    for (size_t i = 0; i < Dimension; i++) {
+      vector[i] = vector3d[i];
+    }
+    return vector;
+  }
+
+  CellValue<const Rdxd>
+  toDimension(const MeshType& mesh, const CellValue<R3x3>& tensor3d) const
+  {
+    CellValue<Rdxd> tensor{mesh.connectivity()};
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { tensor[j] = toDimension(tensor3d[j]); });
+    return tensor;
+  }
+
+  CellValue<const Rd>
+  toDimension(const MeshType& mesh, const CellValue<R3>& vector3d) const
+  {
+    CellValue<Rd> vector{mesh.connectivity()};
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { vector[j] = to3D(vector3d[j]); });
+    return vector;
+  }
+
   NodeValuePerCell<const Rdxd>
   _computeGlaceAjr(const MeshType& mesh, const DiscreteScalarFunction& rhoaL, const DiscreteScalarFunction& rhoaT) const
   {
@@ -412,15 +495,22 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
       throw NormalError("hypoelastic solver expects P0 functions");
     }
 
-    const MeshType& mesh                 = dynamic_cast<const MeshType&>(*i_mesh);
-    const DiscreteScalarFunction& rho    = rho_v->get<DiscreteScalarFunction>();
-    const DiscreteVectorFunction& u      = u_v->get<DiscreteVectorFunction>();
-    const DiscreteScalarFunction& aL     = aL_v->get<DiscreteScalarFunction>();
-    const DiscreteScalarFunction& aT     = aT_v->get<DiscreteScalarFunction>();
-    const DiscreteTensorFunction& sigmad = sigmad_v->get<DiscreteTensorFunction>();
-    const DiscreteScalarFunction& p      = p_v->get<DiscreteScalarFunction>();
-    const Rdxd I                         = identity;
-    const DiscreteTensorFunction& sigma  = -p * I + sigmad;
+    const MeshType& mesh                   = dynamic_cast<const MeshType&>(*i_mesh);
+    const DiscreteScalarFunction& rho      = rho_v->get<DiscreteScalarFunction>();
+    const DiscreteVectorFunction& u        = u_v->get<DiscreteVectorFunction>();
+    const DiscreteScalarFunction& aL       = aL_v->get<DiscreteScalarFunction>();
+    const DiscreteScalarFunction& aT       = aT_v->get<DiscreteScalarFunction>();
+    const DiscreteTensorFunction3d& sigmad = sigmad_v->get<DiscreteTensorFunction3d>();
+    const DiscreteScalarFunction& p        = p_v->get<DiscreteScalarFunction>();
+    const R3x3 I                           = identity;
+
+    std::shared_ptr<const MeshType> p_mesh = std::dynamic_pointer_cast<const MeshType>(i_mesh);
+
+    CellValue<R3x3> tensor_values3d{mesh.connectivity()};
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { tensor_values3d[j] = -p[j] * I + sigmad[j]; });
+    CellValue<const Rdxd> tensor_values = toDimension(mesh, tensor_values3d);
+    DiscreteTensorFunction sigma(p_mesh, tensor_values);
 
     NodeValuePerCell<const Rdxd> Ajr = this->_computeAjr(solver_type, mesh, rho * aL, rho * aT);
 
@@ -450,7 +540,7 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
                const DiscreteScalarFunction& rho,
                const DiscreteVectorFunction& u,
                const DiscreteScalarFunction& E,
-               const DiscreteTensorFunction& sigmad,
+               const DiscreteTensorFunction3d& sigmad,
                const DiscreteScalarFunction& mu,
                const DiscreteScalarFunction& yieldy,
                const NodeValue<const Rd>& ur,
@@ -475,7 +565,7 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
     CellValue<double> new_rho  = copy(rho.cellValues());
     CellValue<Rd> new_u        = copy(u.cellValues());
     CellValue<double> new_E    = copy(E.cellValues());
-    CellValue<Rdxd> new_sigmad = copy(sigmad.cellValues());
+    CellValue<R3x3> new_sigmad = copy(sigmad.cellValues());
     auto chi                   = [&](const double a, const double b) -> double {
       if ((a >= 0) and (b > 0))
         return 1;
@@ -496,24 +586,33 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
           momentum_fluxes += Fjr(j, R);
           energy_fluxes += dot(Fjr(j, R), ur[r]);
         }
+        R3x3 gradv3d            = to3D(gradv);
         const double eps        = 1.e-16;
-        const Rdxd I            = identity;
+        const R3x3 I            = identity;
         const double norms      = l2Norm(sigmad[j]);
         const double yieldf     = norms - std::sqrt(2. / 3.) * yieldy[j];
-        const Rdxd N            = 1. / (norms + eps) * sigmad[j];
-        const Rdxd D            = 0.5 * (gradv + transpose(gradv));
-        const Rdxd Dd           = D - 1. / Dimension * trace(D) * I;
+        const R3x3 N            = 1. / (norms + eps) * sigmad[j];
+        const R3x3 D            = 0.5 * (gradv3d + transpose(gradv3d));
+        const R3x3 Dd           = D - 1. / 3. * trace(D) * I;
         const double scalarND   = scalarProduct(N, D);
-        const Rdxd Dp           = chi(yieldf, scalarND) * scalarND * N;
-        const Rdxd gradva       = 0.5 * (gradv - transpose(gradv));
-        const Rdxd jaumann      = sigmad[j] * gradva - gradva * sigmad[j];
+        const R3x3 Dp           = chi(yieldf, scalarND) * scalarND * N;
+        const R3x3 gradva       = 0.5 * (gradv3d - transpose(gradv3d));
+        const R3x3 jaumann      = sigmad[j] * gradva - gradva * sigmad[j];
         const double dt_over_Mj = dt / (rho[j] * Vj[j]);
         const double dt_over_Vj = dt / Vj[j];
         new_u[j] += dt_over_Mj * momentum_fluxes;
         new_E[j] += dt_over_Mj * energy_fluxes;
+        // const R3x3 sigmad_tr = sigmad[j] + dt_over_Vj * (2 * mu[j] * Dd - jaumann);
+        // const double normsd  = l2Norm(sigmad_tr);
+        // if (chi(yieldf, scalarND)) {
+        //   new_sigmad[j] = std::sqrt(2. / 3.) * yieldy[j] / (normsd + eps) * sigmad_tr;
+        // } else {
+        //   new_sigmad[j] = sigmad_tr;
+        // }
         new_sigmad[j] += dt_over_Vj * (2 * mu[j] * (Dd - Dp) - jaumann);
         if (trace(new_sigmad[j]) >= 1.e-6) {
-          std::cout << j << " trace " << trace(new_sigmad[j]) << "\n";
+          std::cout << j << " trace " << trace(new_sigmad[j]) << " x-strain " << new_sigmad[j](0, 0) << " y-strain "
+                    << new_sigmad[j](1, 1) << " z-strain " << new_sigmad[j](2, 2) << "\n";
         }
       });
 
@@ -525,7 +624,7 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
     return {new_mesh, std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_rho)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh, new_u)),
             std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh, new_E)),
-            std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction(new_mesh, new_sigmad))};
+            std::make_shared<DiscreteFunctionVariant>(DiscreteTensorFunction3d(new_mesh, new_sigmad))};
   }
 
   std::tuple<std::shared_ptr<const IMesh>,
@@ -552,15 +651,15 @@ class HypoelasticSolverHandler::HypoelasticSolver final : public HypoelasticSolv
       throw NormalError("hypoelastic solver expects P0 functions");
     }
 
-    return this->apply_fluxes(dt,                                       //
-                              dynamic_cast<const MeshType&>(*i_mesh),   //
-                              rho->get<DiscreteScalarFunction>(),       //
-                              u->get<DiscreteVectorFunction>(),         //
-                              E->get<DiscreteScalarFunction>(),         //
-                              sigmad->get<DiscreteTensorFunction>(),    //
-                              mu->get<DiscreteScalarFunction>(),        //
-                              yieldy->get<DiscreteScalarFunction>(),    //
-                              ur->get<NodeValue<const Rd>>(),           //
+    return this->apply_fluxes(dt,                                        //
+                              dynamic_cast<const MeshType&>(*i_mesh),    //
+                              rho->get<DiscreteScalarFunction>(),        //
+                              u->get<DiscreteVectorFunction>(),          //
+                              E->get<DiscreteScalarFunction>(),          //
+                              sigmad->get<DiscreteTensorFunction3d>(),   //
+                              mu->get<DiscreteScalarFunction>(),         //
+                              yieldy->get<DiscreteScalarFunction>(),     //
+                              ur->get<NodeValue<const Rd>>(),            //
                               Fjr->get<NodeValuePerCell<const Rd>>());
   }