BornAgain  1.19.79
Open-source research software to simulate and fit neutron and x-ray reflectometry and grazing-incidence small-angle scattering
ReadWriteNumpyTXT.cpp
Go to the documentation of this file.
1 // ************************************************************************************************
2 //
3 // BornAgain: simulate and fit reflection and scattering
4 //
5 //! @file Device/IO/ReadWriteNumpyTXT.cpp
6 //! @brief Implements class ReadWriteNumpyTXT.
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 
16 #include "Base/Axis/Bin.h"
17 #include "Base/Axis/IAxis.h"
18 #include "Base/Util/StringUtils.h"
19 #include "Device/Data/ArrayUtils.h"
21 #include <string>
22 #include <vector>
23 
24 namespace {
25 
26 bool isDoubleStartChar(char c)
27 {
28  return isdigit(c) || c == '-' || c == '+';
29 }
30 
31 } // namespace
32 
33 Datafield* ReadWriteNumpyTXT::readDatafield(std::istream& input_stream)
34 {
35  std::string line;
36  std::vector<std::vector<double>> data;
37 
38  // Read numbers from input stream:
39  while (std::getline(input_stream, line)) {
40  line = BaseUtils::String::trim(line);
41  if (line.empty() || !isDoubleStartChar(line[0]))
42  continue;
43 
44  try {
45  std::vector<double> dataInRow = DataUtils::Format::parse_doubles(line);
46  data.push_back(dataInRow);
47  } catch (...) {
48  continue;
49  }
50  }
51 
52  // validating
53  size_t nrows = data.size();
54  size_t ncols(0);
55  if (nrows)
56  ncols = data[0].size();
57 
58  if (ncols == 0)
59  throw std::runtime_error("ReadNumpyTXTStrategy::readDatafield() -> Error. "
60  "Can't parse file");
61 
62  for (size_t row = 0; row < nrows; row++) {
63  if (data[row].size() != ncols)
64  throw std::runtime_error("ReadNumpyTXTStrategy::readDatafield() -> Error. "
65  "Number of elements is different from row to row.");
66  }
67 
68  if (nrows < 2)
69  return DataUtils::Array::createPField1D(data[0]).release();
70 
71  if (ncols < 2) {
72  const size_t size = data.size();
73  std::vector<double> vector1d(size);
74  for (size_t i = 0; i < size; ++i)
75  vector1d[i] = data[i][0];
76  return DataUtils::Array::createPField1D(vector1d).release();
77  }
78 
79  return DataUtils::Array::createPField2D(data).release();
80 }
81 
82 void ReadWriteNumpyTXT::writeDatafield(const Datafield& data, std::ostream& output_stream)
83 {
84  output_stream << "# BornAgain Intensity Data" << std::endl;
85  output_stream << "# Simple array suitable for numpy, matlab etc." << std::endl;
86 
87  const size_t dim = data.rank();
88  switch (dim) {
89  case 1:
90  write1DRepresentation(data, output_stream);
91  break;
92  case 2:
93  write2DRepresentation(data, output_stream);
94  break;
95  default:
96  throw std::runtime_error("Error in DatafieldWriteNumpyTXTStrategy::writeDatafield: data "
97  "of unsupported dimensions");
98  }
99 }
100 
101 void ReadWriteNumpyTXT::write1DRepresentation(const Datafield& data, std::ostream& output_stream)
102 {
103  output_stream << "# coordinates intensities" << std::endl;
104  output_stream.imbue(std::locale::classic());
105  output_stream << std::scientific << std::setprecision(12);
106 
107  const std::vector<double> axis_values = data.axis(0).binCenters();
108 
109  // printing coordinate and associated intensity
110  for (size_t i = 0, nrows = axis_values.size(); i < nrows; ++i)
111  output_stream << axis_values[i] << " " << ignoreDenormalized(data[i]) << std::endl;
112 }
113 
114 void ReadWriteNumpyTXT::write2DRepresentation(const Datafield& data, std::ostream& output_stream)
115 {
116  const size_t nrows = data.axis(1).size();
117  const size_t ncols = data.axis(0).size();
118 
119  output_stream << "# [nrows=" << nrows << ", ncols=" << ncols << "]" << std::endl;
120 
121  std::vector<std::vector<double>> dataArray = DataUtils::Array::createVector2D(data);
122  output_stream.imbue(std::locale::classic());
123  output_stream << std::scientific << std::setprecision(12);
124 
125  for (size_t i = 0; i < nrows; i++) {
126  for (size_t j = 0; j < ncols; j++) {
127  double z_value = dataArray[i][j];
128  output_stream << ignoreDenormalized(z_value) << " ";
129  }
130  output_stream << std::endl;
131  }
132 }
133 
135 {
136  return (std::fpclassify(value) == FP_SUBNORMAL) ? 0.0 : value;
137 }
Defines various functions to interact from numpy on Python side.
Defines a few helper functions.
Defines structs Bin1D, Bin1DCVector.
Defines class DatafieldIOFactory.
Defines interface IAxis.
Defines ReadWriteNumpyTXT.
Stores radiation power per bin.
Definition: Datafield.h:30
const IAxis & axis(size_t k) const
Definition: Datafield.cpp:91
size_t rank() const
Definition: Datafield.cpp:75
virtual std::vector< double > binCenters() const
Definition: IAxis.cpp:25
virtual size_t size() const =0
Returns the number of bins.
static double ignoreDenormalized(double value)
static void write2DRepresentation(const Datafield &data, std::ostream &output_stream)
void writeDatafield(const Datafield &data, std::ostream &output_stream)
Datafield * readDatafield(std::istream &input_stream)
static void write1DRepresentation(const Datafield &data, std::ostream &output_stream)
std::string scientific(T value, int n=10)
Returns scientific string representing given value of any numeric type.
Definition: StringUtils.h:75
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
std::vector< std::vector< double > > createVector2D(const Datafield &data)
Creates 2D vector from Datafield.
Definition: ArrayUtils.cpp:73
std::unique_ptr< Datafield > createPField1D(const std::vector< double > &vec)
Definition: ArrayUtils.cpp:32
std::unique_ptr< Datafield > createPField2D(const std::vector< std::vector< double >> &vec)
Definition: ArrayUtils.cpp:40
std::vector< double > parse_doubles(const std::string &str)
Parse double values from string to vector of double.