diff --git a/Device/Data/ArrayUtil.cpp b/Device/Data/ArrayUtil.cpp
index dd496f1198aef28783baecc1d8ba30062c0e54c7..f86b6bd9f99d4e96ceb25e0c9ecc18a75544a6b9 100644
--- a/Device/Data/ArrayUtil.cpp
+++ b/Device/Data/ArrayUtil.cpp
@@ -37,28 +37,52 @@ std::unique_ptr<Datafield> DataUtil::Array::createPField1D(const std::vector<dou
     return std::make_unique<Datafield>(std::move(axes), vec);
 }
 
+std::unique_ptr<Datafield> DataUtil::Array::createPField1D(const std::vector<double>& vec,
+                                                           const std::vector<double>& stdv)
+{
+    const size_t N = vec.size();
+    ASSERT(stdv.size() == N);
+    std::vector<const Scale*> axes{newEquiDivision("axis0", N, 0.0, (double)N)};
+    return std::make_unique<Datafield>(std::move(axes), vec, stdv);
+}
+
 std::unique_ptr<Datafield>
-DataUtil::Array::createPField2D(const std::vector<std::vector<double>>& vec)
+DataUtil::Array::createPField2D(const std::vector<std::vector<double>>& vec,
+                                const std::vector<std::vector<double>>& stdv)
 {
     auto shape = DataUtil::Array::getShape(vec);
     const size_t nrows = shape.first;
     const size_t ncols = shape.second;
-
     ASSERT(nrows > 0);
     ASSERT(ncols > 0);
+    const size_t N = nrows * ncols;
 
     std::vector<const Scale*> axes{newEquiDivision("axis0", ncols, 0.0, (double)ncols),
                                    newEquiDivision("axis1", nrows, 0.0, (double)nrows)};
 
-    std::vector<double> out(nrows * ncols);
+    ASSERT(vec.size() == nrows);
+    std::vector<double> out(N);
     for (size_t row = 0; row < nrows; ++row) {
+        ASSERT(vec[row].size() == ncols);
         for (size_t col = 0; col < ncols; ++col) {
             size_t iout = nrows - row - 1 + col * nrows;
             out[iout] = vec[row][col];
         }
     }
 
-    return std::make_unique<Datafield>(std::move(axes), out);
+    if (stdv.empty())
+        return std::make_unique<Datafield>(std::move(axes), out);
+
+    ASSERT(stdv.size() == nrows);
+    std::vector<double> outerr(N);
+    for (size_t row = 0; row < nrows; ++row) {
+        ASSERT(stdv[row].size() == ncols);
+        for (size_t col = 0; col < ncols; ++col) {
+            size_t iout = nrows - row - 1 + col * nrows;
+            outerr[iout] = stdv[row][col];
+        }
+    }
+    return std::make_unique<Datafield>(std::move(axes), out, outerr);
 }
 
 std::vector<double> DataUtil::Array::createVector1D(const Datafield& data)
diff --git a/Device/Data/ArrayUtil.h b/Device/Data/ArrayUtil.h
index 5a89e2decaa02a1b8c115c78bd2668a2ac0a2fd0..2d81318cd63e1d447d075e90501ba9c3a02fd0d2 100644
--- a/Device/Data/ArrayUtil.h
+++ b/Device/Data/ArrayUtil.h
@@ -31,8 +31,11 @@ namespace DataUtil::Array {
 std::pair<size_t, size_t> getShape(const std::vector<std::vector<double>>& data);
 
 std::unique_ptr<Datafield> createPField1D(const std::vector<double>& vec);
+std::unique_ptr<Datafield> createPField1D(const std::vector<double>& vec,
+                                          const std::vector<double>& stdv);
 
-std::unique_ptr<Datafield> createPField2D(const std::vector<std::vector<double>>& vec);
+std::unique_ptr<Datafield> createPField2D(const std::vector<std::vector<double>>& vec,
+                                          const std::vector<std::vector<double>>& stdv = {});
 
 //! Creates 1D vector from Datafield.
 std::vector<double> createVector1D(const Datafield& data);
diff --git a/Device/Data/Datafield.cpp b/Device/Data/Datafield.cpp
index da0c49535576db2ce3e590e1fefb55f1106f6264..c91f2de2b3b3157b7baccd32953651baaabcfcdd 100644
--- a/Device/Data/Datafield.cpp
+++ b/Device/Data/Datafield.cpp
@@ -19,6 +19,64 @@
 #include "Base/Util/Assert.h"
 #include <algorithm>
 
+#ifdef BORNAGAIN_PYTHON
+
+#include "PyCore/Embed/PyInterpreter.h" // Numpy::arrayND, Numpy::getDataPtr
+#include <Python.h>
+
+namespace {
+
+PyObject* npExport(const Frame& frame, const std::vector<double>& flatData)
+{
+    if (flatData.empty())
+        return Py_BuildValue("");
+
+    // TODO: Thoroughly check this function regarding index manipulations
+
+    PyInterpreter::Numpy::initialize();
+
+    ASSERT(frame.rank() <= 2);
+
+    std::vector<size_t> dimensions;
+    for (size_t i = 0; i < frame.rank(); i++)
+        dimensions.push_back(frame.axis(i).size());
+    // for rot90 of 2-dim arrays to conform with numpy
+    if (dimensions.size() == 2)
+        std::swap(dimensions[0], dimensions[1]);
+
+    // creating ndarray objects describing size of dimensions
+    PyObjectPtr pyarray{PyInterpreter::Numpy::arrayND(dimensions)};
+    ASSERT(pyarray.valid());
+
+    // get the pointer to the data buffer of the array (assumed to be C-contiguous)
+    double* data{PyInterpreter::Numpy::getDataPtr(pyarray.get())};
+    ASSERT(data);
+
+    double* array_buffer = data;
+
+    // filling numpy array with output_data
+    if (frame.rank() == 2) {
+        for (size_t i = 0; i < frame.size(); ++i) {
+            std::vector<int> axes_indices = frame.allIndices(i);
+            size_t offset = axes_indices[0]
+                            + frame.axis(0).size() * (frame.axis(1).size() - 1 - axes_indices[1]);
+            array_buffer[offset] = flatData[i];
+        }
+    } else if (frame.rank() == 1) {
+        for (size_t i = 0; i < frame.size(); ++i)
+            *array_buffer++ = flatData[i];
+    } else
+        ASSERT_NEVER;
+
+    // returns a _new_ reference; ie. caller is responsible for the ref-count
+    return pyarray.release();
+}
+
+} // namespace
+
+#endif // BORNAGAIN_PYTHON
+
+
 Datafield::Datafield(std::string title, const Frame* frame, std::vector<double> values,
                      std::vector<double> errSigmas)
     : m_title(std::move(title))
@@ -224,52 +282,14 @@ Datafield* Datafield::crop(double xmin, double xmax) const
 
 #ifdef BORNAGAIN_PYTHON
 
-#include "PyCore/Embed/PyInterpreter.h" // Numpy::arrayND, Numpy::getDataPtr
-
 PyObject* Datafield::npArray() const
 {
-    // TODO: Thoroughly check this function regarding index manipulations
-
-    PyInterpreter::Numpy::initialize();
-
-    ASSERT(rank() <= 2);
-
-    std::vector<size_t> dimensions;
-    for (size_t i = 0; i < rank(); i++)
-        dimensions.push_back(axis(i).size());
-
-    // for rot90 of 2-dim arrays to conform with numpy
-    if (dimensions.size() == 2)
-        std::swap(dimensions[0], dimensions[1]);
-
-    // creating ndarray objects describing size of dimensions
-    PyObjectPtr pyarray{PyInterpreter::Numpy::arrayND(dimensions)};
-    if (!pyarray.valid())
-        return nullptr;
-
-    // get the pointer to the data buffer of the array (assumed to be C-contiguous)
-    double* data{PyInterpreter::Numpy::getDataPtr(pyarray.get())};
-
-    if (!data)
-        return nullptr;
-
-    double* array_buffer = data;
-
-    // filling numpy array with output_data
-    if (rank() == 2) {
-        for (size_t i = 0; i < size(); ++i) {
-            std::vector<int> axes_indices = frame().allIndices(i);
-            size_t offset =
-                axes_indices[0] + axis(0).size() * (axis(1).size() - 1 - axes_indices[1]);
-            array_buffer[offset] = (*this)[i];
-        }
-    } else if (rank() == 1) {
-        for (size_t i = 0; i < size(); ++i)
-            *array_buffer++ = (*this)[i];
-    }
+    return ::npExport(frame(), flatVector());
+}
 
-    // returns a _new_ reference; ie. caller is responsible for the ref-count
-    return pyarray.release();
+PyObject* Datafield::npErrors() const
+{
+    return ::npExport(frame(), errorSigmas());
 }
 
 #endif // BORNAGAIN_PYTHON
diff --git a/Device/Data/Datafield.h b/Device/Data/Datafield.h
index b835382576d6467a298ccc4a50850afde9235a1a..739d2a2b892822d223f005c648c2e3dd6647116d 100644
--- a/Device/Data/Datafield.h
+++ b/Device/Data/Datafield.h
@@ -65,6 +65,7 @@ public:
 #ifdef BORNAGAIN_PYTHON
     //! Returns data as Python numpy array.
     PyObject* npArray() const;
+    PyObject* npErrors() const;
 #endif
 
     //... retrieve basic info
diff --git a/GUI/View/Fit/FitObjectiveBuilder.cpp b/GUI/View/Fit/FitObjectiveBuilder.cpp
index ef315902562e1fea3fc79243ed64621d36cbb725..cd468852dd37865a808009b240e89f91808a58f4 100644
--- a/GUI/View/Fit/FitObjectiveBuilder.cpp
+++ b/GUI/View/Fit/FitObjectiveBuilder.cpp
@@ -85,7 +85,7 @@ std::unique_ptr<FitObjective> FitObjectiveBuilder::createFitObjective() const
 
     std::unique_ptr<Datafield> data(intensity_item->c_field()->clone());
 
-    result->execAddSimulationAndData(builder, *data, nullptr, 1.0);
+    result->execAddSimulationAndData(builder, *data, 1.0);
 
     return result;
 }
diff --git a/Sim/Fitting/FitObjective.cpp b/Sim/Fitting/FitObjective.cpp
index 993a36026603020d03c4eb5b7b521b94f1741015..e43dc091659aaadb6035637a1a6bf9f5508f819c 100644
--- a/Sim/Fitting/FitObjective.cpp
+++ b/Sim/Fitting/FitObjective.cpp
@@ -81,16 +81,17 @@ ChiModuleWrapper::ChiModuleWrapper(std::unique_ptr<IChiSquaredModule> module)
 double ChiModuleWrapper::compute(const std::vector<SimDataPair>& fit_objects, size_t n_pars) const
 {
     size_t n_points = 0;
-    double result = 0.0;
+    double result = 0;
     for (const auto& obj : fit_objects) {
         const auto sim_array = obj.simulation_array();
         const auto exp_array = obj.experimental_array();
-        const auto weights = obj.user_weights_array();
         const size_t n_elements = sim_array.size();
+        double contrib = 0;
         for (size_t i = 0; i < n_elements; ++i) {
-            double value = m_module->residual(sim_array[i], exp_array[i], weights[i]);
-            result += value * value;
+            double value = m_module->residual(sim_array[i], exp_array[i]);
+            contrib += std::pow(value, 2);
         }
+        result += obj.weight() * contrib;
         n_points += n_elements;
     }
 
@@ -116,7 +117,7 @@ double ObjectiveMetricWrapper::compute(const std::vector<SimDataPair>& fit_objec
 
     double result = 0.0;
     for (const auto& obj : fit_objects)
-        result += m_module->compute(obj, use_uncertainties);
+        result += obj.weight() * m_module->computeMetric(obj, use_uncertainties);
     return result;
 }
 
@@ -141,40 +142,39 @@ FitObjective::~FitObjective() = default;
 //!
 //! Should be private, but is used in several tests.
 void FitObjective::execAddSimulationAndData(const simulation_builder_t& builder,
-                                            const Datafield& data,
-                                            std::unique_ptr<Datafield>&& stdv, double weight)
+                                            const Datafield& data, double weight)
 {
-    m_fit_objects.emplace_back(builder, data, std::move(stdv), weight);
+    m_fit_objects.emplace_back(builder, data, weight);
 }
 
 void FitObjective::addSimulationAndData(const PyBuilderCallback& callback,
                                         const std::vector<std::vector<double>>& data, double weight)
 {
     execAddSimulationAndData(simulationBuilder(callback), *DataUtil::Array::createPField2D(data),
-                             nullptr, weight);
+                             weight);
 }
 
 void FitObjective::addSimulationAndData(const PyBuilderCallback& callback,
                                         const std::vector<double>& data, double weight)
 {
     execAddSimulationAndData(simulationBuilder(callback), *DataUtil::Array::createPField1D(data),
-                             nullptr, weight);
+                             weight);
 }
 
 void FitObjective::addSimulationAndData(const PyBuilderCallback& callback,
                                         const std::vector<std::vector<double>>& data,
                                         const std::vector<std::vector<double>>& stdv, double weight)
 {
-    execAddSimulationAndData(simulationBuilder(callback), *DataUtil::Array::createPField2D(data),
-                             DataUtil::Array::createPField2D(stdv), weight);
+    execAddSimulationAndData(simulationBuilder(callback),
+                             *DataUtil::Array::createPField2D(data, stdv), weight);
 }
 
 void FitObjective::addSimulationAndData(const PyBuilderCallback& callback,
                                         const std::vector<double>& data,
                                         const std::vector<double>& stdv, double weight)
 {
-    execAddSimulationAndData(simulationBuilder(callback), *DataUtil::Array::createPField1D(data),
-                             DataUtil::Array::createPField1D(stdv), weight);
+    execAddSimulationAndData(simulationBuilder(callback),
+                             *DataUtil::Array::createPField1D(data, stdv), weight);
 }
 
 double FitObjective::evaluate(const mumufit::Parameters& params)
@@ -189,8 +189,8 @@ std::vector<double> FitObjective::evaluate_residuals(const mumufit::Parameters&
 {
     evaluate(params);
 
-    std::vector<double> result = experimental_array(); // init result with experimental data values
-    const std::vector<double> sim_values = simulation_array();
+    std::vector<double> result = flatExpData(); // init result with experimental data values
+    const std::vector<double> sim_values = flatSimData();
     std::transform(result.begin(), result.end(), sim_values.begin(), result.begin(),
                    [](double lhs, double rhs) { return lhs - rhs; });
     return result;
@@ -208,21 +208,15 @@ Datafield FitObjective::experimentalData(size_t i_item) const
     return dataPair(i_item).experimentalData();
 }
 
-//! Returns experimental data uncertainties in the form of Datafield.
-Datafield FitObjective::uncertaintyData(size_t i_item) const
-{
-    return dataPair(i_item).uncertainties();
-}
-
 //! Returns relative difference between simulation and experimental data
-//! in the form of Datafield.
+//! in the form of Datafield, for use in plotting.
 Datafield FitObjective::relativeDifference(size_t i_item) const
 {
     return dataPair(i_item).relativeDifference();
 }
 
 //! Returns absolute value of difference between simulation and experimental data
-//! in the form of Datafield.
+//! in the form of Datafield, for use in plotting.
 Datafield FitObjective::absoluteDifference(size_t i_item) const
 {
     return dataPair(i_item).absoluteDifference();
@@ -230,32 +224,18 @@ Datafield FitObjective::absoluteDifference(size_t i_item) const
 
 //! Returns one-dimensional array representing merged experimental data.
 //! The area outside of the region of interest is not included, masked data is nullified.
-std::vector<double> FitObjective::experimental_array() const
+std::vector<double> FitObjective::flatExpData() const
 {
     return composeArray(&SimDataPair::experimental_array);
 }
 
 //! Returns one-dimensional array representing merged simulated intensities data.
 //! The area outside of the region of interest is not included, masked data is nullified.
-std::vector<double> FitObjective::simulation_array() const
+std::vector<double> FitObjective::flatSimData() const
 {
     return composeArray(&SimDataPair::simulation_array);
 }
 
-//! Returns one-dimensional array representing merged data uncertainties.
-//! The area outside of the region of interest is not included, masked data is nullified.
-std::vector<double> FitObjective::uncertainties() const
-{
-    return composeArray(&SimDataPair::uncertainties_array);
-}
-
-//! Returns one-dimensional array representing merged user weights.
-//! The area outside of the region of interest is not included, masked data is nullified.
-std::vector<double> FitObjective::weights_array() const
-{
-    return composeArray(&SimDataPair::user_weights_array);
-}
-
 const SimDataPair& FitObjective::dataPair(size_t i_item) const
 {
     return m_fit_objects.at(i_item);
diff --git a/Sim/Fitting/FitObjective.h b/Sim/Fitting/FitObjective.h
index 628be25b7fa226352cb10a26329aebd37bcbdc58..ac6074eb27d9bdcd97d17991cc5cd218adc43176 100644
--- a/Sim/Fitting/FitObjective.h
+++ b/Sim/Fitting/FitObjective.h
@@ -45,7 +45,7 @@ public:
 
 #ifndef SWIG
     void execAddSimulationAndData(const simulation_builder_t& builder, const Datafield& data,
-                                  std::unique_ptr<Datafield>&& stdv, double weight = 1.0);
+                                  double weight = 1.0);
 #endif
     //! Constructs simulation/data pair for later fit.
     //! @param callback: simulation builder capable of producing simulations
@@ -75,14 +75,11 @@ public:
 
     Datafield simulationResult(size_t i_item = 0) const;
     Datafield experimentalData(size_t i_item = 0) const;
-    Datafield uncertaintyData(size_t i_item = 0) const;
     Datafield relativeDifference(size_t i_item = 0) const;
     Datafield absoluteDifference(size_t i_item = 0) const;
 
-    std::vector<double> experimental_array() const;
-    std::vector<double> simulation_array() const;
-    std::vector<double> uncertainties() const;
-    std::vector<double> weights_array() const;
+    std::vector<double> flatExpData() const;
+    std::vector<double> flatSimData() const;
 
     //! Initializes printing to standard output on every_nth fit iteration.
     void initPrint(int every_nth);
diff --git a/Sim/Fitting/ObjectiveMetric.cpp b/Sim/Fitting/ObjectiveMetric.cpp
index e52df3ba29fca734007e28bb55377153549af84c..4d8a52c9cf7e5798e1ca23732e6a083c23829c5d 100644
--- a/Sim/Fitting/ObjectiveMetric.cpp
+++ b/Sim/Fitting/ObjectiveMetric.cpp
@@ -35,11 +35,10 @@ T* copyMetric(const T& metric)
     return result;
 }
 
-void checkIntegrity(const std::vector<double>& sim_data, const std::vector<double>& exp_data,
-                    const std::vector<double>& weight_factors)
+void checkIntegrity(const std::vector<double>& sim_data, const std::vector<double>& exp_data)
 {
     const size_t sim_size = sim_data.size();
-    if (sim_size != exp_data.size() || sim_size != weight_factors.size())
+    if (sim_size != exp_data.size())
         throw std::runtime_error("Error in ObjectiveMetric: input arrays have different sizes");
 
     for (size_t i = 0; i < sim_size; ++i)
@@ -49,12 +48,12 @@ void checkIntegrity(const std::vector<double>& sim_data, const std::vector<doubl
 }
 
 void checkIntegrity(const std::vector<double>& sim_data, const std::vector<double>& exp_data,
-                    const std::vector<double>& exp_stdv, const std::vector<double>& weight_factors)
+                    const std::vector<double>& exp_stdv)
 {
     if (sim_data.size() != exp_stdv.size())
         throw std::runtime_error("Error in ObjectiveMetric: input arrays have different sizes");
 
-    checkIntegrity(sim_data, exp_data, weight_factors);
+    checkIntegrity(sim_data, exp_data);
 }
 
 } // namespace
@@ -64,7 +63,7 @@ ObjectiveMetric::ObjectiveMetric(std::function<double(double)> norm)
 {
 }
 
-double ObjectiveMetric::compute(const SimDataPair& data_pair, bool use_weights) const
+double ObjectiveMetric::computeMetric(const SimDataPair& data_pair, bool use_weights) const
 {
     if (use_weights && !data_pair.containsUncertainties())
         throw std::runtime_error("Error in ObjectiveMetric::compute: the metric is weighted, but "
@@ -72,9 +71,8 @@ double ObjectiveMetric::compute(const SimDataPair& data_pair, bool use_weights)
 
     if (use_weights)
         return computeFromArrays(data_pair.simulation_array(), data_pair.experimental_array(),
-                                 data_pair.uncertainties_array(), data_pair.user_weights_array());
-    return computeFromArrays(data_pair.simulation_array(), data_pair.experimental_array(),
-                             data_pair.user_weights_array());
+                                 data_pair.uncertainties_array());
+    return computeFromArrays(data_pair.simulation_array(), data_pair.experimental_array());
 }
 
 void ObjectiveMetric::setNorm(std::function<double(double)> norm)
@@ -95,30 +93,29 @@ Chi2Metric* Chi2Metric::clone() const
 }
 
 double Chi2Metric::computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                     std::vector<double> exp_stdv,
-                                     std::vector<double> weight_factors) const
+                                     std::vector<double> exp_stdv) const
 {
-    checkIntegrity(sim_data, exp_data, exp_stdv, weight_factors);
+    checkIntegrity(sim_data, exp_data, exp_stdv);
 
     double result = 0.0;
     auto norm_fun = norm();
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i)
-        if (exp_data[i] >= 0.0 && weight_factors[i] > 0.0 && exp_stdv[i] > 0.0)
-            result += norm_fun((exp_data[i] - sim_data[i]) / exp_stdv[i]) * weight_factors[i];
+        if (exp_data[i] >= 0.0 && exp_stdv[i] > 0.0)
+            result += norm_fun((exp_data[i] - sim_data[i]) / exp_stdv[i]);
 
     return std::isfinite(result) ? result : double_max;
 }
 
-double Chi2Metric::computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                     std::vector<double> weight_factors) const
+double Chi2Metric::computeFromArrays(std::vector<double> sim_data,
+                                     std::vector<double> exp_data) const
 {
-    checkIntegrity(sim_data, exp_data, weight_factors);
+    checkIntegrity(sim_data, exp_data);
 
     auto norm_fun = norm();
     double result = 0.0;
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i)
-        if (exp_data[i] >= 0.0 && weight_factors[i] > 0.0)
-            result += norm_fun(exp_data[i] - sim_data[i]) * weight_factors[i];
+        if (exp_data[i] >= 0.0)
+            result += norm_fun(exp_data[i] - sim_data[i]);
 
     return std::isfinite(result) ? result : double_max;
 }
@@ -136,19 +133,18 @@ PoissonLikeMetric* PoissonLikeMetric::clone() const
 }
 
 double PoissonLikeMetric::computeFromArrays(std::vector<double> sim_data,
-                                            std::vector<double> exp_data,
-                                            std::vector<double> weight_factors) const
+                                            std::vector<double> exp_data) const
 {
-    checkIntegrity(sim_data, exp_data, weight_factors);
+    checkIntegrity(sim_data, exp_data);
 
     double result = 0.0;
     auto norm_fun = norm();
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i) {
-        if (weight_factors[i] <= 0.0 || exp_data[i] < 0.0)
+        if (exp_data[i] < 0.0)
             continue;
         const double variance = std::max(1.0, sim_data[i]);
         const double value = (sim_data[i] - exp_data[i]) / std::sqrt(variance);
-        result += norm_fun(value) * weight_factors[i];
+        result += norm_fun(value);
     }
 
     return std::isfinite(result) ? result : double_max;
@@ -167,39 +163,38 @@ LogMetric* LogMetric::clone() const
 }
 
 double LogMetric::computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                    std::vector<double> exp_stdv,
-                                    std::vector<double> weight_factors) const
+                                    std::vector<double> exp_stdv) const
 {
-    checkIntegrity(sim_data, exp_data, exp_stdv, weight_factors);
+    checkIntegrity(sim_data, exp_data, exp_stdv);
 
     double result = 0.0;
     auto norm_fun = norm();
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i) {
-        if (weight_factors[i] <= 0.0 || exp_data[i] < 0.0 || exp_stdv[i] <= 0.0)
+        if (exp_data[i] < 0.0 || exp_stdv[i] <= 0.0)
             continue;
         const double sim_val = std::max(double_min, sim_data[i]);
         const double exp_val = std::max(double_min, exp_data[i]);
         double value = std::log10(sim_val) - std::log10(exp_val);
         value *= exp_val * ln10 / exp_stdv[i];
-        result += norm_fun(value) * weight_factors[i];
+        result += norm_fun(value);
     }
 
     return std::isfinite(result) ? result : double_max;
 }
 
-double LogMetric::computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                    std::vector<double> weight_factors) const
+double LogMetric::computeFromArrays(std::vector<double> sim_data,
+                                    std::vector<double> exp_data) const
 {
-    checkIntegrity(sim_data, exp_data, weight_factors);
+    checkIntegrity(sim_data, exp_data);
 
     double result = 0.0;
     auto norm_fun = norm();
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i) {
-        if (weight_factors[i] <= 0.0 || exp_data[i] < 0.0)
+        if (exp_data[i] < 0.0)
             continue;
         const double sim_val = std::max(double_min, sim_data[i]);
         const double exp_val = std::max(double_min, exp_data[i]);
-        result += norm_fun(std::log10(sim_val) - std::log10(exp_val)) * weight_factors[i];
+        result += norm_fun(std::log10(sim_val) - std::log10(exp_val));
     }
 
     return std::isfinite(result) ? result : double_max;
@@ -218,19 +213,18 @@ meanRelativeDifferenceMetric* meanRelativeDifferenceMetric::clone() const
 }
 
 double meanRelativeDifferenceMetric::computeFromArrays(std::vector<double> sim_data,
-                                                       std::vector<double> exp_data,
-                                                       std::vector<double> weight_factors) const
+                                                       std::vector<double> exp_data) const
 {
-    checkIntegrity(sim_data, exp_data, weight_factors);
+    checkIntegrity(sim_data, exp_data);
 
     double result = 0.0;
     auto norm_fun = norm();
     for (size_t i = 0, sim_size = sim_data.size(); i < sim_size; ++i) {
-        if (weight_factors[i] <= 0.0 || exp_data[i] < 0.0)
+        if (exp_data[i] < 0.0)
             continue;
         const double sim_val = std::max(double_min, sim_data[i]);
         const double exp_val = std::max(double_min, exp_data[i]);
-        result += norm_fun((exp_val - sim_val) / (exp_val + sim_val)) * weight_factors[i];
+        result += norm_fun((exp_val - sim_val) / (exp_val + sim_val));
     }
 
     return std::isfinite(result) ? result : double_max;
@@ -248,10 +242,10 @@ RQ4Metric* RQ4Metric::clone() const
     return copyMetric(*this);
 }
 
-double RQ4Metric::compute(const SimDataPair& data_pair, bool use_weights) const
+double RQ4Metric::computeMetric(const SimDataPair& data_pair, bool use_weights) const
 {
     if (use_weights)
-        return Chi2Metric::compute(data_pair, use_weights);
+        return Chi2Metric::computeMetric(data_pair, use_weights);
 
     // fetching data in RQ4 form
     // TODO weight data points correctly
@@ -262,5 +256,5 @@ double RQ4Metric::compute(const SimDataPair& data_pair, bool use_weights) const
     const std::vector<double> sim_vec = data_pair.simulationResult().flatVector();
     const std::vector<double> exp_vec = data_pair.experimentalData().flatVector();
 
-    return computeFromArrays(sim_vec, exp_vec, data_pair.user_weights_array());
+    return computeFromArrays(sim_vec, exp_vec);
 }
diff --git a/Sim/Fitting/ObjectiveMetric.h b/Sim/Fitting/ObjectiveMetric.h
index 137fcda19cd8e2bb65a94eec21f5c8c451036e31..c3b9e157f78b2af3addb30963a928f46b3b2a8f3 100644
--- a/Sim/Fitting/ObjectiveMetric.h
+++ b/Sim/Fitting/ObjectiveMetric.h
@@ -35,29 +35,23 @@ public:
     //! Computes metric value from SimDataPair object. Calls computeFromArrays internally.
     //! @param data_pair: SimDataPair object. Can optionally contain data uncertainties
     //! @param use_weights: boolean, defines if data uncertainties should be taken into account
-    virtual double compute(const SimDataPair& data_pair, bool use_weights) const;
+    virtual double computeMetric(const SimDataPair& data_pair, bool use_weights) const;
 
     //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors and uncertainties.
+    //! are ignored as well as non-positive uncertainties.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
     //! @param exp_stdv: array with experimental data uncertainties.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
     virtual double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                     std::vector<double> exp_stdv,
-                                     std::vector<double> weight_factors) const = 0;
+                                     std::vector<double> exp_stdv) const = 0;
 
-    //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors.
+    //! Computes metric value from data arrays. Negative values in exp_data are ignored.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
-    virtual double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                                     std::vector<double> weight_factors) const = 0;
+    virtual double computeFromArrays(std::vector<double> sim_data,
+                                     std::vector<double> exp_data) const = 0;
 
     void setNorm(std::function<double(double)> norm);
 
@@ -78,26 +72,20 @@ public:
     Chi2Metric* clone() const override;
 
     //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors and uncertainties.
+    //! are ignored as well as non-positive uncertainties.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
     //! @param exp_stdv: array with experimental data uncertainties.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
     double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> exp_stdv,
-                             std::vector<double> weight_factors) const override;
+                             std::vector<double> exp_stdv) const override;
 
-    //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors.
+    //! Computes metric value from data arrays. Negative values in exp_data are ignored.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
-    double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> weight_factors) const override;
+    double computeFromArrays(std::vector<double> sim_data,
+                             std::vector<double> exp_data) const override;
 };
 
 //! Implementation of \f$ \chi^2 \f$ metric
@@ -114,15 +102,12 @@ public:
 
     using Chi2Metric::computeFromArrays;
 
-    //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors.
+    //! Computes metric value from data arrays. Negative values in exp_data are ignored.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
-    double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> weight_factors) const override;
+    double computeFromArrays(std::vector<double> sim_data,
+                             std::vector<double> exp_data) const override;
 };
 
 //! Implementation of the standard \f$ \chi^2 \f$ metric with intensity \f$I\f$
@@ -136,26 +121,20 @@ public:
     LogMetric* clone() const override;
 
     //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors and uncertainties.
+    //! are ignored as well as non-positive uncertainties.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
     //! @param exp_stdv: array with experimental data uncertainties.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
     double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> exp_stdv,
-                             std::vector<double> weight_factors) const override;
+                             std::vector<double> exp_stdv) const override;
 
-    //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors.
+    //! Computes metric value from data arrays. Negative values in exp_data are ignored.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
-    double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> weight_factors) const override;
+    double computeFromArrays(std::vector<double> sim_data,
+                             std::vector<double> exp_data) const override;
 };
 
 //! Implementation of relative difference metric.
@@ -170,15 +149,12 @@ public:
 
     using Chi2Metric::computeFromArrays;
 
-    //! Computes metric value from data arrays. Negative values in exp_data
-    //! are ignored as well as non-positive weight_factors.
+    //! Computes metric value from data arrays. Negative values in exp_data are ignored.
     //! All arrays involved in the computation must be of the same size.
     //! @param sim_data: array with simulated intensities.
     //! @param exp_data: array with intensity values obtained from an experiment.
-    //! @param weight_factors: user-defined weighting factors. Used linearly, no matter which norm
-    //! is chosen.
-    double computeFromArrays(std::vector<double> sim_data, std::vector<double> exp_data,
-                             std::vector<double> weight_factors) const override;
+    double computeFromArrays(std::vector<double> sim_data,
+                             std::vector<double> exp_data) const override;
 };
 
 //! Implementation of relative difference metric.
@@ -193,7 +169,7 @@ public:
     //! Computes metric value from SimDataPair object. Calls computeFromArrays internally.
     //! @param data_pair: SimDataPair object. Can optionally contain data uncertainties
     //! @param use_weights: boolean, defines if data uncertainties should be taken into account
-    double compute(const SimDataPair& data_pair, bool use_weights) const override;
+    double computeMetric(const SimDataPair& data_pair, bool use_weights) const override;
 };
 
 #endif // BORNAGAIN_SIM_FITTING_OBJECTIVEMETRIC_H
diff --git a/Sim/Fitting/SimDataPair.cpp b/Sim/Fitting/SimDataPair.cpp
index 51465004a0fd54c4af6de6a97686a67e7b5e8a63..da868d8488c4f6b901347b72a1e6ec304eba033d 100644
--- a/Sim/Fitting/SimDataPair.cpp
+++ b/Sim/Fitting/SimDataPair.cpp
@@ -25,13 +25,6 @@
 
 namespace {
 
-std::unique_ptr<Datafield> initUserWeights(const Datafield& shape, double value)
-{
-    auto result = std::make_unique<Datafield>(shape.frame().clone());
-    result->setAllTo(value);
-    return result;
-}
-
 bool haveSameSizes(const IDetector& detector, const Datafield& data)
 {
     if (data.rank() != 2)
@@ -48,27 +41,35 @@ bool haveSameSizes(const IDetector& detector, const Datafield& data)
 //! User data will be cropped to the ROI defined in the simulation, amplitudes in areas
 //! corresponding to the masked areas of the detector will be set to zero.
 
-Datafield convertData(const ScatteringSimulation& simulation, const Datafield& data)
+Datafield repositionData(const ScatteringSimulation& simulation, const Datafield& data)
 {
     Frame coordSystem = simulation.simCoordSystem();
-    auto roi_data = std::make_unique<Datafield>(coordSystem.clonedAxes());
 
-    if (roi_data->frame().hasSameSizes(data.frame())) {
+    std::vector<double> values(coordSystem.size(), 0.);
+    std::vector<double> errors;
+    if (data.hasErrorSigmas())
+        errors = std::vector<double>(coordSystem.size(), 0.);
+
+    if (coordSystem.hasSameSizes(data.frame())) {
         // data is already cropped to ROI
         simulation.detector().iterateOverNonMaskedPoints([&](IDetector::const_iterator it) {
-            (*roi_data)[it.roiIndex()] = data[it.roiIndex()];
+            values[it.roiIndex()] = data[it.roiIndex()];
+            if (data.hasErrorSigmas())
+                errors[it.roiIndex()] = data.errorSigmas()[it.roiIndex()];
         });
     } else if (haveSameSizes(simulation.detector(), data)) {
         // experimental data has same shape as the detector, we have to copy the original
         // data to a smaller roi map
         simulation.detector().iterateOverNonMaskedPoints([&](IDetector::const_iterator it) {
-            (*roi_data)[it.roiIndex()] = data[it.detectorIndex()];
+            values[it.roiIndex()] = data[it.detectorIndex()];
+            if (data.hasErrorSigmas())
+                errors[it.roiIndex()] = data.errorSigmas()[it.detectorIndex()];
         });
     } else
         throw std::runtime_error(
             "FitObject::init_dataset: Detector and experimental data have different shape");
 
-    return {*roi_data};
+    return Datafield(coordSystem.clonedAxes(), values, errors);
 }
 
 } // namespace
@@ -77,26 +78,11 @@ Datafield convertData(const ScatteringSimulation& simulation, const Datafield& d
 //  class implementation
 //  ************************************************************************************************
 
-SimDataPair::SimDataPair(simulation_builder_t builder, const Datafield& raw_data,
-                         std::unique_ptr<Datafield>&& raw_stdv, double user_weight)
-    : m_simulation_builder(std::move(builder))
-    , m_raw_data(raw_data.clone())
-    , m_raw_uncertainties(std::move(raw_stdv))
-{
-    m_raw_user_weights = initUserWeights(*m_raw_data, user_weight);
-    validate();
-}
-
-SimDataPair::SimDataPair(simulation_builder_t builder, const Datafield& raw_data,
-                         std::unique_ptr<Datafield>&& raw_stdv,
-                         std::unique_ptr<Datafield>&& user_weights)
+SimDataPair::SimDataPair(simulation_builder_t builder, const Datafield& raw_data, double weight)
     : m_simulation_builder(std::move(builder))
     , m_raw_data(raw_data.clone())
-    , m_raw_uncertainties(std::move(raw_stdv))
-    , m_raw_user_weights(std::move(user_weights))
+    , m_weight(weight)
 {
-    if (!m_raw_user_weights)
-        m_raw_user_weights = initUserWeights(*m_raw_data, 1.0);
     validate();
 }
 
@@ -111,67 +97,37 @@ void SimDataPair::execSimulation(const mumufit::Parameters& params)
     m_sim_data = std::make_unique<Datafield>(simulation->simulate());
     ASSERT(!m_sim_data->empty());
 
-    if (m_exp_data && !m_exp_data->empty() && m_uncertainties && !m_uncertainties->empty()
-        && m_user_weights && !m_user_weights->empty())
+    if (m_exp_data) {
+        ASSERT(!m_exp_data->empty());
         return;
+    }
 
     auto* const sim2d = dynamic_cast<ScatteringSimulation*>(simulation.get());
-    if (sim2d) {
-        m_exp_data = std::make_unique<Datafield>(convertData(*sim2d, *m_raw_data));
-        m_user_weights = std::make_unique<Datafield>(convertData(*sim2d, *m_raw_user_weights));
-    } else {
+    if (sim2d)
+        m_exp_data = std::make_unique<Datafield>(repositionData(*sim2d, *m_raw_data));
+    else
         m_exp_data = std::make_unique<Datafield>(*m_raw_data);
-        m_user_weights = std::make_unique<Datafield>(*m_raw_user_weights);
-    }
-
-    if (sim2d && containsUncertainties())
-        m_uncertainties = std::make_unique<Datafield>(convertData(*sim2d, *m_raw_uncertainties));
-    else {
-        const Frame& frame = m_sim_data->frame();
-        auto dummy_array = std::make_unique<Datafield>(frame.clonedAxes());
-        m_uncertainties = std::make_unique<Datafield>(*dummy_array);
-    }
 }
 
 bool SimDataPair::containsUncertainties() const
 {
-    return static_cast<bool>(m_raw_uncertainties);
+    return m_raw_data->hasErrorSigmas();
 }
 
 Datafield SimDataPair::simulationResult() const
 {
-    if (!m_sim_data)
-        throw std::runtime_error("SimDataPair::simulationResult() called before sim_data were set");
+    ASSERT(m_sim_data);
     ASSERT(!m_sim_data->empty());
     return *m_sim_data;
 }
 
 Datafield SimDataPair::experimentalData() const
 {
-    if (!m_exp_data)
-        throw std::runtime_error("SimDataPair::experimentalData() called before exp_data were set");
+    ASSERT(m_exp_data);
     ASSERT(!m_exp_data->empty());
     return *m_exp_data;
 }
 
-Datafield SimDataPair::uncertainties() const
-{
-    if (!m_uncertainties)
-        throw std::runtime_error(
-            "SimDataPair::uncertainties() called before uncertainties were set");
-    ASSERT(!m_uncertainties->empty());
-    return *m_uncertainties;
-}
-
-//! Returns the user uncertainties cut to the ROI area.
-Datafield SimDataPair::userWeights() const
-{
-    if (!m_user_weights)
-        throw std::runtime_error("SimDataPair::userWeights() called before user_weights were set");
-    ASSERT(!m_user_weights->empty());
-    return *m_user_weights;
-}
-
 std::vector<double> SimDataPair::simulation_array() const
 {
     return simulationResult().flatVector();
@@ -184,12 +140,8 @@ std::vector<double> SimDataPair::experimental_array() const
 
 std::vector<double> SimDataPair::uncertainties_array() const
 {
-    return uncertainties().flatVector();
-}
-
-std::vector<double> SimDataPair::user_weights_array() const
-{
-    return userWeights().flatVector();
+    ASSERT(m_exp_data);
+    return m_exp_data->errorSigmas();
 }
 
 //! Returns relative difference between simulation and experimental data.
@@ -231,12 +183,4 @@ void SimDataPair::validate() const
 
     if (!m_raw_data)
         throw std::runtime_error("Error in SimDataPair: passed experimental data array is empty");
-
-    if (m_raw_uncertainties && m_raw_uncertainties->frame() != m_raw_data->frame())
-        throw std::runtime_error(
-            "Error in SimDataPair: experimental data and uncertainties have different shape.");
-
-    if (!m_raw_user_weights || m_raw_user_weights->frame() != m_raw_data->frame())
-        throw std::runtime_error(
-            "Error in SimDataPair: user weights are not initialized or have invalid shape");
 }
diff --git a/Sim/Fitting/SimDataPair.h b/Sim/Fitting/SimDataPair.h
index dcc9731d5c370da0f1ead9969fc4d0ae72ef8cca..be23af0419fa5cd5257ac51e76d430276defb0fa 100644
--- a/Sim/Fitting/SimDataPair.h
+++ b/Sim/Fitting/SimDataPair.h
@@ -20,18 +20,13 @@
 
 #include "Sim/Fitting/FitTypes.h"
 
-class Datafield;
 class Datafield;
 
 //! Holds pair of simulation/experimental data to fit.
 
 class SimDataPair {
 public:
-    SimDataPair(simulation_builder_t builder, const Datafield& raw_data,
-                std::unique_ptr<Datafield>&& raw_stdv, double user_weight = 1.0);
-
-    SimDataPair(simulation_builder_t builder, const Datafield& raw_data,
-                std::unique_ptr<Datafield>&& raw_stdv, std::unique_ptr<Datafield>&& user_weights);
+    SimDataPair(simulation_builder_t builder, const Datafield& raw_data, double weight = 1.0);
 
     SimDataPair(SimDataPair&& other) noexcept;
 
@@ -47,13 +42,6 @@ public:
     //! Returns the experimental data cut to the ROI area
     Datafield experimentalData() const;
 
-    //! Returns the data uncertainties cut to the ROI area
-    //! If no uncertainties present, returns zero-filled Datafield.
-    Datafield uncertainties() const;
-
-    //! Returns the user uncertainties cut to the ROI area.
-    Datafield userWeights() const;
-
     //! Returns the relative difference between simulated
     //! and experimental data cut to the ROI area
     Datafield relativeDifference() const;
@@ -73,30 +61,23 @@ public:
     //! Returns a zero-filled array sized to the ROI area.
     std::vector<double> uncertainties_array() const;
 
-    //! Returns a flat array of user weights cut to the ROI area.
-    std::vector<double> user_weights_array() const;
+    double weight() const { return m_weight; }
 
 private:
     void validate() const;
 
     //! ISimulation builder from the user to construct simulation for given set of parameters.
     simulation_builder_t m_simulation_builder;
+    //! Raw experimental data as obtained from the user.
+    std::unique_ptr<Datafield> m_raw_data;
+    //! Weight in multidata fitting
+    double m_weight;
 
     //! Current simulation results. Masked areas are nullified.
     std::unique_ptr<Datafield> m_sim_data;
+
     //! Experimental data cut to the ROI. Masked areas are nullified.
     std::unique_ptr<Datafield> m_exp_data;
-    //! Weights from experimental data uncertainties. Masked areas are nullified.
-    std::unique_ptr<Datafield> m_uncertainties;
-    //! Manually defined (user) weights. Masked areas are nullified.
-    std::unique_ptr<Datafield> m_user_weights;
-
-    //! Raw experimental data as obtained from the user.
-    std::unique_ptr<Datafield> m_raw_data;
-    //! Data uncertainties as provided by the user
-    std::unique_ptr<Datafield> m_raw_uncertainties;
-    //! User-defined weights
-    std::unique_ptr<Datafield> m_raw_user_weights;
 };
 
 #endif // BORNAGAIN_SIM_FITTING_SIMDATAPAIR_H
diff --git a/Sim/Residual/ChiSquaredModule.cpp b/Sim/Residual/ChiSquaredModule.cpp
index 0d8e2f998e7188599c96fddfd3244247187ad082..ed9404a7e45627c6e4536546967f31d3a6b1a5e7 100644
--- a/Sim/Residual/ChiSquaredModule.cpp
+++ b/Sim/Residual/ChiSquaredModule.cpp
@@ -19,7 +19,7 @@
 #include <cmath>
 #include <limits>
 
-double ChiSquaredModule::residual(double a, double b, double weight)
+double ChiSquaredModule::residual(double a, double b)
 {
     double value_simu = a;
     double value_real = b;
@@ -32,5 +32,5 @@ double ChiSquaredModule::residual(double a, double b, double weight)
     double variance = m_variance_function->variance(value_real, value_simu);
     double normalize = variance <= 0 ? std::numeric_limits<double>::min() : std::sqrt(variance);
 
-    return std::sqrt(weight) * (value_simu - value_real) / normalize;
+    return /*std::sqrt(weight) * */ (value_simu - value_real) / normalize;
 }
diff --git a/Sim/Residual/ChiSquaredModule.h b/Sim/Residual/ChiSquaredModule.h
index 70eec8db79da1b9ee976213218626b668b171a11..cf4586e10ecdc70b9ffa0affd76c21070e09703f 100644
--- a/Sim/Residual/ChiSquaredModule.h
+++ b/Sim/Residual/ChiSquaredModule.h
@@ -27,7 +27,7 @@ public:
 
     ChiSquaredModule* clone() const override { return new ChiSquaredModule(*this); }
 
-    double residual(double a, double b, double weight) override;
+    double residual(double a, double b) override;
 };
 
 #endif // BORNAGAIN_SIM_RESIDUAL_CHISQUAREDMODULE_H
diff --git a/Sim/Residual/IChiSquaredModule.h b/Sim/Residual/IChiSquaredModule.h
index 4b4b0d11f3b60f3d9afc13928feb843f6803b1a1..5107c94900b8f14c2f9553ef16034c5f765ffe36 100644
--- a/Sim/Residual/IChiSquaredModule.h
+++ b/Sim/Residual/IChiSquaredModule.h
@@ -43,7 +43,7 @@ public:
     //! Sets data rescaler.
     virtual void setIntensityFunction(const IIntensityFunction& intensity_function);
 
-    virtual double residual(double a, double b, double weight) = 0;
+    virtual double residual(double a, double b) = 0;
 
 protected:
     IChiSquaredModule(const IChiSquaredModule& other);
diff --git a/Tests/Functional/Fitting/FitTests.cpp b/Tests/Functional/Fitting/FitTests.cpp
index 54c50a1414fd922b2a997941475d889f243900ab..53aae7586f869d9172bd89e3418d588990e8554a 100644
--- a/Tests/Functional/Fitting/FitTests.cpp
+++ b/Tests/Functional/Fitting/FitTests.cpp
@@ -136,8 +136,8 @@ public:
     std::unique_ptr<FitObjective> createFitObjective() const override
     {
         std::unique_ptr<FitObjective> result(new FitObjective);
-        result->execAddSimulationAndData(m_sim_builder, *fakeData(), nullptr, 0.5);
-        result->execAddSimulationAndData(m_sim_builder, *fakeData(), nullptr, 0.5);
+        result->execAddSimulationAndData(m_sim_builder, *fakeData(), 0.5);
+        result->execAddSimulationAndData(m_sim_builder, *fakeData(), 0.5);
         result->initPrint(1);
         return result;
     }
diff --git a/Tests/Functional/Fitting/SimfitTestPlan.cpp b/Tests/Functional/Fitting/SimfitTestPlan.cpp
index 33d2e491a710ed34456821f04a8c528afa45725b..58538797e32884befc5505d631fcdc056929e224 100644
--- a/Tests/Functional/Fitting/SimfitTestPlan.cpp
+++ b/Tests/Functional/Fitting/SimfitTestPlan.cpp
@@ -54,7 +54,7 @@ std::unique_ptr<FitObjective> SimfitTestPlan::createFitObjective() const
 {
     std::unique_ptr<FitObjective> result(new FitObjective);
 
-    result->execAddSimulationAndData(m_sim_builder, *fakeData(), nullptr, 1.0);
+    result->execAddSimulationAndData(m_sim_builder, *fakeData(), 1.0);
     result->initPrint(1);
 
     return result;
diff --git a/Tests/Py/Fit/fitobjective_api.py b/Tests/Py/Fit/fitobjective_api.py
index e88aa75c3df267586ed7efc7af077b6eb53cd35a..50d3ba35e7dc98d641dc0b5f6421461279398f33 100644
--- a/Tests/Py/Fit/fitobjective_api.py
+++ b/Tests/Py/Fit/fitobjective_api.py
@@ -79,8 +79,8 @@ class FitObjectiveAPITest(unittest.TestCase):
         for _ in range(0, builder.size()):
             expected_sim.append(0)
             expected_data.append(1)
-        self.assertEqual(expected_sim, list(objective.simulation_array()))
-        self.assertEqual(expected_data, list(objective.experimental_array()))
+        self.assertEqual(expected_sim, list(objective.flatSimData()))
+        self.assertEqual(expected_data, list(objective.flatExpData()))
 
     def test_FittingObserver(self):
         """
diff --git a/Tests/Unit/Sim/FitObjectiveTest.cpp b/Tests/Unit/Sim/FitObjectiveTest.cpp
index 3a30376ab6741db31129beedd467cf23aa449957..22ef57a03dba801bc37c8d5b387b149b0192ea7b 100644
--- a/Tests/Unit/Sim/FitObjectiveTest.cpp
+++ b/Tests/Unit/Sim/FitObjectiveTest.cpp
@@ -23,8 +23,8 @@ TEST(FitObjectiveTest, twoDatasets)
 
     // creating FitObjective with two simulation/data pairs.
     FitObjective objective;
-    objective.execAddSimulationAndData(builder1, *data1, nullptr);
-    objective.execAddSimulationAndData(builder2, *data2, nullptr);
+    objective.execAddSimulationAndData(builder1, *data1);
+    objective.execAddSimulationAndData(builder2, *data2);
 
     // running simulation once
     mumufit::Parameters params;
@@ -35,5 +35,5 @@ TEST(FitObjectiveTest, twoDatasets)
     std::vector<double> expected_exp2(helper2.size(), exp_value2);
     expected_exp1.insert(expected_exp1.end(), expected_exp2.begin(), expected_exp2.end());
 
-    EXPECT_EQ(expected_exp1, objective.experimental_array());
+    EXPECT_EQ(expected_exp1, objective.flatExpData());
 }
diff --git a/Tests/Unit/Sim/ObjectiveMetricTest.cpp b/Tests/Unit/Sim/ObjectiveMetricTest.cpp
index b392f64848c3f3530234cb3eedc6963488ce4fca..4122b503982227858f55fd0ca7399c028e547ca0 100644
--- a/Tests/Unit/Sim/ObjectiveMetricTest.cpp
+++ b/Tests/Unit/Sim/ObjectiveMetricTest.cpp
@@ -3,308 +3,103 @@
 #include "Tests/GTestWrapper/google_test.h"
 #include <cmath>
 
-TEST(ObjectiveMetricTest, Chi2WellFormed)
+TEST(ObjectiveMetricTest, Chi2)
 {
     std::vector<double> sim_data{1.0, 2.0, 3.0, 4.0};
     std::vector<double> exp_data{2.0, 1.0, 4.0, 3.0};
     std::vector<double> uncertainties{0.1, 0.1, 0.5, 0.5};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
 
     Chi2Metric metric;
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, uncertainties, weight_factors),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, weight_factors), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     212.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0);
-
-    std::vector<double> exp_data_1 = exp_data;
-    exp_data_1[0] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, uncertainties, weight_factors),
-                     112.0);
-
-    std::vector<double> uncertainties_1 = uncertainties;
-    uncertainties_1[3] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     204.0);
-    uncertainties_1[3] = 0.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     204.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, uncertainties), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties), 208.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0);
 
     metric.setNorm(ObjectiveMetricUtil::l1Norm());
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     26.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0);
-
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}, {}), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}), 0.0);
-}
-
-TEST(ObjectiveMetricTest, Chi2IllFormed)
-{
-    std::vector<double> sim_data{1.0, 2.0, 3.0, 4.0};
-    std::vector<double> exp_data{2.0, 1.0, 4.0, 3.0};
-    std::vector<double> uncertainties{0.1, 0.1, 0.5, 0.5};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
-
-    Chi2Metric metric;
-
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {}, {1.0}), std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {1.0}), std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data, exp_data, {}, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, exp_data, weight_factors), std::runtime_error);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = -1.0;
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, uncertainties, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, weight_factors),
-                 std::runtime_error);
-
-    std::vector<double> weight_factors_1(weight_factors.size(), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors_1),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors_1), 0.0);
-
-    std::vector<double> uncertainties_1 = uncertainties;
-    uncertainties_1[0] = std::numeric_limits<double>::min();
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     std::numeric_limits<double>::max());
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties), 24.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0);
 }
 
-TEST(ObjectiveMetricTest, PoissionLikeWellFormed)
+TEST(ObjectiveMetricTest, PoissionLike)
 {
     std::vector<double> sim_data{1.0, 2.0, 4.0, 4.0};
     std::vector<double> exp_data{2.0, 1.0, 5.0, 3.0};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
 
     PoissonLikeMetric metric;
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, weight_factors), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 2.25);
-
-    std::vector<double> exp_data_1 = exp_data;
-    exp_data_1[0] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, weight_factors), 1.25);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = 0.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data_1, exp_data, weight_factors), 5.25);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 2.);
 
     metric.setNorm(ObjectiveMetricUtil::l1Norm());
 
     std::vector<double> sim_data_2 = sim_data;
     sim_data_2[1] = 1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data_2, exp_data, weight_factors), 2.5);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data_2, exp_data), 2.);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}, {}), 0.0);
     EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}), 0.0);
 }
 
-TEST(ObjectiveMetricTest, PoissionLikeIllFormed)
-{
-    std::vector<double> sim_data{1.0, 2.0, 3.0, 4.0};
-    std::vector<double> exp_data{2.0, 1.0, 4.0, 3.0};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
-
-    PoissonLikeMetric metric;
-
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {}, {1.0}), std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {1.0}), std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data, exp_data, {}, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, exp_data, weight_factors), std::runtime_error);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = -1.0;
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, weight_factors),
-                 std::runtime_error);
-
-    std::vector<double> weight_factors_1(weight_factors.size(), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors_1), 0.0);
-}
-
-TEST(ObjectiveMetricTest, LogWellFormed)
+TEST(ObjectiveMetricTest, Log)
 {
     std::vector<double> sim_data{1.0, 10.0, 1e2, 1e4};
     std::vector<double> exp_data{10.0, 1.0, 1e3, 1e5};
     std::vector<double> uncertainties{0.1, 0.1, 0.5, 0.5};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
 
     LogMetric metric;
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, uncertainties, weight_factors),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, weight_factors), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     8.00040101e10 * std::log(10.0) * std::log(10.0));
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0);
-
-    std::vector<double> exp_data_1 = exp_data;
-    exp_data_1[0] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, uncertainties, weight_factors),
-                     8.00040001e10 * std::log(10.0) * std::log(10.0));
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, weight_factors), 4.0);
-
-    std::vector<double> uncertainties_1 = uncertainties;
-    uncertainties_1[3] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     4.0101e6 * std::log(10.0) * std::log(10.0));
-    uncertainties_1[3] = 0.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     4.0101e6 * std::log(10.0) * std::log(10.0));
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, uncertainties), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data), 0.0);
+    EXPECT_NEAR(metric.computeFromArrays(sim_data, exp_data, uncertainties), 2.12097e11, 1e6);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0);
 
     metric.setNorm(ObjectiveMetricUtil::l1Norm());
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     4.0211e5 * std::log(10.0));
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0);
+    EXPECT_NEAR(metric.computeFromArrays(sim_data, exp_data, uncertainties), 465375, 0.5);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}, {}), 0.0);
     EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}), 0.0);
 }
 
-TEST(ObjectiveMetricTest, LogIllFormed)
-{
-    std::vector<double> sim_data{1.0, 10.0, 1e2, 1e4};
-    std::vector<double> exp_data{10.0, 1.0, 1e3, 1e5};
-    std::vector<double> uncertainties{0.1, 0.1, 0.5, 0.5};
-    std::vector<double> weight_factors{1.0, 1.0, 1.0, 2.0};
-
-    LogMetric metric;
-
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {}, {1.0}), std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, {}, {1.0}), std::runtime_error);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = -1.0;
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, uncertainties, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, weight_factors),
-                 std::runtime_error);
-
-    std::vector<double> weight_factors_1(weight_factors.size(), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors_1),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors_1), 0.0);
-
-    std::vector<double> uncertainties_1 = uncertainties;
-    uncertainties_1[0] = std::numeric_limits<double>::min();
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties_1, weight_factors),
-                     std::numeric_limits<double>::max());
-}
-
-TEST(ObjectiveMetricTest, meanRelativeDifferenceWellFormed)
+TEST(ObjectiveMetricTest, meanRelativeDifference)
 {
     std::vector<double> sim_data{1.0, 2.0, 4.0, 4.0};
     std::vector<double> exp_data{2.0, 1.0, 2.0, 2.0};
     std::vector<double> uncertainties{1.0, 1.0, 2.0, 1.0};
-    std::vector<double> weight_factors{1.0, 1.0, 2.0, 1.0};
 
     meanRelativeDifferenceMetric metric;
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, weight_factors), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0 / 9.0);
-
-    std::vector<double> exp_data_1 = exp_data;
-    exp_data_1[0] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, weight_factors), 4.0 / 9.0);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = 0.0;
-    exp_data_1[0] = 0.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data_1, exp_data_1, weight_factors), 4.0 / 9.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0 / 9);
 
     metric.setNorm(ObjectiveMetricUtil::l1Norm());
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 5.0 / 3.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 4.0 / 3);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     6.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties), 5.0);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}, {}), 0.0);
     EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}), 0.0);
 }
 
-TEST(ObjectiveMetricTest, meanRelativeDifferenceIllFormed)
-{
-    std::vector<double> sim_data{1.0, 2.0, 4.0, 4.0};
-    std::vector<double> exp_data{2.0, 1.0, 3.0, 2.0};
-    std::vector<double> uncertainties{1.0, 1.0, 2.0, 1.0};
-    std::vector<double> weight_factors{1.0, 1.0, 2.0, 1.0};
-
-    meanRelativeDifferenceMetric metric;
-
-    EXPECT_THROW(metric.computeFromArrays(sim_data, {}, uncertainties, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data, {}, weight_factors), std::runtime_error);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = -1.0;
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, uncertainties, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, weight_factors),
-                 std::runtime_error);
-
-    std::vector<double> weight_factors_1(weight_factors.size(), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors_1),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors_1), 0.0);
-}
-
-TEST(ObjectiveMetricTest, RQ4WellFormed)
+TEST(ObjectiveMetricTest, RQ4)
 {
     std::vector<double> sim_data{1.0, 2.0, 4.0, 4.0};
     std::vector<double> exp_data{2.0, 1.0, 2.0, 2.0};
     std::vector<double> uncertainties{1.0, 1.0, 2.0, 1.0};
-    std::vector<double> weight_factors{1.0, 1.0, 2.0, 1.0};
 
     RQ4Metric metric;
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data, weight_factors), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 14.0);
-
-    std::vector<double> exp_data_1 = exp_data;
-    exp_data_1[0] = -1.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data_1, weight_factors), 13.0);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = 0.0;
-    exp_data_1[0] = 0.0;
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data_1, exp_data_1, weight_factors), 13.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, sim_data), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 10.0);
 
     metric.setNorm(ObjectiveMetricUtil::l1Norm());
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors), 8.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data), 6.0);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors),
-                     6.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties), 5.0);
 
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}, {}), 0.0);
     EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}, {}), 0.0);
-}
-
-TEST(ObjectiveMetricTest, RQ4IllFormed)
-{
-    std::vector<double> sim_data{1.0, 2.0, 4.0, 4.0};
-    std::vector<double> exp_data{2.0, 1.0, 3.0, 2.0};
-    std::vector<double> uncertainties{1.0, 1.0, 2.0, 1.0};
-    std::vector<double> weight_factors{1.0, 1.0, 2.0, 1.0};
-
-    RQ4Metric metric;
-
-    EXPECT_THROW(metric.computeFromArrays(sim_data, exp_data, {}, weight_factors),
-                 std::runtime_error);
-    EXPECT_THROW(metric.computeFromArrays({}, exp_data, weight_factors), std::runtime_error);
-
-    std::vector<double> sim_data_1 = sim_data;
-    sim_data_1[0] = -1.0;
-    EXPECT_THROW(metric.computeFromArrays(sim_data_1, exp_data, uncertainties, weight_factors),
-                 std::runtime_error);
-
-    std::vector<double> weight_factors_1(weight_factors.size(), 0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, uncertainties, weight_factors_1),
-                     0.0);
-    EXPECT_DOUBLE_EQ(metric.computeFromArrays(sim_data, exp_data, weight_factors_1), 0.0);
+    EXPECT_DOUBLE_EQ(metric.computeFromArrays({}, {}), 0.0);
 }
 
 TEST(ObjectiveMetricTest, createMetric)
diff --git a/Tests/Unit/Sim/SimDataPairTest.cpp b/Tests/Unit/Sim/SimDataPairTest.cpp
index 6d693bbd38b6106276e03ff0e580ecb6adbc892b..0c005bf9efb84603b3e1ebb454a02c9709b25df9 100644
--- a/Tests/Unit/Sim/SimDataPairTest.cpp
+++ b/Tests/Unit/Sim/SimDataPairTest.cpp
@@ -15,11 +15,10 @@ TEST(SimDataPairTest, standardPair)
     const double exp_value(10.0);
     const double dataset_weight(0.5);
 
-    SimDataPair obj(builder, *helper.createTestData(exp_value), nullptr, dataset_weight);
+    SimDataPair obj(builder, *helper.createTestData(exp_value), dataset_weight);
 
     // default state, no simulation has been called yet
     EXPECT_THROW(obj.uncertainties_array(), std::runtime_error);
-    EXPECT_THROW(obj.user_weights_array(), std::runtime_error);
     EXPECT_THROW(obj.simulation_array(), std::runtime_error);
     EXPECT_THROW(obj.experimental_array(), std::runtime_error);
     EXPECT_THROW(obj.simulationResult(), std::runtime_error);
@@ -55,9 +54,8 @@ TEST(SimDataPairTest, move)
     };
 
     const double exp_value(10.0);
-    const double dataset_weight(0.5);
 
-    SimDataPair obj(builder, *helper.createTestData(exp_value), nullptr, dataset_weight);
+    SimDataPair obj(builder, *helper.createTestData(exp_value), 0.5);
     // calling builder once
     mumufit::Parameters params;
     EXPECT_EQ(helper.m_builder_calls, 0u);
diff --git a/Wrap/Python/ba_fitmonitor.py b/Wrap/Python/ba_fitmonitor.py
index 4e7e5cd6106b1e0103a09fdefb542a3e37e66fde..b199be1f11ca4f314e0b7db7bef9abd26b12d233 100644
--- a/Wrap/Python/ba_fitmonitor.py
+++ b/Wrap/Python/ba_fitmonitor.py
@@ -152,12 +152,11 @@ class PlotterSpecular:
         # retrieving data from fit suite
         exp_data = fit_objective.experimentalData()
         sim_data = fit_objective.simulationResult()
-        unc_data = fit_objective.uncertaintyData()
 
         # data values
         sim_values = sim_data.npArray()
         exp_values = exp_data.npArray()
-        unc_values = None if unc_data is None else unc_data.npArray()
+        unc_values = exp_data.npErrors()
 
         # default font properties dictionary to use
         font = { 'size': 16 }
diff --git a/Wrap/Swig/libBornAgainSim.i b/Wrap/Swig/libBornAgainSim.i
index 0109f115fae695c3135a2ab7244106330927b049..be08a16266f4e2ab3f9d61c3026c300f7ed11f79 100644
--- a/Wrap/Swig/libBornAgainSim.i
+++ b/Wrap/Swig/libBornAgainSim.i
@@ -223,24 +223,5 @@ class ObserverCallbackWrapper(PyObserverCallback):
     def initPlot(self, every_nth, callback):
         self.wrp_plot_observer = ObserverCallbackWrapper(callback)
         return self.initPlot_cpp(every_nth, self.wrp_plot_observer)
-
-    def uncertainties(self):
-        """
-        Returns one-dimensional array representing merged data uncertainties.
-        If any of the associated data pairs lack uncertainties, returns None.
-        """
-        if self.allPairsHaveUncertainties_cpp():
-            return self.uncertainties_cpp()
-        return None
-
-    def uncertaintyData(self, i=0):
-        """
-        Returns uncertainties for i-th simulation-data pair. If
-        no uncertainties are assigned to the data pair, returns
-        None.
-        """
-        if self.containsUncertainties_cpp(i):
-            return self.uncertaintyData_cpp(i)
-        return None
 %}
 };
diff --git a/auto/Examples/fit/scatter2d/custom_objective_function.py b/auto/Examples/fit/scatter2d/custom_objective_function.py
index a316fe9ff3d353193fadd180ef61f008e327577d..bde5d2abe244199b63d66f25a9e8a5dd98c4730c 100755
--- a/auto/Examples/fit/scatter2d/custom_objective_function.py
+++ b/auto/Examples/fit/scatter2d/custom_objective_function.py
@@ -24,8 +24,8 @@ class MyObjective(ba.FitObjective):
 
         # accessing simulated and experimental data as flat numpy arrays
         # applying sqrt to every element
-        sim = np.sqrt(np.asarray(self.simulation_array()))
-        exp = np.sqrt(np.asarray(self.experimental_array()))
+        sim = np.sqrt(np.asarray(self.flatSimData()))
+        exp = np.sqrt(np.asarray(self.flatExpData()))
 
         # return vector of residuals
         return sim - exp
diff --git a/auto/MiniExamples/fit/scatter2d/custom_objective_function.py b/auto/MiniExamples/fit/scatter2d/custom_objective_function.py
index a316fe9ff3d353193fadd180ef61f008e327577d..bde5d2abe244199b63d66f25a9e8a5dd98c4730c 100755
--- a/auto/MiniExamples/fit/scatter2d/custom_objective_function.py
+++ b/auto/MiniExamples/fit/scatter2d/custom_objective_function.py
@@ -24,8 +24,8 @@ class MyObjective(ba.FitObjective):
 
         # accessing simulated and experimental data as flat numpy arrays
         # applying sqrt to every element
-        sim = np.sqrt(np.asarray(self.simulation_array()))
-        exp = np.sqrt(np.asarray(self.experimental_array()))
+        sim = np.sqrt(np.asarray(self.flatSimData()))
+        exp = np.sqrt(np.asarray(self.flatExpData()))
 
         # return vector of residuals
         return sim - exp
diff --git a/auto/Wrap/libBornAgainDevice.py b/auto/Wrap/libBornAgainDevice.py
index 81641c33be0003db76a142efaf3916be7cc774d8..fcd2b4c12bdf9cf099433bbc6a984ea2c08555c0 100644
--- a/auto/Wrap/libBornAgainDevice.py
+++ b/auto/Wrap/libBornAgainDevice.py
@@ -2093,6 +2093,10 @@ class Datafield(object):
         r"""npArray(Datafield self) -> PyObject *"""
         return _libBornAgainDevice.Datafield_npArray(self)
 
+    def npErrors(self):
+        r"""npErrors(Datafield self) -> PyObject *"""
+        return _libBornAgainDevice.Datafield_npErrors(self)
+
     def frame(self):
         r"""frame(Datafield self) -> Frame"""
         return _libBornAgainDevice.Datafield_frame(self)
diff --git a/auto/Wrap/libBornAgainDevice_wrap.cpp b/auto/Wrap/libBornAgainDevice_wrap.cpp
index a2b67fac7c32f0e1e08036ba2863bb07c0f64ce4..e8cd0ec2047165f0c788cc6ccf8921bcd372668b 100644
--- a/auto/Wrap/libBornAgainDevice_wrap.cpp
+++ b/auto/Wrap/libBornAgainDevice_wrap.cpp
@@ -29712,6 +29712,39 @@ fail:
 }
 
 
+SWIGINTERN PyObject *_wrap_Datafield_npErrors(PyObject *self, PyObject *args) {
+  PyObject *resultobj = 0;
+  Datafield *arg1 = (Datafield *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  PyObject *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_Datafield, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "Datafield_npErrors" "', argument " "1"" of type '" "Datafield const *""'"); 
+  }
+  arg1 = reinterpret_cast< Datafield * >(argp1);
+  {
+    try {
+      result = (PyObject *)((Datafield const *)arg1)->npErrors();
+    } catch (const std::exception& ex) {
+      // message shown in the Python interpreter
+      const std::string msg {
+        "BornAgain C++ Exception: " + std::string(ex.what())
+      };
+      SWIG_exception(SWIG_RuntimeError, msg.c_str());
+    }
+  }
+  resultobj = result;
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
 SWIGINTERN PyObject *_wrap_Datafield_frame(PyObject *self, PyObject *args) {
   PyObject *resultobj = 0;
   Datafield *arg1 = (Datafield *) 0 ;
@@ -40895,6 +40928,7 @@ static PyMethodDef SwigMethods[] = {
 	 { "Datafield_setAt", _wrap_Datafield_setAt, METH_VARARGS, "Datafield_setAt(Datafield self, size_t i, double val)"},
 	 { "Datafield_valAt", _wrap_Datafield_valAt, METH_VARARGS, "Datafield_valAt(Datafield self, size_t i) -> double"},
 	 { "Datafield_npArray", _wrap_Datafield_npArray, METH_O, "Datafield_npArray(Datafield self) -> PyObject *"},
+	 { "Datafield_npErrors", _wrap_Datafield_npErrors, METH_O, "Datafield_npErrors(Datafield self) -> PyObject *"},
 	 { "Datafield_frame", _wrap_Datafield_frame, METH_O, "Datafield_frame(Datafield self) -> Frame"},
 	 { "Datafield_rank", _wrap_Datafield_rank, METH_O, "Datafield_rank(Datafield self) -> size_t"},
 	 { "Datafield_axis", _wrap_Datafield_axis, METH_VARARGS, "Datafield_axis(Datafield self, size_t k) -> Scale"},
diff --git a/auto/Wrap/libBornAgainSim.py b/auto/Wrap/libBornAgainSim.py
index 7633bbcc0a9167d865cfee12558ddcd6720d2fd5..362d2f641d680809c21cb8e35930e66a0317014d 100644
--- a/auto/Wrap/libBornAgainSim.py
+++ b/auto/Wrap/libBornAgainSim.py
@@ -2360,10 +2360,6 @@ class FitObjective(object):
         r"""experimentalData(FitObjective self, size_t i_item=0) -> Datafield"""
         return _libBornAgainSim.FitObjective_experimentalData(self, i_item)
 
-    def uncertaintyData_cpp(self, i_item=0):
-        r"""uncertaintyData_cpp(FitObjective self, size_t i_item=0) -> Datafield"""
-        return _libBornAgainSim.FitObjective_uncertaintyData_cpp(self, i_item)
-
     def relativeDifference(self, i_item=0):
         r"""relativeDifference(FitObjective self, size_t i_item=0) -> Datafield"""
         return _libBornAgainSim.FitObjective_relativeDifference(self, i_item)
@@ -2372,21 +2368,13 @@ class FitObjective(object):
         r"""absoluteDifference(FitObjective self, size_t i_item=0) -> Datafield"""
         return _libBornAgainSim.FitObjective_absoluteDifference(self, i_item)
 
-    def experimental_array(self):
-        r"""experimental_array(FitObjective self) -> vdouble1d_t"""
-        return _libBornAgainSim.FitObjective_experimental_array(self)
-
-    def simulation_array(self):
-        r"""simulation_array(FitObjective self) -> vdouble1d_t"""
-        return _libBornAgainSim.FitObjective_simulation_array(self)
-
-    def uncertainties_cpp(self):
-        r"""uncertainties_cpp(FitObjective self) -> vdouble1d_t"""
-        return _libBornAgainSim.FitObjective_uncertainties_cpp(self)
+    def flatExpData(self):
+        r"""flatExpData(FitObjective self) -> vdouble1d_t"""
+        return _libBornAgainSim.FitObjective_flatExpData(self)
 
-    def weights_array(self):
-        r"""weights_array(FitObjective self) -> vdouble1d_t"""
-        return _libBornAgainSim.FitObjective_weights_array(self)
+    def flatSimData(self):
+        r"""flatSimData(FitObjective self) -> vdouble1d_t"""
+        return _libBornAgainSim.FitObjective_flatSimData(self)
 
     def initPrint(self, every_nth):
         r"""initPrint(FitObjective self, int every_nth)"""
@@ -2495,25 +2483,6 @@ class FitObjective(object):
         self.wrp_plot_observer = ObserverCallbackWrapper(callback)
         return self.initPlot_cpp(every_nth, self.wrp_plot_observer)
 
-    def uncertainties(self):
-        """
-        Returns one-dimensional array representing merged data uncertainties.
-        If any of the associated data pairs lack uncertainties, returns None.
-        """
-        if self.allPairsHaveUncertainties_cpp():
-            return self.uncertainties_cpp()
-        return None
-
-    def uncertaintyData(self, i=0):
-        """
-        Returns uncertainties for i-th simulation-data pair. If
-        no uncertainties are assigned to the data pair, returns
-        None.
-        """
-        if self.containsUncertainties_cpp(i):
-            return self.uncertaintyData_cpp(i)
-        return None
-
     def __disown__(self):
         self.this.disown()
         _libBornAgainSim.disown_FitObjective(self)
@@ -3019,9 +2988,9 @@ class IChiSquaredModule(libBornAgainBase.ICloneable):
         r"""setIntensityFunction(IChiSquaredModule self, IIntensityFunction intensity_function)"""
         return _libBornAgainSim.IChiSquaredModule_setIntensityFunction(self, intensity_function)
 
-    def residual(self, a, b, weight):
-        r"""residual(IChiSquaredModule self, double a, double b, double weight) -> double"""
-        return _libBornAgainSim.IChiSquaredModule_residual(self, a, b, weight)
+    def residual(self, a, b):
+        r"""residual(IChiSquaredModule self, double a, double b) -> double"""
+        return _libBornAgainSim.IChiSquaredModule_residual(self, a, b)
 
 # Register IChiSquaredModule in _libBornAgainSim:
 _libBornAgainSim.IChiSquaredModule_swigregister(IChiSquaredModule)
@@ -3043,9 +3012,9 @@ class ChiSquaredModule(IChiSquaredModule):
         r"""clone(ChiSquaredModule self) -> ChiSquaredModule"""
         return _libBornAgainSim.ChiSquaredModule_clone(self)
 
-    def residual(self, a, b, weight):
-        r"""residual(ChiSquaredModule self, double a, double b, double weight) -> double"""
-        return _libBornAgainSim.ChiSquaredModule_residual(self, a, b, weight)
+    def residual(self, a, b):
+        r"""residual(ChiSquaredModule self, double a, double b) -> double"""
+        return _libBornAgainSim.ChiSquaredModule_residual(self, a, b)
 
 # Register ChiSquaredModule in _libBornAgainSim:
 _libBornAgainSim.ChiSquaredModule_swigregister(ChiSquaredModule)
diff --git a/auto/Wrap/libBornAgainSim_wrap.cpp b/auto/Wrap/libBornAgainSim_wrap.cpp
index f6a1ae0cf32ec71ea7d2e47891d3e20c726210f3..9b24701c98c2578ea2d2fc75afe8561a62b02a22 100644
--- a/auto/Wrap/libBornAgainSim_wrap.cpp
+++ b/auto/Wrap/libBornAgainSim_wrap.cpp
@@ -32902,118 +32902,6 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FitObjective_uncertaintyData_cpp__SWIG_0(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {
-  PyObject *resultobj = 0;
-  FitObjective *arg1 = (FitObjective *) 0 ;
-  size_t arg2 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  size_t val2 ;
-  int ecode2 = 0 ;
-  SwigValueWrapper< Datafield > result;
-  
-  if ((nobjs < 2) || (nobjs > 2)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_uncertaintyData_cpp" "', argument " "1"" of type '" "FitObjective const *""'"); 
-  }
-  arg1 = reinterpret_cast< FitObjective * >(argp1);
-  ecode2 = SWIG_AsVal_size_t(swig_obj[1], &val2);
-  if (!SWIG_IsOK(ecode2)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode2), "in method '" "FitObjective_uncertaintyData_cpp" "', argument " "2"" of type '" "size_t""'");
-  } 
-  arg2 = static_cast< size_t >(val2);
-  {
-    try {
-      result = ((FitObjective const *)arg1)->uncertaintyData(arg2);
-    } catch (const std::exception& ex) {
-      // message shown in the Python interpreter
-      const std::string msg {
-        "BornAgain C++ Exception: " + std::string(ex.what())
-      };
-      SWIG_exception(SWIG_RuntimeError, msg.c_str());
-    }
-  }
-  resultobj = SWIG_NewPointerObj((new Datafield(result)), SWIGTYPE_p_Datafield, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_FitObjective_uncertaintyData_cpp__SWIG_1(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {
-  PyObject *resultobj = 0;
-  FitObjective *arg1 = (FitObjective *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  SwigValueWrapper< Datafield > result;
-  
-  if ((nobjs < 1) || (nobjs > 1)) SWIG_fail;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_uncertaintyData_cpp" "', argument " "1"" of type '" "FitObjective const *""'"); 
-  }
-  arg1 = reinterpret_cast< FitObjective * >(argp1);
-  {
-    try {
-      result = ((FitObjective const *)arg1)->uncertaintyData();
-    } catch (const std::exception& ex) {
-      // message shown in the Python interpreter
-      const std::string msg {
-        "BornAgain C++ Exception: " + std::string(ex.what())
-      };
-      SWIG_exception(SWIG_RuntimeError, msg.c_str());
-    }
-  }
-  resultobj = SWIG_NewPointerObj((new Datafield(result)), SWIGTYPE_p_Datafield, SWIG_POINTER_OWN |  0 );
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_FitObjective_uncertaintyData_cpp(PyObject *self, PyObject *args) {
-  Py_ssize_t argc;
-  PyObject *argv[3] = {
-    0
-  };
-  
-  if (!(argc = SWIG_Python_UnpackTuple(args, "FitObjective_uncertaintyData_cpp", 0, 2, argv))) SWIG_fail;
-  --argc;
-  if (argc == 1) {
-    int _v = 0;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_FitObjective, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      return _wrap_FitObjective_uncertaintyData_cpp__SWIG_1(self, argc, argv);
-    }
-  }
-  if (argc == 2) {
-    int _v = 0;
-    void *vptr = 0;
-    int res = SWIG_ConvertPtr(argv[0], &vptr, SWIGTYPE_p_FitObjective, 0);
-    _v = SWIG_CheckState(res);
-    if (_v) {
-      {
-        int res = SWIG_AsVal_size_t(argv[1], NULL);
-        _v = SWIG_CheckState(res);
-      }
-      if (_v) {
-        return _wrap_FitObjective_uncertaintyData_cpp__SWIG_0(self, argc, argv);
-      }
-    }
-  }
-  
-fail:
-  SWIG_Python_RaiseOrModifyTypeError("Wrong number or type of arguments for overloaded function 'FitObjective_uncertaintyData_cpp'.\n"
-    "  Possible C/C++ prototypes are:\n"
-    "    FitObjective::uncertaintyData(size_t) const\n"
-    "    FitObjective::uncertaintyData() const\n");
-  return 0;
-}
-
-
 SWIGINTERN PyObject *_wrap_FitObjective_relativeDifference__SWIG_0(PyObject *self, Py_ssize_t nobjs, PyObject **swig_obj) {
   PyObject *resultobj = 0;
   FitObjective *arg1 = (FitObjective *) 0 ;
@@ -33238,40 +33126,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FitObjective_experimental_array(PyObject *self, PyObject *args) {
-  PyObject *resultobj = 0;
-  FitObjective *arg1 = (FitObjective *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  std::vector< double,std::allocator< double > > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_experimental_array" "', argument " "1"" of type '" "FitObjective const *""'"); 
-  }
-  arg1 = reinterpret_cast< FitObjective * >(argp1);
-  {
-    try {
-      result = ((FitObjective const *)arg1)->experimental_array();
-    } catch (const std::exception& ex) {
-      // message shown in the Python interpreter
-      const std::string msg {
-        "BornAgain C++ Exception: " + std::string(ex.what())
-      };
-      SWIG_exception(SWIG_RuntimeError, msg.c_str());
-    }
-  }
-  resultobj = swig::from(static_cast< std::vector< double,std::allocator< double > > >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_FitObjective_simulation_array(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_FitObjective_flatExpData(PyObject *self, PyObject *args) {
   PyObject *resultobj = 0;
   FitObjective *arg1 = (FitObjective *) 0 ;
   void *argp1 = 0 ;
@@ -33283,12 +33138,12 @@ SWIGINTERN PyObject *_wrap_FitObjective_simulation_array(PyObject *self, PyObjec
   swig_obj[0] = args;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_simulation_array" "', argument " "1"" of type '" "FitObjective const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_flatExpData" "', argument " "1"" of type '" "FitObjective const *""'"); 
   }
   arg1 = reinterpret_cast< FitObjective * >(argp1);
   {
     try {
-      result = ((FitObjective const *)arg1)->simulation_array();
+      result = ((FitObjective const *)arg1)->flatExpData();
     } catch (const std::exception& ex) {
       // message shown in the Python interpreter
       const std::string msg {
@@ -33304,7 +33159,7 @@ fail:
 }
 
 
-SWIGINTERN PyObject *_wrap_FitObjective_uncertainties_cpp(PyObject *self, PyObject *args) {
+SWIGINTERN PyObject *_wrap_FitObjective_flatSimData(PyObject *self, PyObject *args) {
   PyObject *resultobj = 0;
   FitObjective *arg1 = (FitObjective *) 0 ;
   void *argp1 = 0 ;
@@ -33316,45 +33171,12 @@ SWIGINTERN PyObject *_wrap_FitObjective_uncertainties_cpp(PyObject *self, PyObje
   swig_obj[0] = args;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_uncertainties_cpp" "', argument " "1"" of type '" "FitObjective const *""'"); 
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_flatSimData" "', argument " "1"" of type '" "FitObjective const *""'"); 
   }
   arg1 = reinterpret_cast< FitObjective * >(argp1);
   {
     try {
-      result = ((FitObjective const *)arg1)->uncertainties();
-    } catch (const std::exception& ex) {
-      // message shown in the Python interpreter
-      const std::string msg {
-        "BornAgain C++ Exception: " + std::string(ex.what())
-      };
-      SWIG_exception(SWIG_RuntimeError, msg.c_str());
-    }
-  }
-  resultobj = swig::from(static_cast< std::vector< double,std::allocator< double > > >(result));
-  return resultobj;
-fail:
-  return NULL;
-}
-
-
-SWIGINTERN PyObject *_wrap_FitObjective_weights_array(PyObject *self, PyObject *args) {
-  PyObject *resultobj = 0;
-  FitObjective *arg1 = (FitObjective *) 0 ;
-  void *argp1 = 0 ;
-  int res1 = 0 ;
-  PyObject *swig_obj[1] ;
-  std::vector< double,std::allocator< double > > result;
-  
-  if (!args) SWIG_fail;
-  swig_obj[0] = args;
-  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_FitObjective, 0 |  0 );
-  if (!SWIG_IsOK(res1)) {
-    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "FitObjective_weights_array" "', argument " "1"" of type '" "FitObjective const *""'"); 
-  }
-  arg1 = reinterpret_cast< FitObjective * >(argp1);
-  {
-    try {
-      result = ((FitObjective const *)arg1)->weights_array();
+      result = ((FitObjective const *)arg1)->flatSimData();
     } catch (const std::exception& ex) {
       // message shown in the Python interpreter
       const std::string msg {
@@ -38456,19 +38278,16 @@ SWIGINTERN PyObject *_wrap_IChiSquaredModule_residual(PyObject *self, PyObject *
   IChiSquaredModule *arg1 = (IChiSquaredModule *) 0 ;
   double arg2 ;
   double arg3 ;
-  double arg4 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
   double val3 ;
   int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
+  PyObject *swig_obj[3] ;
   double result;
   
-  if (!SWIG_Python_UnpackTuple(args, "IChiSquaredModule_residual", 4, 4, swig_obj)) SWIG_fail;
+  if (!SWIG_Python_UnpackTuple(args, "IChiSquaredModule_residual", 3, 3, swig_obj)) SWIG_fail;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_IChiSquaredModule, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "IChiSquaredModule_residual" "', argument " "1"" of type '" "IChiSquaredModule *""'"); 
@@ -38484,14 +38303,9 @@ SWIGINTERN PyObject *_wrap_IChiSquaredModule_residual(PyObject *self, PyObject *
     SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "IChiSquaredModule_residual" "', argument " "3"" of type '" "double""'");
   } 
   arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "IChiSquaredModule_residual" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
   {
     try {
-      result = (double)(arg1)->residual(arg2,arg3,arg4);
+      result = (double)(arg1)->residual(arg2,arg3);
     } catch (const std::exception& ex) {
       // message shown in the Python interpreter
       const std::string msg {
@@ -38670,19 +38484,16 @@ SWIGINTERN PyObject *_wrap_ChiSquaredModule_residual(PyObject *self, PyObject *a
   ChiSquaredModule *arg1 = (ChiSquaredModule *) 0 ;
   double arg2 ;
   double arg3 ;
-  double arg4 ;
   void *argp1 = 0 ;
   int res1 = 0 ;
   double val2 ;
   int ecode2 = 0 ;
   double val3 ;
   int ecode3 = 0 ;
-  double val4 ;
-  int ecode4 = 0 ;
-  PyObject *swig_obj[4] ;
+  PyObject *swig_obj[3] ;
   double result;
   
-  if (!SWIG_Python_UnpackTuple(args, "ChiSquaredModule_residual", 4, 4, swig_obj)) SWIG_fail;
+  if (!SWIG_Python_UnpackTuple(args, "ChiSquaredModule_residual", 3, 3, swig_obj)) SWIG_fail;
   res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ChiSquaredModule, 0 |  0 );
   if (!SWIG_IsOK(res1)) {
     SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ChiSquaredModule_residual" "', argument " "1"" of type '" "ChiSquaredModule *""'"); 
@@ -38698,14 +38509,9 @@ SWIGINTERN PyObject *_wrap_ChiSquaredModule_residual(PyObject *self, PyObject *a
     SWIG_exception_fail(SWIG_ArgError(ecode3), "in method '" "ChiSquaredModule_residual" "', argument " "3"" of type '" "double""'");
   } 
   arg3 = static_cast< double >(val3);
-  ecode4 = SWIG_AsVal_double(swig_obj[3], &val4);
-  if (!SWIG_IsOK(ecode4)) {
-    SWIG_exception_fail(SWIG_ArgError(ecode4), "in method '" "ChiSquaredModule_residual" "', argument " "4"" of type '" "double""'");
-  } 
-  arg4 = static_cast< double >(val4);
   {
     try {
-      result = (double)(arg1)->residual(arg2,arg3,arg4);
+      result = (double)(arg1)->residual(arg2,arg3);
     } catch (const std::exception& ex) {
       // message shown in the Python interpreter
       const std::string msg {
@@ -40003,13 +39809,10 @@ static PyMethodDef SwigMethods[] = {
 	 { "FitObjective_evaluate_residuals_cpp", _wrap_FitObjective_evaluate_residuals_cpp, METH_VARARGS, "FitObjective_evaluate_residuals_cpp(FitObjective self, mumufit::Parameters const & params) -> vdouble1d_t"},
 	 { "FitObjective_simulationResult", _wrap_FitObjective_simulationResult, METH_VARARGS, "FitObjective_simulationResult(FitObjective self, size_t i_item=0) -> Datafield"},
 	 { "FitObjective_experimentalData", _wrap_FitObjective_experimentalData, METH_VARARGS, "FitObjective_experimentalData(FitObjective self, size_t i_item=0) -> Datafield"},
-	 { "FitObjective_uncertaintyData_cpp", _wrap_FitObjective_uncertaintyData_cpp, METH_VARARGS, "FitObjective_uncertaintyData_cpp(FitObjective self, size_t i_item=0) -> Datafield"},
 	 { "FitObjective_relativeDifference", _wrap_FitObjective_relativeDifference, METH_VARARGS, "FitObjective_relativeDifference(FitObjective self, size_t i_item=0) -> Datafield"},
 	 { "FitObjective_absoluteDifference", _wrap_FitObjective_absoluteDifference, METH_VARARGS, "FitObjective_absoluteDifference(FitObjective self, size_t i_item=0) -> Datafield"},
-	 { "FitObjective_experimental_array", _wrap_FitObjective_experimental_array, METH_O, "FitObjective_experimental_array(FitObjective self) -> vdouble1d_t"},
-	 { "FitObjective_simulation_array", _wrap_FitObjective_simulation_array, METH_O, "FitObjective_simulation_array(FitObjective self) -> vdouble1d_t"},
-	 { "FitObjective_uncertainties_cpp", _wrap_FitObjective_uncertainties_cpp, METH_O, "FitObjective_uncertainties_cpp(FitObjective self) -> vdouble1d_t"},
-	 { "FitObjective_weights_array", _wrap_FitObjective_weights_array, METH_O, "FitObjective_weights_array(FitObjective self) -> vdouble1d_t"},
+	 { "FitObjective_flatExpData", _wrap_FitObjective_flatExpData, METH_O, "FitObjective_flatExpData(FitObjective self) -> vdouble1d_t"},
+	 { "FitObjective_flatSimData", _wrap_FitObjective_flatSimData, METH_O, "FitObjective_flatSimData(FitObjective self) -> vdouble1d_t"},
 	 { "FitObjective_initPrint", _wrap_FitObjective_initPrint, METH_VARARGS, "FitObjective_initPrint(FitObjective self, int every_nth)"},
 	 { "FitObjective_initPlot_cpp", _wrap_FitObjective_initPlot_cpp, METH_VARARGS, "FitObjective_initPlot_cpp(FitObjective self, int every_nth, PyObserverCallback callback)"},
 	 { "FitObjective_iterationInfo", _wrap_FitObjective_iterationInfo, METH_O, "FitObjective_iterationInfo(FitObjective self) -> IterationInfo"},
@@ -40165,7 +39968,7 @@ static PyMethodDef SwigMethods[] = {
 	 { "IChiSquaredModule_setVarianceFunction", _wrap_IChiSquaredModule_setVarianceFunction, METH_VARARGS, "IChiSquaredModule_setVarianceFunction(IChiSquaredModule self, IVarianceFunction variance_function)"},
 	 { "IChiSquaredModule_getIntensityFunction", _wrap_IChiSquaredModule_getIntensityFunction, METH_O, "IChiSquaredModule_getIntensityFunction(IChiSquaredModule self) -> IIntensityFunction"},
 	 { "IChiSquaredModule_setIntensityFunction", _wrap_IChiSquaredModule_setIntensityFunction, METH_VARARGS, "IChiSquaredModule_setIntensityFunction(IChiSquaredModule self, IIntensityFunction intensity_function)"},
-	 { "IChiSquaredModule_residual", _wrap_IChiSquaredModule_residual, METH_VARARGS, "IChiSquaredModule_residual(IChiSquaredModule self, double a, double b, double weight) -> double"},
+	 { "IChiSquaredModule_residual", _wrap_IChiSquaredModule_residual, METH_VARARGS, "IChiSquaredModule_residual(IChiSquaredModule self, double a, double b) -> double"},
 	 { "IChiSquaredModule_swigregister", IChiSquaredModule_swigregister, METH_O, NULL},
 	 { "new_ChiSquaredModule", _wrap_new_ChiSquaredModule, METH_VARARGS, "\n"
 		"ChiSquaredModule()\n"
@@ -40173,7 +39976,7 @@ static PyMethodDef SwigMethods[] = {
 		""},
 	 { "delete_ChiSquaredModule", _wrap_delete_ChiSquaredModule, METH_O, "delete_ChiSquaredModule(ChiSquaredModule self)"},
 	 { "ChiSquaredModule_clone", _wrap_ChiSquaredModule_clone, METH_O, "ChiSquaredModule_clone(ChiSquaredModule self) -> ChiSquaredModule"},
-	 { "ChiSquaredModule_residual", _wrap_ChiSquaredModule_residual, METH_VARARGS, "ChiSquaredModule_residual(ChiSquaredModule self, double a, double b, double weight) -> double"},
+	 { "ChiSquaredModule_residual", _wrap_ChiSquaredModule_residual, METH_VARARGS, "ChiSquaredModule_residual(ChiSquaredModule self, double a, double b) -> double"},
 	 { "ChiSquaredModule_swigregister", ChiSquaredModule_swigregister, METH_O, NULL},
 	 { "ChiSquaredModule_swiginit", ChiSquaredModule_swiginit, METH_VARARGS, NULL},
 	 { "delete_IVarianceFunction", _wrap_delete_IVarianceFunction, METH_O, "delete_IVarianceFunction(IVarianceFunction self)"},
diff --git a/rawEx/fit/scatter2d/custom_objective_function.py b/rawEx/fit/scatter2d/custom_objective_function.py
index a316fe9ff3d353193fadd180ef61f008e327577d..bde5d2abe244199b63d66f25a9e8a5dd98c4730c 100755
--- a/rawEx/fit/scatter2d/custom_objective_function.py
+++ b/rawEx/fit/scatter2d/custom_objective_function.py
@@ -24,8 +24,8 @@ class MyObjective(ba.FitObjective):
 
         # accessing simulated and experimental data as flat numpy arrays
         # applying sqrt to every element
-        sim = np.sqrt(np.asarray(self.simulation_array()))
-        exp = np.sqrt(np.asarray(self.experimental_array()))
+        sim = np.sqrt(np.asarray(self.flatSimData()))
+        exp = np.sqrt(np.asarray(self.flatExpData()))
 
         # return vector of residuals
         return sim - exp