diff --git a/Device/IO/IOFactory.cpp b/Device/IO/IOFactory.cpp
index 8007870608f4a9e62e03da50aa758861382cef5b..d8db7ce2339f1a6c64bfb17efdb62e13e373d2a8 100644
--- a/Device/IO/IOFactory.cpp
+++ b/Device/IO/IOFactory.cpp
@@ -108,16 +108,16 @@ void stream2file(const std::string& file_name, std::stringstream& s)
     fout.close();
 }
 
-bool fileTypeMatchesLoaderSelector(const std::string& fileName, IOFactory::LoaderSelector selector)
+bool fileTypeMatchesLoaderSelector(const std::string& fileName, IO::LoaderSelector selector)
 {
     switch (selector) {
-    case IOFactory::bornagain:
+    case IO::bornagain:
         return DataUtil::Format::isIntFile(fileName);
-    case IOFactory::nicos:
+    case IO::nicos:
         return DataUtil::Format::isNicosFile(fileName);
-    case IOFactory::tiff:
+    case IO::tiff:
         return DataUtil::Format::isTiffFile(fileName);
-    case IOFactory::automatic:
+    case IO::automatic:
         return false;
     }
 
@@ -127,7 +127,7 @@ bool fileTypeMatchesLoaderSelector(const std::string& fileName, IOFactory::Loade
 } // namespace
 
 
-Datafield* IOFactory::readDatafield(const std::string& file_name, LoaderSelector selector)
+Datafield* IO::readDatafield(const std::string& file_name, LoaderSelector selector)
 {
     const auto readAs = [=](LoaderSelector testForSelector) {
         return (selector == testForSelector)
@@ -138,42 +138,42 @@ Datafield* IOFactory::readDatafield(const std::string& file_name, LoaderSelector
     auto s = ::file2stream(file_name);
 
     if (readAs(bornagain))
-        return IO::readBAInt(s);
+        return Util::RW::readBAInt(s);
 
     else if (readAs(nicos))
-        return IO::readNicos(s);
+        return Util::RW::readNicos(s);
 
 #ifdef BA_TIFF_SUPPORT
     else if (readAs(tiff))
-        return IO::readTiff(s);
+        return Util::RW::readTiff(s);
 #endif
 
     else
         // Try to read ASCII by default. Binary maps to ASCII.
         // If the file is not actually a matrix of numbers,
         // the error will be thrown during the reading.
-        return IO::readNumpyTxt(s);
+        return Util::RW::readNumpyTxt(s);
 }
 
-Datafield* IOFactory::readReflectometryData(const std::string& file_name)
+Datafield* IO::readReflectometryData(const std::string& file_name)
 {
     auto s = ::file2stream(file_name);
-    return IO::readReflectometryTable(s);
+    return Util::RW::readReflectometryTable(s);
 }
 
-void IOFactory::writeDatafield(const Datafield& data, const std::string& file_name)
+void IO::writeDatafield(const Datafield& data, const std::string& file_name)
 {
     try {
         std::stringstream s;
 
         if (DataUtil::Format::isIntFile(file_name))
-            IO::writeBAInt(data, s);
+            Util::RW::writeBAInt(data, s);
 #ifdef BA_TIFF_SUPPORT
         else if (DataUtil::Format::isTiffFile(file_name))
-            IO::writeTiff(data, s);
+            Util::RW::writeTiff(data, s);
 #endif
         else
-            IO::writeNumpyTxt(data, s);
+            Util::RW::writeNumpyTxt(data, s);
 
         ::stream2file(file_name, s);
 
@@ -182,11 +182,12 @@ void IOFactory::writeDatafield(const Datafield& data, const std::string& file_na
     }
 }
 
-bool IOUtil::filesAgree(const std::string& datFileName, const std::string& refFileName, double tol)
+bool Util::RW::filesAgree(const std::string& datFileName, const std::string& refFileName,
+                          double tol)
 {
     std::unique_ptr<Datafield> datDat;
     try {
-        datDat.reset(IOFactory::readDatafield(datFileName));
+        datDat.reset(IO::readDatafield(datFileName));
     } catch (const std::runtime_error& ex) {
         std::cerr << "File comparison: Could not read data from file " << datFileName
                   << ". Runtime error: " << ex.what() << std::endl;
@@ -202,7 +203,7 @@ bool IOUtil::filesAgree(const std::string& datFileName, const std::string& refFi
 
     std::unique_ptr<Datafield> refDat;
     try {
-        refDat.reset(IOFactory::readDatafield(refFileName));
+        refDat.reset(IO::readDatafield(refFileName));
     } catch (...) {
         std::cerr << "File comparison: Could not read reference data from file " << refFileName
                   << std::endl;
diff --git a/Device/IO/IOFactory.h b/Device/IO/IOFactory.h
index a000280f7501f55f7878cf70daba93592355724a..e212220b044b8f34fc3fcab22155d3f23a755d50 100644
--- a/Device/IO/IOFactory.h
+++ b/Device/IO/IOFactory.h
@@ -19,7 +19,7 @@
 
 class Datafield;
 
-namespace IOFactory {
+namespace IO {
 
 enum LoaderSelector { automatic, bornagain, tiff, nicos };
 
@@ -38,13 +38,13 @@ Datafield* readReflectometryData(const std::string& file_name);
 //! If file name ends with "*.gz" or "*.bz2" the file will be zipped on the fly.
 void writeDatafield(const Datafield& data, const std::string& file_name);
 
-} // namespace IOFactory
+} // namespace IO
 
-namespace IOUtil {
+namespace Util::RW {
 
 //! Returns true if data in both files agree
 bool filesAgree(const std::string& datFileName, const std::string& refFileName, double tol);
 
-} // namespace IOUtil
+} // namespace Util::RW
 
 #endif // BORNAGAIN_DEVICE_IO_IOFACTORY_H
diff --git a/Device/IO/ReadReflectometry.cpp b/Device/IO/ReadReflectometry.cpp
index 27dc3c2f530c61822e833f7f3b07a81856cc966f..9c843bca161d5f7231f306a1dbc8fa2320fbf9ac 100644
--- a/Device/IO/ReadReflectometry.cpp
+++ b/Device/IO/ReadReflectometry.cpp
@@ -20,7 +20,7 @@
 #include "Device/IO/DataFormatUtil.h"
 #include <map>
 
-Datafield* IO::readReflectometryTable(std::istream& inStream)
+Datafield* Util::RW::readReflectometryTable(std::istream& inStream)
 {
     std::string line;
     std::vector<std::vector<double>> vecVec;
diff --git a/Device/IO/ReadReflectometry.h b/Device/IO/ReadReflectometry.h
index d93aa1f94443e1839c88681680f2f6454cf434d7..96090006f50ebbc1e77e3d7cd727c5b1de0ef7a0 100644
--- a/Device/IO/ReadReflectometry.h
+++ b/Device/IO/ReadReflectometry.h
@@ -22,11 +22,11 @@
 
 class Datafield;
 
-namespace IO {
+namespace Util::RW {
 
 //! Read reflectometry scan from plain old table.
 Datafield* readReflectometryTable(std::istream& inStream);
 
-} // namespace IO
+} // namespace Util::RW
 
 #endif // BORNAGAIN_DEVICE_IO_READREFLECTOMETRY_H
diff --git a/Device/IO/ReadWriteINT.cpp b/Device/IO/ReadWriteINT.cpp
index bd9ee636bd8dee50264cdb2d61c0424f47153aa3..b5f33895d7e975a28dec7f2f61688bac460610a3 100644
--- a/Device/IO/ReadWriteINT.cpp
+++ b/Device/IO/ReadWriteINT.cpp
@@ -35,7 +35,7 @@ void writeDatafieldDoubles(const std::vector<double>& dataValues, std::ostream&
     }
 }
 
-Datafield* IO::readBAInt(std::istream& input_stream)
+Datafield* Util::RW::readBAInt(std::istream& input_stream)
 {
     std::string line;
 
@@ -55,7 +55,7 @@ Datafield* IO::readBAInt(std::istream& input_stream)
     return result;
 }
 
-void IO::writeBAInt(const Datafield& data, std::ostream& output_stream)
+void Util::RW::writeBAInt(const Datafield& data, std::ostream& output_stream)
 {
     output_stream << "# BornAgain Intensity Data\n\n";
 
diff --git a/Device/IO/ReadWriteINT.h b/Device/IO/ReadWriteINT.h
index c2f2a35bacf0680dbab3113c678e514dd5d7c997..a871030861b832fb18b963159db62789f03c0330 100644
--- a/Device/IO/ReadWriteINT.h
+++ b/Device/IO/ReadWriteINT.h
@@ -22,13 +22,13 @@
 
 class Datafield;
 
-namespace IO {
+namespace Util::RW {
 
 //! Write Datafield as BornAgain intensity ASCII file.
 Datafield* readBAInt(std::istream& input_stream);
 //! Read Datafield from BornAgain intensity ASCII file.
 void writeBAInt(const Datafield& data, std::ostream& output_stream);
 
-} // namespace IO
+} // namespace Util::RW
 
 #endif // BORNAGAIN_DEVICE_IO_READWRITEINT_H
diff --git a/Device/IO/ReadWriteNicos.cpp b/Device/IO/ReadWriteNicos.cpp
index 8c34a5df58f847af46b1a231e5dc21d19552f692..b9836161622635779ee283f5ed784f8e8b1dab71 100644
--- a/Device/IO/ReadWriteNicos.cpp
+++ b/Device/IO/ReadWriteNicos.cpp
@@ -3,7 +3,7 @@
 //  BornAgain: simulate and fit reflection and scattering
 //
 //! @file      Device/IO/ReadWriteNicos.cpp
-//! @brief     Implements function IO::readNicos
+//! @brief     Implements function Util::RW::readNicos
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -48,7 +48,7 @@ unsigned int readAssignedPositiveIntValue(const std::string& line, int lineNumbe
 } // namespace
 
 
-Datafield* IO::readNicos(std::istream& input_stream)
+Datafield* Util::RW::readNicos(std::istream& input_stream)
 {
     std::string line;
     int lineNumber = 0;
diff --git a/Device/IO/ReadWriteNicos.h b/Device/IO/ReadWriteNicos.h
index 92fb031aafa51cdbc6545f3222438f60f71e3c40..fdf0e7a8ee10e20b912f252e1d9a7f623e8ff58f 100644
--- a/Device/IO/ReadWriteNicos.h
+++ b/Device/IO/ReadWriteNicos.h
@@ -3,7 +3,7 @@
 //  BornAgain: simulate and fit reflection and scattering
 //
 //! @file      Device/IO/ReadWriteNicos.h
-//! @brief     Declares function IO::readNicos
+//! @brief     Declares function Util::RW::readNicos
 //!
 //! @homepage  http://www.bornagainproject.org
 //! @license   GNU General Public License v3 or higher (see COPYING)
@@ -21,7 +21,7 @@ class Datafield;
 
 //! Read/write SANSDRaw files written by Nicos (*.001).
 
-namespace IO {
+namespace Util::RW {
 
 Datafield* readNicos(std::istream& input_stream);
 
diff --git a/Device/IO/ReadWriteNumpyTXT.cpp b/Device/IO/ReadWriteNumpyTXT.cpp
index 28891930ea7a2c1f6f55f92843cbb35beb001e29..2da1172ef52cb909905a5cd192ce7deb796dc95a 100644
--- a/Device/IO/ReadWriteNumpyTXT.cpp
+++ b/Device/IO/ReadWriteNumpyTXT.cpp
@@ -65,7 +65,7 @@ void write2DRepresentation(const Datafield& data, std::ostream& output_stream)
 
 } // namespace
 
-Datafield* IO::readNumpyTxt(std::istream& input_stream)
+Datafield* Util::RW::readNumpyTxt(std::istream& input_stream)
 {
     std::string line;
     std::vector<std::vector<double>> data;
@@ -107,7 +107,7 @@ Datafield* IO::readNumpyTxt(std::istream& input_stream)
     return DataUtil::Array::createPField2D(data).release();
 }
 
-void IO::writeNumpyTxt(const Datafield& data, std::ostream& output_stream)
+void Util::RW::writeNumpyTxt(const Datafield& data, std::ostream& output_stream)
 {
     output_stream << "# BornAgain Intensity Data" << std::endl;
     output_stream << "# Simple array suitable for numpy, matlab etc." << std::endl;
diff --git a/Device/IO/ReadWriteNumpyTXT.h b/Device/IO/ReadWriteNumpyTXT.h
index c186a431d9608292c8db1fc848ca7d74d39d5b53..d81ed8b1ddc80c9239032aa315baf0352244b06a 100644
--- a/Device/IO/ReadWriteNumpyTXT.h
+++ b/Device/IO/ReadWriteNumpyTXT.h
@@ -22,13 +22,13 @@
 
 class Datafield;
 
-namespace IO {
+namespace Util::RW {
 
 //! Reads Datafield from simple ASCII file with layout as in numpy.savetxt.
 Datafield* readNumpyTxt(std::istream& input_stream);
 //! Writes Datafield to simple ASCII file with layout as in numpy.savetxt.
 void writeNumpyTxt(const Datafield& data, std::ostream& output_stream);
 
-} // namespace IO
+} // namespace Util::RW
 
 #endif // BORNAGAIN_DEVICE_IO_READWRITENUMPYTXT_H
diff --git a/Device/IO/ReadWriteTiff.cpp b/Device/IO/ReadWriteTiff.cpp
index bbeb99d7527c99b773b3cb074fa5485c94d5b76c..152fce698871a2851db3ad5aa9f1482fe6227038 100644
--- a/Device/IO/ReadWriteTiff.cpp
+++ b/Device/IO/ReadWriteTiff.cpp
@@ -27,7 +27,7 @@
 #include <tiffio.h>
 #include <tiffio.hxx>
 
-Datafield* IO::readTiff(std::istream& input_stream)
+Datafield* Util::RW::readTiff(std::istream& input_stream)
 {
     TIFF* tiffstream = TIFFStreamOpen("MemTIFF", &input_stream);
     if (!tiffstream)
@@ -167,7 +167,7 @@ Datafield* IO::readTiff(std::istream& input_stream)
     return data.release();
 }
 
-void IO::writeTiff(const Datafield& data, std::ostream& output_stream)
+void Util::RW::writeTiff(const Datafield& data, std::ostream& output_stream)
 {
     if (data.rank() != 2)
         throw std::runtime_error("Cannot read TIFF file: unsupported data rank");
diff --git a/Device/IO/ReadWriteTiff.h b/Device/IO/ReadWriteTiff.h
index 847a2d6fcaa7e3b9288a84b6484d47664414a574..08454e17cb9ad22d9872510f0d0eb99cf8bd8116 100644
--- a/Device/IO/ReadWriteTiff.h
+++ b/Device/IO/ReadWriteTiff.h
@@ -23,12 +23,12 @@
 
 class Datafield;
 
-namespace IO {
+namespace Util::RW {
 
 Datafield* readTiff(std::istream& input_stream);
 void writeTiff(const Datafield& data, std::ostream& output_stream);
 
-} // namespace IO
+} // namespace Util::RW
 
 #endif // BA_TIFF_SUPPORT
 #endif // BORNAGAIN_DEVICE_IO_READWRITETIFF_H
diff --git a/GUI/Model/Axis/PointwiseAxisItem.cpp b/GUI/Model/Axis/PointwiseAxisItem.cpp
index 4fb9fa791460a8002b8c587d3810f7bd74e30911..ab20ac5ea2ad798fcd3e54a404d25579c053f722 100644
--- a/GUI/Model/Axis/PointwiseAxisItem.cpp
+++ b/GUI/Model/Axis/PointwiseAxisItem.cpp
@@ -76,7 +76,7 @@ QByteArray PointwiseAxisItem::serializeBinaryData() const
     Datafield axisData({m_axis->clone()});
 
     std::stringstream ss;
-    IO::writeBAInt(axisData, ss);
+    Util::RW::writeBAInt(axisData, ss);
     return QByteArray(ss.str().c_str(), static_cast<int>(ss.str().size()));
 }
 
@@ -86,7 +86,7 @@ void PointwiseAxisItem::deserializeBinaryData(const QByteArray& data)
         return;
 
     std::istringstream str(data.toStdString());
-    std::unique_ptr<Datafield> d(IO::readBAInt(str));
+    std::unique_ptr<Datafield> d(Util::RW::readBAInt(str));
     m_axis = std::unique_ptr<Scale>(d->axis(0).clone());
 }
 
diff --git a/GUI/Model/Data/DataItem.cpp b/GUI/Model/Data/DataItem.cpp
index ad8525c11c7188c1d649ba1af62c54b8a0675358..d08f9a5547d2666ad90bbdb7c6b1a3dc910355d3 100644
--- a/GUI/Model/Data/DataItem.cpp
+++ b/GUI/Model/Data/DataItem.cpp
@@ -105,7 +105,7 @@ QString DataItem::loadDatafield(MessageService* messageService, const QString& p
     ASSERT(messageService);
     const auto file = dataFullPath(projectDir);
     try {
-        auto* data = IOFactory::readDatafield(file.toStdString());
+        auto* data = IO::readDatafield(file.toStdString());
         if (!data)
             throw std::runtime_error("Datafield is not created for file: " + file.toStdString());
         setDatafield(data);
@@ -135,7 +135,7 @@ void DataItem::saveDatafield(const QString& projectDir) const
         std::string errorMessage;
         auto* saveThread = new std::thread([&errorMessage, &field, path]() {
             try {
-                IOFactory::writeDatafield(*field, path.toStdString());
+                IO::writeDatafield(*field, path.toStdString());
             } catch (const std::exception& ex) {
                 errorMessage = ex.what();
             }
@@ -145,7 +145,7 @@ void DataItem::saveDatafield(const QString& projectDir) const
         if (!errorMessage.empty())
             throw std::runtime_error(errorMessage);
     } else
-        IOFactory::writeDatafield(*field, path.toStdString());
+        IO::writeDatafield(*field, path.toStdString());
 
     m_last_saved = QDateTime::currentDateTime();
 }
diff --git a/GUI/View/Import/ImportDataUtil.cpp b/GUI/View/Import/ImportDataUtil.cpp
index 9423ead4a9041b2d8517910151a9c033dda0c8b1..17fe8a265f1ff87a3f9b2752f35e9a688fdddcbe 100644
--- a/GUI/View/Import/ImportDataUtil.cpp
+++ b/GUI/View/Import/ImportDataUtil.cpp
@@ -33,12 +33,12 @@ const QString filter_string_ascii = "Intensity File (*.int *.int.gz *.txt *.csv
 //! Currently used for all 2D, and some 1D data files.
 
 std::unique_ptr<Datafield> ImportKnownData(const QString& fileName,
-                                           IOFactory::LoaderSelector loader = IOFactory::automatic)
+                                           IO::LoaderSelector loader = IO::automatic)
 {
     // Try to use the canonical tools for importing data
     std::unique_ptr<Datafield> result;
     try {
-        result.reset(IOFactory::readDatafield(fileName.toStdString(), loader));
+        result.reset(IO::readDatafield(fileName.toStdString(), loader));
     } catch (std::exception& ex) {
         QString message = QString("Error while trying to read file\n\n'%1'\n\n%2")
                               .arg(fileName)
@@ -52,7 +52,7 @@ std::unique_ptr<Datafield> ImportKnownData(const QString& fileName,
 
 
 std::unique_ptr<Datafield> GUI::View::ImportDataUtil::Import2dData(const QString& fileName,
-                                                                   IOFactory::LoaderSelector loader)
+                                                                   IO::LoaderSelector loader)
 {
     return ImportKnownData(fileName, loader);
 }
diff --git a/GUI/View/Import/ImportDataUtil.h b/GUI/View/Import/ImportDataUtil.h
index da10204800aa0c1531f5a24eff43ad26f7999e2a..ac931285b99b2af6b3f6afca2d4eaf7012a52af7 100644
--- a/GUI/View/Import/ImportDataUtil.h
+++ b/GUI/View/Import/ImportDataUtil.h
@@ -29,7 +29,7 @@ class AbstractDataLoader;
 namespace GUI::View::ImportDataUtil {
 
 //! Imports 2D data, stores them as Datafield, and returns owning pointer.
-std::unique_ptr<Datafield> Import2dData(const QString& fileName, IOFactory::LoaderSelector loader);
+std::unique_ptr<Datafield> Import2dData(const QString& fileName, IO::LoaderSelector loader);
 
 //! Imports 1D data into the given item.
 
diff --git a/GUI/View/Import/RealDataSelectorWidget.cpp b/GUI/View/Import/RealDataSelectorWidget.cpp
index d5a3dcbe0716a2102bb68bed06d1a78a8e349ddd..5e6bdd7ff824250e661b4da89e8fb421225882a5 100644
--- a/GUI/View/Import/RealDataSelectorWidget.cpp
+++ b/GUI/View/Import/RealDataSelectorWidget.cpp
@@ -282,20 +282,20 @@ void RealDataSelectorWidget::importData1D()
 
 void RealDataSelectorWidget::importData2D()
 {
-    QMap<QString, IOFactory::LoaderSelector> loaderOfFilter;
+    QMap<QString, IO::LoaderSelector> loaderOfFilter;
     QString filters;
 
-    const auto addFilter = [&](IOFactory::LoaderSelector loaderSelector, const QString& filter) {
+    const auto addFilter = [&](IO::LoaderSelector loaderSelector, const QString& filter) {
         if (!filters.isEmpty())
             filters += ";;";
         filters += filter;
         loaderOfFilter[filter] = loaderSelector;
     };
-    addFilter(IOFactory::tiff, "TIFF (*.tif *.tiff *.tif.gz)");
-    addFilter(IOFactory::nicos, "Nicos/SANSDRaw (*.001)");
-    addFilter(IOFactory::bornagain, "BornAgain (*.int.gz)");
-    addFilter(IOFactory::automatic, "CSV (*.txt *.csv *.dat)");
-    addFilter(IOFactory::automatic, "All (*.*)");
+    addFilter(IO::tiff, "TIFF (*.tif *.tiff *.tif.gz)");
+    addFilter(IO::nicos, "Nicos/SANSDRaw (*.001)");
+    addFilter(IO::bornagain, "BornAgain (*.int.gz)");
+    addFilter(IO::automatic, "CSV (*.txt *.csv *.dat)");
+    addFilter(IO::automatic, "All (*.*)");
 
     QString selectedFilter = ProjectManager::instance()->recentlyUsedImportFilter2D();
 
@@ -310,7 +310,7 @@ void RealDataSelectorWidget::importData2D()
     ProjectManager::instance()->setImportDirFromFilePath(fileNames[0]);
     ProjectManager::instance()->setRecentlyUsedImportFilter2D(selectedFilter);
 
-    const auto selectedLoader = loaderOfFilter.value(selectedFilter, IOFactory::automatic);
+    const auto selectedLoader = loaderOfFilter.value(selectedFilter, IO::automatic);
 
     for (const auto& fileName : fileNames) {
         std::unique_ptr<Datafield> data =
diff --git a/GUI/View/Loaders/AutomaticDataLoader1D.cpp b/GUI/View/Loaders/AutomaticDataLoader1D.cpp
index 5206b5401267082a1b1ee4f9cfd093557c88ebe4..ec28ffd8cd4d34209b3022e422620e2905642ece 100644
--- a/GUI/View/Loaders/AutomaticDataLoader1D.cpp
+++ b/GUI/View/Loaders/AutomaticDataLoader1D.cpp
@@ -90,7 +90,7 @@ void AutomaticDataLoader1D::processContents()
 
     try {
         std::stringstream str(m_fileContent.constData());
-        auto* oData = IO::readReflectometryTable(str);
+        auto* oData = Util::RW::readReflectometryTable(str);
 
         ImportDataInfo importInfo(std::move(*oData), Coords::QSPACE);
         m_item->setImportData(std::move(importInfo));
diff --git a/GUI/View/PlotUtil/SavePlotAssistant.cpp b/GUI/View/PlotUtil/SavePlotAssistant.cpp
index 1801dbfbf27861fad986a622afec4f795ab511e7..901d68290b9958a8ad4a4529ee8f75ca271188a0 100644
--- a/GUI/View/PlotUtil/SavePlotAssistant.cpp
+++ b/GUI/View/PlotUtil/SavePlotAssistant.cpp
@@ -85,7 +85,7 @@ void saveToFile(const QString& fileName, QCustomPlot* plot, const Datafield* out
 
     else {
         ASSERT(output_data);
-        IOFactory::writeDatafield(*output_data, fileName.toStdString());
+        IO::writeDatafield(*output_data, fileName.toStdString());
     }
 }
 
diff --git a/Tests/Functional/Consistence/CompareTwoReferences.cpp b/Tests/Functional/Consistence/CompareTwoReferences.cpp
index 1e8c6269b0286795013f5e12ffe737bd4ab70919..2b13e018631cdbfc2e092c4589dc7fd510a8e704 100644
--- a/Tests/Functional/Consistence/CompareTwoReferences.cpp
+++ b/Tests/Functional/Consistence/CompareTwoReferences.cpp
@@ -30,7 +30,7 @@ std::unique_ptr<Datafield> load(const std::string& name)
         BaseUtil::Filesystem::jointPath(BATesting::ReferenceDir_Suite(), name + ".int.gz");
     std::unique_ptr<Datafield> data;
     try {
-        data.reset(IOFactory::readDatafield(path));
+        data.reset(IO::readDatafield(path));
     } catch (const std::exception&) {
         std::cout << "Data file " << path << "not found.\n"
                   << "Run the pertinent Core standard test, copy the fresh data file"
diff --git a/Tests/Functional/CoreSpecial/CoreIOPathTest.cpp b/Tests/Functional/CoreSpecial/CoreIOPathTest.cpp
index c31b57b271713e8370ed8f6d70aef63f15b3ca73..90333b3df04784aa9a85b968fc43e859707f9d5f 100644
--- a/Tests/Functional/CoreSpecial/CoreIOPathTest.cpp
+++ b/Tests/Functional/CoreSpecial/CoreIOPathTest.cpp
@@ -35,8 +35,8 @@ std::unique_ptr<Datafield> createTestData()
 
 bool test_io(const Datafield* data, const std::string& file_name)
 {
-    IOFactory::writeDatafield(*data, file_name);
-    std::unique_ptr<Datafield> loaded(IOFactory::readDatafield(file_name));
+    IO::writeDatafield(*data, file_name);
+    std::unique_ptr<Datafield> loaded(IO::readDatafield(file_name));
     return DiffUtil::meanRelVecDiff(data->flatVector(), loaded->flatVector()) <= 1e-06;
 }
 
diff --git a/Tests/Functional/CoreSpecial/FourierTransformationTest.cpp b/Tests/Functional/CoreSpecial/FourierTransformationTest.cpp
index c5ac93c9b35aaa1af540d46c3992d0531d1b375f..1cf1dd029b8d3236ff7aaa2524b424e424523f5a 100644
--- a/Tests/Functional/CoreSpecial/FourierTransformationTest.cpp
+++ b/Tests/Functional/CoreSpecial/FourierTransformationTest.cpp
@@ -46,7 +46,7 @@ bool test_fft(const std::string& input_image_name, const std::string& reference_
     try {
         const auto filename =
             BaseUtil::Filesystem::jointPath(BATesting::ReferenceDir_Suite(), input_image_name);
-        input_image.reset(IOFactory::readDatafield(filename));
+        input_image.reset(IO::readDatafield(filename));
     } catch (const std::exception&) {
         std::cout << "Error: no input image.\n";
         return false;
@@ -58,7 +58,7 @@ bool test_fft(const std::string& input_image_name, const std::string& reference_
     std::cout << "loading reference" << std::endl;
     std::unique_ptr<Datafield> reference_fft;
     try {
-        reference_fft.reset(IOFactory::readDatafield(reference_fft_name));
+        reference_fft.reset(IO::readDatafield(reference_fft_name));
     } catch (const std::exception&) {
         std::cout << "Error: no reference fft image. Creating new one.\n";
     }
@@ -73,7 +73,7 @@ bool test_fft(const std::string& input_image_name, const std::string& reference_
         BaseUtil::Filesystem::createDirectory(BATesting::TestOutDir_Core());
         std::string out_fname = BaseUtil::Filesystem::jointPath(
             BATesting::TestOutDir_Core(), BaseUtil::Filesystem::filename(reference_fft_name));
-        IOFactory::writeDatafield(*fft, out_fname);
+        IO::writeDatafield(*fft, out_fname);
         std::cout << "New fft image stored in " << out_fname << std::endl;
     }
 
diff --git a/Tests/Suite/GUI/Check.cpp b/Tests/Suite/GUI/Check.cpp
index abc837cc54844fb3f7d3f36414ac6054314e28af..3d1c6006be0bd5f64bff51c5150d6d1f5e6ec769 100644
--- a/Tests/Suite/GUI/Check.cpp
+++ b/Tests/Suite/GUI/Check.cpp
@@ -72,7 +72,7 @@ bool checkSimulation(const std::string& name, ISimulation& sim, const double lim
                                                                       {"std", ref_data}};
     for (const auto& [kind, data] : tosave) {
         const std::string out_fname = (dir / fs::path(name + "." + kind + ".int.gz")).string();
-        IOFactory::writeDatafield(data, out_fname);
+        IO::writeDatafield(data, out_fname);
         std::cout << "Saved " << out_fname << "\n";
     }
     std::cout << "Notes:\n"
diff --git a/Tests/Suite/Persist/Check.cpp b/Tests/Suite/Persist/Check.cpp
index d404783a415c6cedb7f2066548a23846b605f093..8df5bc0b4840d08fb06429f583fadc81c7c0291a 100644
--- a/Tests/Suite/Persist/Check.cpp
+++ b/Tests/Suite/Persist/Check.cpp
@@ -38,7 +38,7 @@ bool checkSimulation(const std::string& name, ISimulation& direct_simulation, co
         const std::string refPath =
             BaseUtil::Filesystem::jointPath(BATesting::ReferenceDir_Suite(), name + ".int.gz");
         std::cout << "- reference: " << refPath << "\n";
-        reference.reset(IOFactory::readDatafield(refPath));
+        reference.reset(IO::readDatafield(refPath));
     } catch (const std::exception&) {
         std::cerr << "FAILED: cannot read reference\n";
     }
@@ -59,7 +59,7 @@ bool checkSimulation(const std::string& name, ISimulation& direct_simulation, co
     BaseUtil::Filesystem::createDirectories(BATesting::TestOutDir_Suite());
     std::string out_fname =
         BaseUtil::Filesystem::jointPath(BATesting::TestOutDir_Suite(), name + ".int.gz");
-    IOFactory::writeDatafield(result_data, out_fname);
+    IO::writeDatafield(result_data, out_fname);
     std::cout << "Notes:\n- to visualize an intensity map, use " << BABuild::srcDir()
               << "/devtools/view/plot-int.py\n"
               << "- to plot a difference image, use " << BABuild::srcDir()
diff --git a/Tests/Suite/Py/Check.cpp b/Tests/Suite/Py/Check.cpp
index 4be8023dd05ca66fd3dc56e6d1de9bd7e46d8e28..55ec51300c054e6c7269b33b281c9df152f5763f 100644
--- a/Tests/Suite/Py/Check.cpp
+++ b/Tests/Suite/Py/Check.cpp
@@ -61,7 +61,7 @@ std::vector<double> domainData(const std::string& test_name, const ISimulation&
     if (err)
         throw std::runtime_error("Exported Python script did not execute properly");
 
-    auto result = std::unique_ptr<Datafield>(IOFactory::readDatafield(output_path));
+    auto result = std::unique_ptr<Datafield>(IO::readDatafield(output_path));
     if (!result)
         throw std::runtime_error("Could not read back simulation output from file " + output_path);
     return result->flatVector();
diff --git a/Tests/Unit/Device/IOReaderWriterTest.cpp b/Tests/Unit/Device/IOReaderWriterTest.cpp
index 357dae82154a57be9e16f23b6383148fc60eab03..df9899078cfc12b8ec67d0ed007cddd0de4db663 100644
--- a/Tests/Unit/Device/IOReaderWriterTest.cpp
+++ b/Tests/Unit/Device/IOReaderWriterTest.cpp
@@ -21,9 +21,9 @@ protected:
 TEST_F(IOReaderWriterTest, TestRWINT)
 {
     std::stringstream ss;
-    IO::writeBAInt(m_model_data, ss);
+    Util::RW::writeBAInt(m_model_data, ss);
 
-    auto result = std::unique_ptr<Datafield>(IO::readBAInt(ss));
+    auto result = std::unique_ptr<Datafield>(Util::RW::readBAInt(ss));
 
     auto compare_axis = [this, &result](size_t index) {
         EXPECT_EQ(m_model_data.axis(index).size(), result->axis(index).size());
@@ -41,9 +41,9 @@ TEST_F(IOReaderWriterTest, TestRWINT)
 TEST_F(IOReaderWriterTest, TestRWNumpyTXT)
 {
     std::stringstream ss;
-    IO::writeNumpyTxt(m_model_data, ss);
+    Util::RW::writeNumpyTxt(m_model_data, ss);
 
-    auto result = std::unique_ptr<Datafield>(IO::readNumpyTxt(ss));
+    auto result = std::unique_ptr<Datafield>(Util::RW::readNumpyTxt(ss));
     EXPECT_EQ(m_model_data.rank(), result->rank());
     for (size_t i = 0, size = m_model_data.size(); i < size; ++i)
         EXPECT_EQ(m_model_data[i], (*result)[i]);
@@ -54,9 +54,9 @@ TEST_F(IOReaderWriterTest, TestRWNumpyTXT)
 TEST_F(IOReaderWriterTest, TestRWTiff)
 {
     std::stringstream ss;
-    IO::writeTiff(m_model_data, ss);
+    Util::RW::writeTiff(m_model_data, ss);
 
-    auto result = std::unique_ptr<Datafield>(IO::readTiff(ss));
+    auto result = std::unique_ptr<Datafield>(Util::RW::readTiff(ss));
     EXPECT_EQ(m_model_data.rank(), result->rank());
     for (size_t i = 0, size = m_model_data.size(); i < size; ++i)
         EXPECT_EQ(m_model_data[i], (*result)[i]);
diff --git a/Tests/Unit/Device/ReadSANSDRawTest.cpp b/Tests/Unit/Device/ReadSANSDRawTest.cpp
index 3b80c95eddfc5174ce8cbfd490be4109553d33fe..0a8eb39d8152b8f85fef6d4d599c4453984a4226 100644
--- a/Tests/Unit/Device/ReadSANSDRawTest.cpp
+++ b/Tests/Unit/Device/ReadSANSDRawTest.cpp
@@ -6,7 +6,7 @@
 TEST(ReadSANSDRawTest, Read)
 {
     const auto fname = BATesting::ExampleDataDir() + "/SANSDRaw.001";
-    Datafield* data = IOFactory::readDatafield(fname, IOFactory::automatic);
+    Datafield* data = IO::readDatafield(fname, IO::automatic);
     EXPECT_NE(data, nullptr);
     if (!data)
         return;
diff --git a/Tests/Unit/GUI/TestJobModel.cpp b/Tests/Unit/GUI/TestJobModel.cpp
index 11b9194b55fc09de3889ee79f6e4a2416d0c1f71..260437eb2c3e7da47f11320a0933168c292e74e0 100644
--- a/Tests/Unit/GUI/TestJobModel.cpp
+++ b/Tests/Unit/GUI/TestJobModel.cpp
@@ -88,8 +88,8 @@ TEST(TestJobModel, saveNonXMLData)
     EXPECT_TRUE(QFile::exists(fname2));
 
     // read data from disk, check it is the same
-    std::unique_ptr<Datafield> dataOnDisk1(IOFactory::readDatafield(fname1.toStdString()));
-    std::unique_ptr<Datafield> dataOnDisk2(IOFactory::readDatafield(fname2.toStdString()));
+    std::unique_ptr<Datafield> dataOnDisk1(IO::readDatafield(fname1.toStdString()));
+    std::unique_ptr<Datafield> dataOnDisk2(IO::readDatafield(fname2.toStdString()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk1, *jobItem->simulatedDataItem()->c_field()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk2, *jobItem->realItem()->dataItem()->c_field()));
 
@@ -103,7 +103,7 @@ TEST(TestJobModel, saveNonXMLData)
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk2, *jobItem->realItem()->dataItem()->c_field()));
 
     // check that data on disk has changed
-    dataOnDisk1.reset(IOFactory::readDatafield(fname1.toStdString()));
+    dataOnDisk1.reset(IO::readDatafield(fname1.toStdString()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk1, *jobItem->simulatedDataItem()->c_field()));
 
     // rename job and check that file on disk changed the name
diff --git a/Tests/Unit/GUI/TestRealModel.cpp b/Tests/Unit/GUI/TestRealModel.cpp
index 30330c84984f952294197f06f269354af94f5179..fb881ef1d271fa860e6d6264949310304f540355 100644
--- a/Tests/Unit/GUI/TestRealModel.cpp
+++ b/Tests/Unit/GUI/TestRealModel.cpp
@@ -125,8 +125,8 @@ TEST(TestRealModel, saveNonXMLData)
     EXPECT_TRUE(QFile::exists(fname2));
 
     // read data from disk, checking it is the same
-    std::unique_ptr<Datafield> dataOnDisk1(IOFactory::readDatafield(fname1.toStdString()));
-    std::unique_ptr<Datafield> dataOnDisk2(IOFactory::readDatafield(fname2.toStdString()));
+    std::unique_ptr<Datafield> dataOnDisk1(IO::readDatafield(fname1.toStdString()));
+    std::unique_ptr<Datafield> dataOnDisk2(IO::readDatafield(fname2.toStdString()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk1, *item1->dataItem()->c_field()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk2, *item2->dataItem()->c_field()));
 
@@ -139,7 +139,7 @@ TEST(TestRealModel, saveNonXMLData)
     EXPECT_FALSE(UTest::GUI::isTheSame(*dataOnDisk2, *item2->dataItem()->c_field()));
 
     // check that data on disk has changed
-    dataOnDisk2.reset(IOFactory::readDatafield(fname2.toStdString()));
+    dataOnDisk2.reset(IO::readDatafield(fname2.toStdString()));
     EXPECT_TRUE(UTest::GUI::isTheSame(*dataOnDisk2, *item2->dataItem()->c_field()));
 
     // rename RealData and check that file on disk changed the name
diff --git a/Tests/Unit/GUI/Utils.cpp b/Tests/Unit/GUI/Utils.cpp
index 0db85eb8a2d86a3c3b969ada2c3455544371531c..4018bf1632145b48b545b30f0f768bd98562c323 100644
--- a/Tests/Unit/GUI/Utils.cpp
+++ b/Tests/Unit/GUI/Utils.cpp
@@ -67,6 +67,6 @@ bool UTest::GUI::isTheSame(const Datafield& data1, const Datafield& data2)
 
 bool UTest::GUI::isTheSame(const QString& fileName, const Datafield& data)
 {
-    std::unique_ptr<Datafield> dataOnDisk(IOFactory::readDatafield(fileName.toStdString()));
+    std::unique_ptr<Datafield> dataOnDisk(IO::readDatafield(fileName.toStdString()));
     return isTheSame(*dataOnDisk, data);
 }