diff --git a/ProcessLib/AbstractJacobianAssembler.h b/ProcessLib/AbstractJacobianAssembler.h
index b589df0aff89b41e72e6614a077bf5551e396999..d10ed2f4bc1c35354e069278ca75756b5a6a223b 100644
--- a/ProcessLib/AbstractJacobianAssembler.h
+++ b/ProcessLib/AbstractJacobianAssembler.h
@@ -50,6 +50,8 @@ public:
         OGS_FATAL("not implemented.");
     }
 
+    virtual std::unique_ptr<AbstractJacobianAssembler> copy() const = 0;
+
     virtual ~AbstractJacobianAssembler() = default;
 };
 
diff --git a/ProcessLib/AnalyticalJacobianAssembler.cpp b/ProcessLib/AnalyticalJacobianAssembler.cpp
index cc62365c52960f78feb0dbb1d15afaa34fe81441..61a1f91d12a21075f659471a9dd862f6bd705609 100644
--- a/ProcessLib/AnalyticalJacobianAssembler.cpp
+++ b/ProcessLib/AnalyticalJacobianAssembler.cpp
@@ -38,4 +38,10 @@ void AnalyticalJacobianAssembler::assembleWithJacobianForStaggeredScheme(
         local_b_data, local_Jac_data);
 }
 
+std::unique_ptr<AbstractJacobianAssembler> AnalyticalJacobianAssembler::copy()
+    const
+{
+    return std::make_unique<AnalyticalJacobianAssembler>(*this);
+}
+
 }  // namespace ProcessLib
diff --git a/ProcessLib/AnalyticalJacobianAssembler.h b/ProcessLib/AnalyticalJacobianAssembler.h
index a5b9f092f994b6544acb70c9a035a5beb8d905ac..b0204790f77bf4f11236414741d41f61b68fefd4 100644
--- a/ProcessLib/AnalyticalJacobianAssembler.h
+++ b/ProcessLib/AnalyticalJacobianAssembler.h
@@ -47,6 +47,8 @@ public:
         std::vector<double>& local_M_data, std::vector<double>& local_K_data,
         std::vector<double>& local_b_data,
         std::vector<double>& local_Jac_data) override;
+
+    std::unique_ptr<AbstractJacobianAssembler> copy() const override;
 };
 
 }  // namespace ProcessLib
diff --git a/ProcessLib/CentralDifferencesJacobianAssembler.cpp b/ProcessLib/CentralDifferencesJacobianAssembler.cpp
index 82eb141334c79e2b7b0c2bc769888d56af52b3a5..4796bf5d2dc57794ce1b833946dbecad6729b4d5 100644
--- a/ProcessLib/CentralDifferencesJacobianAssembler.cpp
+++ b/ProcessLib/CentralDifferencesJacobianAssembler.cpp
@@ -221,4 +221,10 @@ createCentralDifferencesJacobianAssembler(BaseLib::ConfigTree const& config)
         std::move(abs_eps));
 }
 
+std::unique_ptr<AbstractJacobianAssembler>
+CentralDifferencesJacobianAssembler::copy() const
+{
+    return std::make_unique<CentralDifferencesJacobianAssembler>(*this);
+}
+
 }  // namespace ProcessLib
diff --git a/ProcessLib/CentralDifferencesJacobianAssembler.h b/ProcessLib/CentralDifferencesJacobianAssembler.h
index 2b1bec489fabb18076b4c40169fb19d80216dceb..320abf6908465053eb51a68301e74652063eb718 100644
--- a/ProcessLib/CentralDifferencesJacobianAssembler.h
+++ b/ProcessLib/CentralDifferencesJacobianAssembler.h
@@ -11,12 +11,13 @@
 #pragma once
 
 #include <memory>
+
 #include "AbstractJacobianAssembler.h"
 
 namespace BaseLib
 {
 class ConfigTree;
-}  // BaseLib
+}  // namespace BaseLib
 
 namespace ProcessLib
 {
@@ -59,6 +60,8 @@ public:
                               std::vector<double>& local_b_data,
                               std::vector<double>& local_Jac_data) override;
 
+    std::unique_ptr<AbstractJacobianAssembler> copy() const override;
+
 private:
     std::vector<double> const _absolute_epsilons;
 
diff --git a/ProcessLib/CompareJacobiansJacobianAssembler.cpp b/ProcessLib/CompareJacobiansJacobianAssembler.cpp
index 45afa470eeebf2378beb2e75c9fa6267fe9e3b60..0c8388b9dbac4fde29cbc3cee2e922aa15c7f77a 100644
--- a/ProcessLib/CompareJacobiansJacobianAssembler.cpp
+++ b/ProcessLib/CompareJacobiansJacobianAssembler.cpp
@@ -396,6 +396,15 @@ void CompareJacobiansJacobianAssembler::assembleWithJacobian(
     }
 }
 
+std::unique_ptr<AbstractJacobianAssembler>
+CompareJacobiansJacobianAssembler::copy() const
+{
+    OGS_FATAL(
+        "CompareJacobiansJacobianAssembler should not be copied. This class "
+        "logs to a file, which would most certainly break after copying "
+        "(concurrent file access) with the current implementation.");
+}
+
 std::unique_ptr<CompareJacobiansJacobianAssembler>
 createCompareJacobiansJacobianAssembler(BaseLib::ConfigTree const& config)
 {
@@ -427,5 +436,4 @@ createCompareJacobiansJacobianAssembler(BaseLib::ConfigTree const& config)
         std::move(asm1), std::move(asm2), abs_tol, rel_tol, fail_on_error,
         log_file);
 }
-
 }  // namespace ProcessLib
diff --git a/ProcessLib/CompareJacobiansJacobianAssembler.h b/ProcessLib/CompareJacobiansJacobianAssembler.h
index 29579a7d59577ea0170238bbadebe67fdaedaba4..74b85599fa8550d19320e64bf83d9ac7f105f53c 100644
--- a/ProcessLib/CompareJacobiansJacobianAssembler.h
+++ b/ProcessLib/CompareJacobiansJacobianAssembler.h
@@ -13,6 +13,7 @@
 #include <fstream>
 #include <limits>
 #include <memory>
+
 #include "AbstractJacobianAssembler.h"
 
 namespace BaseLib
@@ -60,6 +61,8 @@ public:
                               std::vector<double>& local_b_data,
                               std::vector<double>& local_Jac_data) override;
 
+    std::unique_ptr<AbstractJacobianAssembler> copy() const override;
+
 private:
     std::unique_ptr<AbstractJacobianAssembler> _asm1;
     std::unique_ptr<AbstractJacobianAssembler> _asm2;
diff --git a/ProcessLib/ForwardDifferencesJacobianAssembler.cpp b/ProcessLib/ForwardDifferencesJacobianAssembler.cpp
index 067b71fb7bb1685c4d920b3fffec304f0d7dcff4..2a22c0644543b3d4f66b565faf56df2928bd7d1f 100644
--- a/ProcessLib/ForwardDifferencesJacobianAssembler.cpp
+++ b/ProcessLib/ForwardDifferencesJacobianAssembler.cpp
@@ -153,4 +153,10 @@ void ForwardDifferencesJacobianAssembler::assembleWithJacobian(
     }
 }
 
+std::unique_ptr<AbstractJacobianAssembler>
+ForwardDifferencesJacobianAssembler::copy() const
+{
+    return std::make_unique<ForwardDifferencesJacobianAssembler>(*this);
+}
+
 }  // namespace ProcessLib
diff --git a/ProcessLib/ForwardDifferencesJacobianAssembler.h b/ProcessLib/ForwardDifferencesJacobianAssembler.h
index a7045aa6c39796cf233d043a72a6e9cd08f9fe71..c8e695702dadb71c72c6ccd47a801309ffc6fc18 100644
--- a/ProcessLib/ForwardDifferencesJacobianAssembler.h
+++ b/ProcessLib/ForwardDifferencesJacobianAssembler.h
@@ -52,6 +52,8 @@ public:
                               std::vector<double>& local_b_data,
                               std::vector<double>& local_Jac_data) override;
 
+    std::unique_ptr<AbstractJacobianAssembler> copy() const override;
+
 private:
     std::vector<double> const _absolute_epsilons;