BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
IOFactory.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/IO/IOFactory.cpp
6 //! @brief Implements class DatafieldIOFactory.
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2018
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
15 #include "Device/IO/IOFactory.h"
16 #include "Base/Util/Assert.h"
18 #include "Device/Histo/DiffUtil.h"
22 #include "Device/IO/ReadWriteINT.h"
26 #include <exception>
27 #include <fstream>
28 #include <iostream>
29 #include <memory>
30 #include <sstream>
31 
32 #ifdef _WIN32
33 #pragma warning(push)
34 #pragma warning(disable : 4244 4275)
36 #pragma warning(pop)
37 #else
39 #endif
40 
41 Datafield* IOFactory::readDatafield(const std::string& file_name, LoaderSelector selector)
42 {
43  const auto readAs = [=](LoaderSelector testForSelector) {
44  return (selector == testForSelector)
45  || (selector == automatic
46  && fileTypeMatchesLoaderSelector(file_name, testForSelector));
47  };
48 
49  Datafield* result = nullptr;
50 
51  if (readAs(bornagain))
52  result = readDatafield(file_name,
53  [](std::istream& s) { return ReadWriteINT().readDatafield(s); });
54 
55  else if (readAs(nicos))
56  result = readDatafield(file_name, [](std::istream& s) { return IO::readNicosData(s); });
57 
58 #ifdef BA_TIFF_SUPPORT
59  else if (readAs(tiff))
60  result = readDatafield(file_name,
61  [](std::istream& s) { return ReadWriteTiff().readDatafield(s); });
62 #endif
63 
64  else
65  // Try to read ASCII by default. Binary maps to ASCII.
66  // If the file is not actually a matrix of numbers,
67  // the error will be thrown during the reading.
68  result = readDatafield(
69  file_name, [](std::istream& s) { return ReadWriteNumpyTXT().readDatafield(s); });
70 
71  ASSERT(result);
72  return result;
73 }
74 
75 Datafield* IOFactory::readReflectometryData(const std::string& file_name)
76 {
77  return readDatafield(file_name,
78  [](std::istream& s) { return ReadReflectometry().readDatafield(s); });
79 }
80 
81 void IOFactory::writeDatafield(const Datafield& data, const std::string& file_name)
82 {
83  if (DataUtils::Format::isIntFile(file_name))
84  writeDatafield(file_name, [&](std::ostream& s) { ReadWriteINT().writeDatafield(data, s); });
85 #ifdef BA_TIFF_SUPPORT
86  else if (DataUtils::Format::isTiffFile(file_name))
87  writeDatafield(file_name,
88  [&](std::ostream& s) { ReadWriteTiff().writeDatafield(data, s); });
89 #endif
90  else
91  writeDatafield(file_name,
92  [&](std::ostream& s) { ReadWriteNumpyTXT().writeDatafield(data, s); });
93 }
94 
95 void IOFactory::writeDatafield(const std::string& file_name,
96  std::function<void(std::ostream&)> writeData)
97 {
98  using namespace DataUtils::Format;
99 
100  std::ofstream fout;
101  std::ios_base::openmode openmode = std::ios::out;
102  if (isTiffFile(file_name) || isCompressed(file_name))
103  openmode = std::ios::out | std::ios_base::binary;
104 
105 #ifdef _WIN32
106  fout.open(BaseUtils::Filesystem::convert_utf8_to_utf16(file_name), openmode);
107 #else
108  fout.open(file_name, openmode);
109 #endif
110 
111  if (!fout.is_open())
112  throw std::runtime_error("Cannot open file for writing: " + file_name);
113  if (!fout.good())
114  throw std::runtime_error("File is not good, probably it is a directory: " + file_name);
115  std::stringstream ss;
116  writeData(ss);
117 
118  boost::iostreams::filtering_streambuf<boost::iostreams::input> input_filtered;
119  if (DataUtils::Format::isGZipped(file_name))
120  input_filtered.push(boost::iostreams::gzip_compressor());
121  else if (DataUtils::Format::isBZipped(file_name))
122  input_filtered.push(boost::iostreams::bzip2_compressor());
123  input_filtered.push(ss);
124 
125  boost::iostreams::copy(input_filtered, fout);
126 
127  fout.close();
128 }
129 
130 bool IOFactory::fileTypeMatchesLoaderSelector(const std::string& fileName, LoaderSelector selector)
131 {
132  switch (selector) {
133  case bornagain:
134  return DataUtils::Format::isIntFile(fileName);
135  case nicos:
136  return DataUtils::Format::isNicosFile(fileName);
137  case tiff:
138  return DataUtils::Format::isTiffFile(fileName);
139  case automatic:
140  return false;
141  }
142 
143  return false;
144 }
145 
146 void IOFactory::writeSimulationResult(const SimulationResult& result, const std::string& file_name)
147 {
148  auto data = result.datafield();
149  writeDatafield(*data, file_name); // TODO delete ptr
150 }
151 
152 Datafield* IOFactory::readDatafield(const std::string& file_name,
153  std::function<Datafield*(std::istream&)> readData)
154 {
155  if (!BaseUtils::Filesystem::IsFileExists(file_name))
156  throw std::runtime_error("File does not exist: " + file_name);
157 
158  using namespace DataUtils::Format;
159  std::ifstream input_stream;
160  std::ios_base::openmode openmode = std::ios::in;
161  if (isTiffFile(file_name) || isCompressed(file_name))
162  openmode = std::ios::in | std::ios_base::binary;
163 
164 #ifdef _WIN32
165  input_stream.open(BaseUtils::Filesystem::convert_utf8_to_utf16(file_name), openmode);
166 #else
167  input_stream.open(file_name, openmode);
168 #endif
169 
170  if (!input_stream.is_open())
171  throw std::runtime_error("Cannot open file for reading: " + file_name);
172  if (!input_stream.good())
173  throw std::runtime_error("File is not good, probably it is a directory:" + file_name);
174 
175  boost::iostreams::filtering_streambuf<boost::iostreams::input> input_filtered;
176  if (DataUtils::Format::isGZipped(file_name))
177  input_filtered.push(boost::iostreams::gzip_decompressor());
178  else if (DataUtils::Format::isBZipped(file_name))
179  input_filtered.push(boost::iostreams::bzip2_decompressor());
180  input_filtered.push(input_stream);
181  // we use stringstream since it provides random access which is important for tiff files
182  std::stringstream str;
183  boost::iostreams::copy(input_filtered, str);
184 
185  return readData(str);
186 }
187 
188 
189 bool IOUtil::filesAgree(const std::string& datFileName, const std::string& refFileName, double tol)
190 {
191  std::unique_ptr<Datafield> datDat;
192  try {
193  datDat.reset(IOFactory::readDatafield(datFileName));
194  } catch (const std::runtime_error& ex) {
195  std::cerr << "File comparison: Could not read data from file " << datFileName
196  << ". Runtime error: " << ex.what() << std::endl;
197  } catch (const std::exception& ex) {
198  std::cerr << "File comparison: Could not read data from file " << datFileName
199  << ". Exception: " << ex.what() << std::endl;
200  } catch (...) {
201  std::cerr << "File comparison: Could not read data from file " << datFileName
202  << ". Unknown exception." << std::endl;
203  return false;
204  }
205  ASSERT(datDat);
206 
207  std::unique_ptr<Datafield> refDat;
208  try {
209  refDat.reset(IOFactory::readDatafield(refFileName));
210  } catch (...) {
211  std::cerr << "File comparison: Could not read reference data from file " << refFileName
212  << std::endl;
213  return false;
214  }
215  ASSERT(refDat);
216 
217  return DiffUtil::checkRelativeDifference(datDat->flatVector(), refDat->flatVector(), tol);
218 }
Defines the macro ASSERT.
#define ASSERT(condition)
Definition: Assert.h:45
Defines class DatafieldIOFactory.
Defines namespace DataUtils.
Defines namespace FileSystemUtils.
Defines class IOFactory.
Defines ReadReflectometry.
Defines ReadWriteINT.
Defines function IO::readNicosData.
Defines ReadWriteNumpyTXT.
Defines class ReadWriteTiff.
Defines class SimulationResult.
Contains boost streams related headers.
Stores radiation power per bin.
Definition: Datafield.h:30
static bool fileTypeMatchesLoaderSelector(const std::string &fileName, LoaderSelector selector)
Definition: IOFactory.cpp:130
static void writeSimulationResult(const SimulationResult &result, const std::string &file_name)
Writes Datafield contained in the given SimulationResult object.
Definition: IOFactory.cpp:146
static void writeDatafield(const Datafield &data, const std::string &file_name)
Writes Datafield in file.
Definition: IOFactory.cpp:81
static Datafield * readReflectometryData(const std::string &file_name)
Definition: IOFactory.cpp:75
LoaderSelector
Definition: IOFactory.h:48
@ bornagain
Definition: IOFactory.h:48
@ automatic
Definition: IOFactory.h:48
static Datafield * readDatafield(const std::string &file_name, LoaderSelector selector=automatic)
Reads file and returns newly created Datafield object. If selector is automatic, then the file extens...
Definition: IOFactory.cpp:41
Class for reading reflectometry data from ASCII file.
Datafield * readDatafield(std::istream &inStream)
Class for reading and writing BornAgain native IntensityData from ASCII file.
Definition: ReadWriteINT.h:29
Datafield * readDatafield(std::istream &input_stream)
void writeDatafield(const Datafield &data, std::ostream &output_stream)
Class for reading and writing Datafield from simple ASCII file with the layout as in numpy....
void writeDatafield(const Datafield &data, std::ostream &output_stream)
Datafield * readDatafield(std::istream &input_stream)
Wrapper around Datafield that also provides unit conversions.
Datafield * datafield(Coords units=Coords::UNDEFINED) const
std::wstring convert_utf8_to_utf16(const std::string &str)
Converts utf8 string represented by std::string to utf16 string represented by std::wstring.
bool IsFileExists(const std::string &path)
Returns true if file with given name exists on disk.
Utility functions for data input and output.
bool isBZipped(const std::string &name)
Returns true if name contains *.bz2 extension.
bool isIntFile(const std::string &file_name)
Returns true if file name corresponds to BornAgain native format (compressed or not)
bool isGZipped(const std::string &name)
Returns true if name contains *.gz extension.
bool isTiffFile(const std::string &file_name)
Returns true if file name corresponds to tiff file (can be also compressed)
bool isCompressed(const std::string &name)
Returns true if name contains *.gz extension.
bool isNicosFile(const std::string &file_name)
Returns true if file name corresponds to Nicos format (compressed or not)
bool checkRelativeDifference(const std::vector< double > &dat, const std::vector< double > &ref, double threshold)
Returns true is relative difference is below threshold; prints informative output.
Definition: DiffUtil.cpp:64
bool filesAgree(const std::string &datFileName, const std::string &refFileName, double tol)
Returns true if data in both files agree.
Definition: IOFactory.cpp:189
Datafield * readNicosData(std::istream &input_stream)