BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
DataFormatUtils.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/IO/DataFormatUtils.cpp
6 //! @brief Implements class DataFormatUtils.
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 
18 #include "Base/Axis/FixedBinAxis.h"
21 #include "Base/Util/StringUtils.h"
22 #include "Device/Data/Datafield.h"
23 #include <functional>
24 #include <iostream>
25 #include <iterator>
26 
27 namespace {
28 
29 using createAxisFun = std::function<IAxis*(std::istringstream iss)>;
30 
31 const std::string GzipExtension = ".gz";
32 const std::string BzipExtension = ".bz2";
33 const std::string IntExtension = ".int";
34 const std::string NicosExtension = ".001";
35 const std::string TiffExtension = ".tif";
36 const std::string TiffExtension2 = ".tiff";
37 
38 std::istringstream getAxisStringRepresentation(std::istream& input_stream)
39 {
40  std::string line;
41  std::getline(input_stream, line);
42  const std::vector<std::string> to_replace = {",", "\"", "(", ")", "[", "]"};
43  BaseUtils::String::replaceItemsFromString(line, to_replace, " ");
44  return std::istringstream(line);
45 }
46 
47 std::string uncompressedFilename(const std::string& name)
48 {
50  return name.substr(0, name.size() - GzipExtension.size());
52  return name.substr(0, name.size() - BzipExtension.size());
53  return name;
54 }
55 
56 
57 //! Creates one of FixedBinAxis from string representation
58 //! FixedBinAxis("axis0", 10, -1, 1)
59 //! ConstKBinAxis("axis0", 10, -1, 1)
60 //! CustomBinAxis("axis0", 10, -1, 1)
61 template <class Axis>
62 IAxis* createFixedBinLikeAxis(std::istringstream iss)
63 {
64  std::string name;
65  size_t nbins(0);
66  if (!(iss >> name >> nbins))
67  throw std::runtime_error("createFixedBinLikeAxis() -> Error. Can't parse the string.");
68 
69  std::vector<double> boundaries;
70  DataUtils::Format::readLineOfDoubles(boundaries, iss);
71  if (boundaries.size() != 2)
72  throw std::runtime_error("Error in createFixedBinLikeAxis: Can't parse the string while "
73  "reading boundaries.");
74 
75  return new Axis(name, nbins, boundaries[0], boundaries[1]);
76 }
77 
78 //! Creates VariableBinAxis from string representation
79 //! VariableBinAxis("axis0", 4, [-1, -0.5, 0.5, 1, 2])
80 IAxis* createVariableBinAxis(std::istringstream iss)
81 {
82  std::string name;
83  size_t nbins(0);
84  if (!(iss >> name >> nbins))
85  throw std::runtime_error("Error in createVariableBinAxis: Can't parse the string.");
86 
87  std::vector<double> boundaries;
88  DataUtils::Format::readLineOfDoubles(boundaries, iss);
89  if (boundaries.size() != nbins + 1)
90  throw std::runtime_error(
91  "Error in createVariableBinAxis: wrong number of boundaries read.");
92 
93  return new VariableBinAxis(name, boundaries);
94 }
95 
96 //! Creates createPointwiseAxis from string representation
97 //! PointwiseAxis("axis0", [-0.5, 0.5, 1, 2])
98 IAxis* createPointwiseAxis(std::istringstream iss)
99 {
100  std::string name;
101  if (!(iss >> name))
102  throw std::runtime_error("Error in createPointwiseAxis:Can't parse the string.");
103 
104  std::vector<double> coordinates;
105  DataUtils::Format::readLineOfDoubles(coordinates, iss);
106 
107  return new PointwiseAxis(name, coordinates);
108 }
109 
110 const std::vector<std::pair<std::string, createAxisFun>> type_map = {
111  {"ConstKBinAxis", createFixedBinLikeAxis<ConstKBinAxis>},
112  {"CustomBinAxis", createFixedBinLikeAxis<CustomBinAxis>},
113  {"FixedBinAxis", createFixedBinLikeAxis<FixedBinAxis>},
114  {"PointwiseAxis", createPointwiseAxis},
115  {"VariableBinAxis", createVariableBinAxis}};
116 
117 } // namespace
118 
119 
120 bool DataUtils::Format::isCompressed(const std::string& name)
121 {
122  return isGZipped(name) || isBZipped(name);
123 }
124 
125 //! Does name contain *.gz extension?
126 
127 bool DataUtils::Format::isGZipped(const std::string& name)
128 {
129  return BaseUtils::Filesystem::hasExtension(name, GzipExtension);
130 }
131 
132 bool DataUtils::Format::isBZipped(const std::string& name)
133 {
134  return BaseUtils::Filesystem::hasExtension(name, BzipExtension);
135 }
136 
137 bool DataUtils::Format::isIntFile(const std::string& file_name)
138 {
139  return BaseUtils::Filesystem::hasExtension(uncompressedFilename(file_name), IntExtension);
140 }
141 
142 bool DataUtils::Format::isNicosFile(const std::string& file_name)
143 {
144  return BaseUtils::Filesystem::hasExtension(uncompressedFilename(file_name), NicosExtension);
145 }
146 
147 bool DataUtils::Format::isTiffFile(const std::string& file_name)
148 {
149  return BaseUtils::Filesystem::hasExtension(uncompressedFilename(file_name), TiffExtension)
150  || BaseUtils::Filesystem::hasExtension(uncompressedFilename(file_name), TiffExtension2);
151 }
152 
153 //! Creates axis of certain type from input stream
154 IAxis* DataUtils::Format::createAxis(std::istream& input_stream)
155 {
156  auto iss = getAxisStringRepresentation(input_stream);
157  std::string type;
158  if (!(iss >> type))
159  throw std::runtime_error(
160  "Error in DataUtils::Format::createAxis:: couldn't read axis type from input");
161 
162  for (auto iter = type_map.cbegin(); iter != type_map.end(); ++iter)
163  if (iter->first == type)
164  return iter->second(std::move(iss));
165  throw std::runtime_error("Error in DataUtils::Format::createAxis:"
166  "Unknown axis type '"
167  + type + "'");
168 }
169 
170 //! Fills output data raw buffer from input stream
171 void DataUtils::Format::fillDatafield(Datafield* data, std::istream& input_stream)
172 {
173  std::string line;
174  size_t iout = 0;
175  while (std::getline(input_stream, line)) {
176  if (line.empty() || line[0] == '#')
177  break;
178  std::istringstream iss(line);
179  std::vector<double> buffer;
180  readLineOfDoubles(buffer, iss);
181  for (auto value : buffer)
182  (*data)[iout++] = value;
183  }
184  if (iout != data->size())
185  throw std::runtime_error("Error while parsing data, did not reach expected end");
186 }
187 
188 //! Parse double values from string to vector of double
189 
190 // #migration +++ this works only if separator is space or tab; it does not work e.g. with comma or
191 // semicolon
192 std::vector<double> DataUtils::Format::parse_doubles(const std::string& str)
193 {
194  std::vector<double> result;
195  std::istringstream iss(str);
197  if (result.empty()) {
198  std::string out = str;
199  const size_t max_string_length(10);
200  if (out.size() > max_string_length)
201  out.resize(max_string_length, ' ');
202  out += " ...";
203  throw std::runtime_error("DataUtils::Format::parse_doubles -> Error! Can't parse double "
204  "values from a string '"
205  + out + "'");
206  }
207  return result;
208 }
209 
210 // #migration +++ this works only if separator is space or tab; it does not work e.g. with comma or
211 // semicolon
212 void DataUtils::Format::readLineOfDoubles(std::vector<double>& buffer, std::istringstream& iss)
213 {
214  iss.imbue(std::locale::classic());
215  std::copy(std::istream_iterator<double>(iss), std::istream_iterator<double>(),
216  back_inserter(buffer));
217 }
Defines a few helper functions.
Defines class ConstKBinAxis.
Defines class CustomBinAxis.
Defines class DatafieldIOFactory.
Defines and implements templated class Datafield.
Defines namespace FileSystemUtils.
Defines class FixedBinAxis.
Defines class PointwiseAxis.
Stores radiation power per bin.
Definition: Datafield.h:30
size_t size() const
Returns total size of data buffer (product of bin number in every dimension).
Definition: Datafield.cpp:80
Abstract base class for one-dimensional axes.
Definition: IAxis.h:27
Axis containing arbitrary (non-equidistant) coordinate values. Lower boundary of the first bin and up...
Definition: PointwiseAxis.h:33
Axis with variable bin size.
bool hasExtension(const std::string &path, const std::string &ref_extension)
Returns true if extension of path, converted to lower case, matches given reference extension.
void replaceItemsFromString(std::string &text, const std::vector< std::string > &items, const std::string &replacement="")
Replaces all occurrences of items from string text with delimiter.
Definition: StringUtils.cpp:37
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)
std::vector< double > parse_doubles(const std::string &str)
Parse double values from string to vector of double.
void readLineOfDoubles(std::vector< double > &buffer, std::istringstream &iss)
void fillDatafield(Datafield *data, std::istream &input_stream)
Fills output data raw buffer from input stream.
bool isGZipped(const std::string &name)
Returns true if name contains *.gz extension.
IAxis * createAxis(std::istream &input_stream)
Creates axis of certain type from input stream.
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)