BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
ReadWriteNicos.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/IO/ReadWriteNicos.cpp
6 //! @brief Implements function IO::readNicosData
7 //!
8 //! @homepage http://www.bornagainproject.org
9 //! @license GNU General Public License v3 or higher (see COPYING)
10 //! @copyright Forschungszentrum Jülich GmbH 2021
11 //! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
12 //
13 // ************************************************************************************************
14 
16 #include "Base/Axis/FixedBinAxis.h"
17 #include "Base/Axis/Frame.h"
18 #include "Base/Util/StringUtils.h"
19 #include <memory>
20 
21 namespace {
22 
23 std::string lineRelatedError(const std::string& errorText, int lineNumber)
24 {
25  return "Line " + std::to_string(lineNumber) + ": " + errorText;
26 }
27 
28 
29 unsigned int readAssignedPositiveIntValue(const std::string& line, int lineNumber)
30 {
31  const auto parts = BaseUtils::String::split(line, "=");
32  if (parts.size() != 2)
33  throw std::runtime_error(lineRelatedError("Missing assigned value", lineNumber));
34 
35  int value = 0;
36  if (!BaseUtils::String::to_int(parts[1], &value))
37  throw std::runtime_error(
38  lineRelatedError("Can't parse assigned value '" + parts[1] + "'", lineNumber));
39 
40  if (value <= 0)
41  throw std::runtime_error(
42  lineRelatedError("Value of '" + parts[1] + "' is nonpositive", lineNumber));
43 
44  return value;
45 }
46 
47 } // namespace
48 
49 
50 Datafield* IO::readNicosData(std::istream& input_stream)
51 {
52  std::string line;
53  int lineNumber = 0;
54 
55  unsigned int width = 0;
56  unsigned int height = 0;
57 
58  // -- read dimensions
59  bool inFileSection = false;
60  bool fileSectionFound = false;
61  bool typeFound = false;
62  while (std::getline(input_stream, line)) {
63  lineNumber++;
64  line = BaseUtils::String::trimFront(line, " ");
65 
66  if (!inFileSection) {
67  if (BaseUtils::String::startsWith(line, "%File")) {
68  inFileSection = true;
69  fileSectionFound = true;
70  continue;
71  }
72  continue;
73  }
74 
75  if (BaseUtils::String::startsWith(line, "%"))
76  break; // next section
77 
78  if (BaseUtils::String::startsWith(line, "Type=")) {
79  const auto parts = BaseUtils::String::split(line, "=");
80  if (parts[1] != "SANSDRaw")
81  throw std::runtime_error(
82  lineRelatedError("Unsupported file type '" + parts[1] + "'", lineNumber));
83  typeFound = true;
84  }
85 
86  if (BaseUtils::String::startsWith(line, "DataSizeX"))
87  width = readAssignedPositiveIntValue(line, lineNumber);
88  else if (BaseUtils::String::startsWith(line, "DataSizeY"))
89  height = readAssignedPositiveIntValue(line, lineNumber);
90  if (width != 0 && height != 0)
91  break;
92  }
93 
94  if (!fileSectionFound)
95  throw std::runtime_error("Could not find 'File' section");
96  if (!typeFound)
97  throw std::runtime_error("File type not found");
98  if (width == 0)
99  throw std::runtime_error("Could not find 'DataSizeX' value");
100  if (height == 0)
101  throw std::runtime_error("Could not find 'DataSizeY' value");
102 
103  auto frame = new Frame(
104  {new FixedBinAxis("x", width, 0.0, width),
105  new FixedBinAxis("y", height, 0.0, height)});
106  auto result = std::make_unique<Datafield>(frame);
107 
108  // -- read data
109  bool inCountSection = false;
110  bool countSectionFound = false;
111  unsigned int dataRow = 0;
112 
113  while (std::getline(input_stream, line)) {
114  lineNumber++;
115  line = BaseUtils::String::trimFront(line, " ");
116 
117  if (!inCountSection) {
118  if (BaseUtils::String::startsWith(line, "%Counts")) {
119  inCountSection = true;
120  countSectionFound = true;
121  continue;
122  }
123  continue;
124  }
125 
126  if (BaseUtils::String::startsWith(line, "%"))
127  break; // next section
128 
129  // line is a data line
130  line = BaseUtils::String::trim(line, " ");
131  if (line.empty())
132  continue;
133 
134  const auto valuesAsString = BaseUtils::String::split(line, ",");
135  if (valuesAsString.size() != width)
136  throw std::runtime_error(
137  lineRelatedError("Number of found values (" + std::to_string(valuesAsString.size())
138  + ") does not match DataSizeX (" + std::to_string(width) + ")",
139  lineNumber));
140 
141  for (unsigned col = 0; col < width; ++col) {
142  const size_t global_index = result->frame().toGlobalIndex(
143  {col, height - 1 - dataRow}); // y-axis "0" is at bottom => invert y
144  // to show first line at top of image
145 
146  int value = 0;
147  if (!BaseUtils::String::to_int(valuesAsString[col], &value))
148  throw std::runtime_error(lineRelatedError(
149  "Value '" + valuesAsString[col] + "' could not be converted to integer",
150  lineNumber));
151 
152  (*result)[global_index] = value;
153  }
154  dataRow++;
155 
156  if (dataRow == height)
157  break;
158  }
159 
160  if (!countSectionFound)
161  throw std::runtime_error("Could not find 'Counts' section");
162  if (dataRow != height)
163  throw std::runtime_error("Number of found data rows (" + std::to_string(dataRow)
164  + ") does not match DataSizeY (" + std::to_string(height) + ")");
165 
166  return result.release();
167 }
Defines a few helper functions.
Defines class FixedBinAxis.
Defines and implements templated class Frame.
Defines function IO::readNicosData.
Stores radiation power per bin.
Definition: Datafield.h:30
Axis with fixed bin size.
Definition: FixedBinAxis.h:23
Holds one or two axes.
Definition: Frame.h:27
size_t toGlobalIndex(const std::vector< unsigned > &axes_indices) const
Returns global index for specified indices of axes.
Definition: Frame.cpp:79
std::vector< std::string > split(const std::string &text, const std::string &delimiter)
Split string into vector of string using delimiter.
Definition: StringUtils.cpp:29
std::string trim(const std::string &str, const std::string &whitespace=" \t")
Cuts any of the chars given in whitespace from start and end of str.
Definition: StringUtils.cpp:87
bool to_int(const std::string &str, int *result)
Interprets the contained text as an integer and returns it in result. Space chars at its begin and en...
Definition: StringUtils.cpp:64
std::string trimFront(const std::string &str, const std::string &whitespace=" \t")
Cuts any of the chars given in whitespace from start.
bool startsWith(const std::string &str, const std::string &substr)
True if the string starts with substr. The comparison is case sensitive.
Datafield * readNicosData(std::istream &input_stream)