From 9da2194ccd3ef3ac982d9975d05b48bb1c7dbd7f Mon Sep 17 00:00:00 2001
From: "Joachim Wuttke (o)" <j.wuttke@fz-juelich.de>
Date: Tue, 23 May 2023 15:17:02 +0200
Subject: [PATCH] importing legacy tables with 2-3 columns works

---
 Base/Util/StringUtil.cpp                   |  2 ++
 Device/IO/IOFactory.cpp                    | 23 ++++++++++++++++++----
 Device/IO/IOFactory.h                      |  2 +-
 Device/IO/ImportSettings.cpp               | 18 +++--------------
 Device/IO/ImportSettings.h                 |  7 ++++++-
 Device/IO/ReadReflectometry.cpp            |  2 +-
 GUI/View/Import/RealDataSelectorWidget.cpp | 12 +++++++----
 auto/Wrap/libBornAgainDevice.py            |  8 ++++++++
 auto/Wrap/libBornAgainDevice_wrap.cpp      |  4 ++++
 9 files changed, 52 insertions(+), 26 deletions(-)

diff --git a/Base/Util/StringUtil.cpp b/Base/Util/StringUtil.cpp
index 67e417e775a..acd760fe29e 100644
--- a/Base/Util/StringUtil.cpp
+++ b/Base/Util/StringUtil.cpp
@@ -31,6 +31,8 @@ std::string Base::String::padRight(const std::string& name, size_t length)
 //! Returns token vector obtained by splitting string at delimiters.
 std::vector<std::string> Base::String::split(const std::string& text, const std::string& delimiter)
 {
+    if (text.empty())
+        return {};
     std::vector<std::string> result;
     boost::split(result, text, boost::is_any_of(delimiter));
     return result;
diff --git a/Device/IO/IOFactory.cpp b/Device/IO/IOFactory.cpp
index 4fa9e74d0d5..28e431bce11 100644
--- a/Device/IO/IOFactory.cpp
+++ b/Device/IO/IOFactory.cpp
@@ -19,6 +19,7 @@
 #include "Device/Data/Datafield.h"
 #include "Device/Histo/DiffUtil.h"
 #include "Device/Histo/SimulationResult.h"
+#include "Device/IO/ImportSettings.h"
 #include "Device/IO/ParseUtil.h"
 #include "Device/IO/ReadReflectometry.h"
 #include "Device/IO/ReadWriteINT.h"
@@ -180,17 +181,31 @@ Datafield* IO::readData1D(const std::string& file_name, Filetype1D ftype,
 
     std::stringstream s = ::file2stream(file_name);
 
+    if (ftype == csv1D) {
+        if (!importSettings)
+            throw std::runtime_error("No import settings given for 'other legacy' data");
+        return Util::RW::readReflectometryTable(s, *importSettings);
+    }
+
+    if (importSettings)
+        throw std::runtime_error("Import settings given in spite of fully specified data format");
+
     if (ftype == mft)
         return Util::RW::readMotofit(s);
 
     if (ftype == bornagain1D)
         return Util::RW::readBAInt(s);
 
-    ASSERT(ftype == csv1D);
-    if (!importSettings)
-        throw std::runtime_error("No import settings given for csv data");
+    if (ftype == csv1D_2cols)
+        return Util::RW::readReflectometryTable(s, legacy1D_2cols);
+    if (ftype == csv1D_3cols)
+        return Util::RW::readReflectometryTable(s, legacy1D_3cols);
+    if (ftype == csv1D_4cols)
+        return Util::RW::readReflectometryTable(s, legacy1D_4cols);
+    if (ftype == csv1D_5cols)
+        return Util::RW::readReflectometryTable(s, legacy1D_5cols);
 
-    return Util::RW::readReflectometryTable(s, *importSettings);
+    ASSERT(false);
 }
 
 Datafield* IO::readData2D(const std::string& file_name, Filetype2D ftype)
diff --git a/Device/IO/IOFactory.h b/Device/IO/IOFactory.h
index 769ef630491..7bd1f478921 100644
--- a/Device/IO/IOFactory.h
+++ b/Device/IO/IOFactory.h
@@ -22,7 +22,7 @@ struct ImportSettings1D;
 
 namespace IO {
 
-enum Filetype1D { unknown1D, csv1D, bornagain1D, mft };
+enum Filetype1D { unknown1D, csv1D, csv1D_2cols, csv1D_3cols, csv1D_4cols, csv1D_5cols, bornagain1D, mft };
 enum Filetype2D { unknown2D, csv2D, bornagain2D, tiff, nicos2D };
 
 #ifndef SWIG
diff --git a/Device/IO/ImportSettings.cpp b/Device/IO/ImportSettings.cpp
index fa683ca0671..2d04b63e79a 100644
--- a/Device/IO/ImportSettings.cpp
+++ b/Device/IO/ImportSettings.cpp
@@ -14,19 +14,7 @@
 
 #include "Device/IO/ImportSettings.h"
 
-struct ImportSettings1D {
-    std::string headerPrefix; //!< prefix of header lines (usually a single character like "#")
-    std::string linesToSkip;  //!< pattern denoting line to skip (i.e. '1,10-12,42')
-    std::string separator;    //!< column separator
-    size_t col_Q;             //!< column number of Q (counting from 1!)
-    size_t col_R;             //!< column number of R
-    size_t col_sR;            //!< column number of sigma R, or 0
-    size_t col_dQ;            //!< column number of delta Q, or 0
-    size_t col_lambda;        //!< column number of wavelength, or 0
-
-    // bool operator!=(const ImportSettings& other) const;
-    // QByteArray serialize() const;
-    // void deserialize(const QByteArray& data);
-};
-
+const ImportSettings1D legacy1D_2cols { "#", "", "SPACE", 1, 2, 0, 0, 0 };
+const ImportSettings1D legacy1D_3cols { "#", "", "SPACE", 1, 2, 3, 0, 0 };
 const ImportSettings1D legacy1D_4cols { "#", "", "SPACE", 1, 2, 3, 4, 0 };
+const ImportSettings1D legacy1D_5cols { "#", "", "SPACE", 1, 2, 3, 4, 5 };
diff --git a/Device/IO/ImportSettings.h b/Device/IO/ImportSettings.h
index 4a5187aa8fc..33ae5a14c76 100644
--- a/Device/IO/ImportSettings.h
+++ b/Device/IO/ImportSettings.h
@@ -15,6 +15,8 @@
 #ifndef BORNAGAIN_DEVICE_IO_IMPORTSETTINGS_H
 #define BORNAGAIN_DEVICE_IO_IMPORTSETTINGS_H
 
+#include <string>
+
 //! This parameterization can be set interactively by GUI users.
 //! Therefore, exceptionally, indices are counting from 1, not  from 0.
 
@@ -24,8 +26,8 @@ struct ImportSettings1D {
     std::string separator;    //!< column separator
     size_t col_Q;             //!< column number of Q (counting from 1!)
     size_t col_R;             //!< column number of R
-    size_t col_dQ;            //!< column number of delta Q, or 0
     size_t col_sR;            //!< column number of sigma R, or 0
+    size_t col_dQ;            //!< column number of delta Q, or 0
     size_t col_lambda;        //!< column number of wavelength, or 0
 
     // bool operator!=(const ImportSettings& other) const;
@@ -33,6 +35,9 @@ struct ImportSettings1D {
     // void deserialize(const QByteArray& data);
 };
 
+extern const ImportSettings1D legacy1D_2cols;
+extern const ImportSettings1D legacy1D_3cols;
 extern const ImportSettings1D legacy1D_4cols;
+extern const ImportSettings1D legacy1D_5cols;
 
 #endif // BORNAGAIN_DEVICE_IO_IMPORTSETTINGS_H
diff --git a/Device/IO/ReadReflectometry.cpp b/Device/IO/ReadReflectometry.cpp
index d07a3ed0674..2ccb4c4a8a4 100644
--- a/Device/IO/ReadReflectometry.cpp
+++ b/Device/IO/ReadReflectometry.cpp
@@ -57,7 +57,7 @@ Datafield* Util::RW::readReflectometryTable(std::istream& s, const ImportSetting
             sRVec.push_back(rowVec[p.col_sR - 1]);
     }
 
-    return new Datafield(std::vector<const Scale*>{newListScan("qVector", QVec)}, QVec, sRVec);
+    return new Datafield(std::vector<const Scale*>{newListScan("qVector", QVec)}, RVec, sRVec);
 }
 
 Datafield* Util::RW::readMotofit(std::istream& s)
diff --git a/GUI/View/Import/RealDataSelectorWidget.cpp b/GUI/View/Import/RealDataSelectorWidget.cpp
index 001d8b68163..d04c4bea68f 100644
--- a/GUI/View/Import/RealDataSelectorWidget.cpp
+++ b/GUI/View/Import/RealDataSelectorWidget.cpp
@@ -251,8 +251,12 @@ void RealDataSelectorWidget::importData1D()
     static const std::map<const QString, IO::Filetype1D> filters1D{
         {"Motofit (*.mft)", IO::mft},
         {"BornAgain (*.int.gz)", IO::bornagain1D},
-        {"CSV (*.txt *.csv *.dat)", IO::csv1D},
-        {"All (*.*)", IO::unknown1D}};
+        {"legacy 2 columns: Q R (*.csv *.dat *.tab *.txt)", IO::csv1D_2cols},
+        {"legacy 3 columns: Q R σR (*.csv *.dat *.tab *.txt)", IO::csv1D_3cols},
+        {"legacy 4 columns: Q R σR δQ (*.csv *.dat *.tab *.txt)", IO::csv1D_4cols},
+        {"legacy 5 columns: Q R σR δQ λ (*.csv *.dat *.tab *.txt)", IO::csv1D_5cols},
+        {"any other CSV: interactive configuration (*.csv *.dat *.tab *.txt)", IO::csv1D},
+        {"all (*.*)", IO::unknown1D}};
 
     QString filters = ::join_mapkeys(filters1D, ";;");
 
@@ -301,8 +305,8 @@ void RealDataSelectorWidget::importData2D()
         {"TIFF (*.tif *.tiff *.tif.gz)", IO::tiff},
         {"Nicos/SANSDRaw (*.001)", IO::nicos2D},
         {"BornAgain (*.int.gz)", IO::bornagain2D},
-        {"CSV (*.txt *.csv *.dat)", IO::csv2D},
-        {"All (*.*)", IO::unknown2D}};
+        {"CSV (*.csv *.dat *.tab *.txt)", IO::csv2D},
+        {"all (*.*)", IO::unknown2D}};
 
     QString filters = ::join_mapkeys(filters2D, ";;");
 
diff --git a/auto/Wrap/libBornAgainDevice.py b/auto/Wrap/libBornAgainDevice.py
index 94f49d5408f..78fe2afd11e 100644
--- a/auto/Wrap/libBornAgainDevice.py
+++ b/auto/Wrap/libBornAgainDevice.py
@@ -2993,6 +2993,14 @@ unknown1D = _libBornAgainDevice.unknown1D
 
 csv1D = _libBornAgainDevice.csv1D
 
+csv1D_2cols = _libBornAgainDevice.csv1D_2cols
+
+csv1D_3cols = _libBornAgainDevice.csv1D_3cols
+
+csv1D_4cols = _libBornAgainDevice.csv1D_4cols
+
+csv1D_5cols = _libBornAgainDevice.csv1D_5cols
+
 bornagain1D = _libBornAgainDevice.bornagain1D
 
 mft = _libBornAgainDevice.mft
diff --git a/auto/Wrap/libBornAgainDevice_wrap.cpp b/auto/Wrap/libBornAgainDevice_wrap.cpp
index 36b280ca0b2..2841de33cc3 100644
--- a/auto/Wrap/libBornAgainDevice_wrap.cpp
+++ b/auto/Wrap/libBornAgainDevice_wrap.cpp
@@ -39337,6 +39337,10 @@ SWIG_init(void) {
   SWIG_Python_SetConstant(d, "RectangularDetector_PERPENDICULAR_TO_REFLECTED_BEAM",SWIG_From_int(static_cast< int >(RectangularDetector::PERPENDICULAR_TO_REFLECTED_BEAM)));
   SWIG_Python_SetConstant(d, "unknown1D",SWIG_From_int(static_cast< int >(IO::unknown1D)));
   SWIG_Python_SetConstant(d, "csv1D",SWIG_From_int(static_cast< int >(IO::csv1D)));
+  SWIG_Python_SetConstant(d, "csv1D_2cols",SWIG_From_int(static_cast< int >(IO::csv1D_2cols)));
+  SWIG_Python_SetConstant(d, "csv1D_3cols",SWIG_From_int(static_cast< int >(IO::csv1D_3cols)));
+  SWIG_Python_SetConstant(d, "csv1D_4cols",SWIG_From_int(static_cast< int >(IO::csv1D_4cols)));
+  SWIG_Python_SetConstant(d, "csv1D_5cols",SWIG_From_int(static_cast< int >(IO::csv1D_5cols)));
   SWIG_Python_SetConstant(d, "bornagain1D",SWIG_From_int(static_cast< int >(IO::bornagain1D)));
   SWIG_Python_SetConstant(d, "mft",SWIG_From_int(static_cast< int >(IO::mft)));
   SWIG_Python_SetConstant(d, "unknown2D",SWIG_From_int(static_cast< int >(IO::unknown2D)));
-- 
GitLab