From b127b422e72b7334f492b5b6fe8401636b841e0f Mon Sep 17 00:00:00 2001
From: Joachim Wuttke <j.wuttke@fz-juelich.de>
Date: Thu, 28 Sep 2023 15:44:02 +0200
Subject: [PATCH] provide and use DataUtil::Array::flatten2D

---
 Device/Data/ArrayUtil.cpp | 58 +++++++++++++++++++--------------------
 Device/Data/ArrayUtil.h   |  4 ++-
 2 files changed, 32 insertions(+), 30 deletions(-)

diff --git a/Device/Data/ArrayUtil.cpp b/Device/Data/ArrayUtil.cpp
index f86b6bd9f99..5ca1edec179 100644
--- a/Device/Data/ArrayUtil.cpp
+++ b/Device/Data/ArrayUtil.cpp
@@ -19,17 +19,35 @@
 #include "Device/Data/Datafield.h"
 #include <stdexcept>
 
-std::pair<size_t, size_t> DataUtil::Array::getShape(const std::vector<std::vector<double>>& data)
+std::pair<size_t, size_t> DataUtil::Array::getShape(const std::vector<std::vector<double>>& vec)
 {
-    size_t nrows = data.size();
+    size_t nrows = vec.size();
     size_t ncols(0);
     if (nrows)
-        ncols = data[0].size();
+        ncols = vec[0].size();
     for (size_t row = 0; row < nrows; row++)
-        ASSERT(data[row].size() == ncols);
+        ASSERT(vec[row].size() == ncols);
     return std::make_pair(nrows, ncols);
 }
 
+std::tuple<size_t, size_t, std::vector<double>>
+DataUtil::Array::flatten2D(const std::vector<std::vector<double>>& vec)
+{
+    size_t nrows = vec.size();
+    size_t ncols(0);
+    if (nrows)
+        ncols = vec[0].size();
+    std::vector<double> outvec(nrows * ncols);
+    for (size_t row = nrows - 1; row != (size_t)-1; --row) {
+        ASSERT(vec[row].size() == ncols);
+        for (size_t col = 0; col < ncols; ++col)
+            // TODO: why do we need to shuffle cols and rows and reverse row order?
+            outvec[nrows - row - 1 + col * nrows] = vec[row][col];
+    }
+    ASSERT(outvec.size() == nrows * ncols);
+    return {nrows, ncols, outvec};
+}
+
 std::unique_ptr<Datafield> DataUtil::Array::createPField1D(const std::vector<double>& vec)
 {
     const size_t N = vec.size();
@@ -50,39 +68,21 @@ std::unique_ptr<Datafield>
 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;
+    const auto [nrows, ncols, outvec] = flatten2D(vec);
     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)};
 
-    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];
-        }
-    }
-
     if (stdv.empty())
-        return std::make_unique<Datafield>(std::move(axes), out);
+        return std::make_unique<Datafield>(std::move(axes), outvec);
 
-    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);
+    const auto [nrows2, ncols2, outvec2] = flatten2D(stdv);
+    ASSERT(nrows2 == nrows);
+    ASSERT(ncols2 == ncols);
+
+    return std::make_unique<Datafield>(std::move(axes), outvec, outvec2);
 }
 
 std::vector<double> DataUtil::Array::createVector1D(const Datafield& data)
diff --git a/Device/Data/ArrayUtil.h b/Device/Data/ArrayUtil.h
index 2d81318cd63..50f4bad6c1c 100644
--- a/Device/Data/ArrayUtil.h
+++ b/Device/Data/ArrayUtil.h
@@ -28,7 +28,9 @@ class Datafield;
 namespace DataUtil::Array {
 
 //! Returns shape nrows, ncols of 2D array.
-std::pair<size_t, size_t> getShape(const std::vector<std::vector<double>>& data);
+std::pair<size_t, size_t> getShape(const std::vector<std::vector<double>>&);
+
+std::tuple<size_t, size_t, std::vector<double>> flatten2D(const std::vector<std::vector<double>>&);
 
 std::unique_ptr<Datafield> createPField1D(const std::vector<double>& vec);
 std::unique_ptr<Datafield> createPField1D(const std::vector<double>& vec,
-- 
GitLab