diff --git a/src/scheme/Order2LocalDtHyperelasticSolver.cpp b/src/scheme/Order2LocalDtHyperelasticSolver.cpp
index ff0c44b0fffcf57b97c71c87970f342984d94942..80f34ce82448f88e4b448ae81058a3a2601b6735 100644
--- a/src/scheme/Order2LocalDtHyperelasticSolver.cpp
+++ b/src/scheme/Order2LocalDtHyperelasticSolver.cpp
@@ -1136,6 +1136,113 @@ class Order2LocalDtHyperelasticSolverHandler::Order2LocalDtHyperelasticSolver fi
                               Fjr->get<NodeValuePerCell<const Rd>>());
   }
 
+  std::tuple<std::shared_ptr<const MeshVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>>
+  order2_apply_fluxes(const double& dt,
+               const MeshType& mesh,
+               const DiscreteScalarFunction& rho,
+               const DiscreteVectorFunction& u,
+               const DiscreteScalarFunction& E,
+               const DiscreteTensorFunction& CG,
+               const DiscreteScalarFunction& rho_app,
+               const DiscreteTensorFunction& CG_app,
+               const NodeValue<const Rd>& ur,
+               const NodeValuePerCell<const Rd>& Fjr) const
+  {
+    const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix();
+
+    if ((mesh.shared_connectivity() != ur.connectivity_ptr()) or
+        (mesh.shared_connectivity() != Fjr.connectivity_ptr())) {
+      throw NormalError("fluxes are not defined on the same connectivity than the mesh");
+    }
+
+    NodeValue<Rd> new_xr = copy(mesh.xr());
+    parallel_for(
+      mesh.numberOfNodes(), PUGS_LAMBDA(NodeId r) { new_xr[r] += dt * ur[r]; });
+
+    std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh.shared_connectivity(), new_xr);
+
+    CellValue<const double> Vj           = MeshDataManager::instance().getMeshData(mesh).Vj();
+    const NodeValuePerCell<const Rd> Cjr = MeshDataManager::instance().getMeshData(mesh).Cjr();
+
+    CellValue<double> new_rho = copy(rho.cellValues());
+    CellValue<Rd> new_u       = copy(u.cellValues());
+    CellValue<double> new_E   = copy(E.cellValues());
+    CellValue<Rdxd> new_CG    = copy(CG.cellValues());
+
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) {
+        const auto& cell_nodes = cell_to_node_matrix[j];
+
+        Rd momentum_fluxes   = zero;
+        double energy_fluxes = 0;
+        Rdxd gradv           = zero;
+        for (size_t R = 0; R < cell_nodes.size(); ++R) {
+          const NodeId r = cell_nodes[R];
+          gradv += tensorProduct(ur[r], Cjr(j, R));
+          momentum_fluxes += Fjr(j, R);
+          energy_fluxes += dot(Fjr(j, R), ur[r]);
+        }
+        const Rdxd cauchy_green_fluxes = rho_app[j] * (gradv * CG_app[j] + CG_app[j] * transpose(gradv));
+        const double dt_over_Mj        = dt / (rho[j] * Vj[j]);
+        new_u[j] += dt_over_Mj * momentum_fluxes;
+        new_E[j] += dt_over_Mj * energy_fluxes;
+        new_CG[j] += dt_over_Mj * cauchy_green_fluxes;
+        new_CG[j] += transpose(new_CG[j]);
+        new_CG[j] *= 0.5;
+      });
+
+    CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj();
+
+    parallel_for(
+      mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { new_rho[j] *= Vj[j] / new_Vj[j]; });
+
+    return {std::make_shared<MeshVariant>(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_CG))};
+  }
+
+  std::tuple<std::shared_ptr<const MeshVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>>
+  order2_apply_fluxes(const double& dt,
+               const std::shared_ptr<const DiscreteFunctionVariant>& rho,
+               const std::shared_ptr<const DiscreteFunctionVariant>& u,
+               const std::shared_ptr<const DiscreteFunctionVariant>& E,
+               const std::shared_ptr<const DiscreteFunctionVariant>& CG,
+               const std::shared_ptr<const DiscreteFunctionVariant>& rho_app,
+               const std::shared_ptr<const DiscreteFunctionVariant>& CG_app,
+               const std::shared_ptr<const ItemValueVariant>& ur,
+               const std::shared_ptr<const SubItemValuePerItemVariant>& Fjr) const
+  {
+    std::shared_ptr mesh_v = getCommonMesh({rho, u, E});
+    if (not mesh_v) {
+      throw NormalError("discrete functions are not defined on the same mesh");
+    }
+
+    if (not checkDiscretizationType({rho, u, E}, DiscreteFunctionType::P0)) {
+      throw NormalError("hyperelastic solver expects P0 functions");
+    }
+
+    return this->order2_apply_fluxes(dt,                                   //
+                              *mesh_v->get<MeshType>(),             //
+                              rho->get<DiscreteScalarFunction>(),   //
+                              u->get<DiscreteVectorFunction>(),     //
+                              E->get<DiscreteScalarFunction>(),     //
+                              CG->get<DiscreteTensorFunction>(),    //
+                              rho_app->get<DiscreteScalarFunction>(),   //
+                              CG_app->get<DiscreteTensorFunction>(),    //
+                              ur->get<NodeValue<const Rd>>(),       //
+                              Fjr->get<NodeValuePerCell<const Rd>>());
+  }
+
   std::tuple<std::shared_ptr<const MeshVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,