faunus
table_1d.h
1 #pragma once
2 
3 #include <Eigen/Core>
4 #include <vector>
5 #include <fstream>
6 
7 namespace Faunus {
8 
13 template <typename Tcoeff = double,
14  typename base = Eigen::Matrix<Tcoeff, Eigen::Dynamic, Eigen::Dynamic>>
15 class Table : public base
16 {
17  private:
18  using Tvec = std::vector<double>;
19  Tvec _bw, _lo, _hi;
20  using index_t = typename base::Index;
21  static_assert(std::is_integral_v<index_t> && std::is_signed_v<index_t>,
22  "signed integral value expected");
23  index_t _rows;
24  index_t _cols;
25 
26  public:
27  explicit Table(const Tvec& bw = {1, 1}, const Tvec& lo = {0, 0}, const Tvec& hi = {2, 2})
28  {
29  reInitializer(bw, lo, hi);
30  }
31 
32  // required for assignment from Eigen::Matrix and Eigen::Array objects
33  template <typename OtherDerived>
34  explicit Table(const Eigen::MatrixBase<OtherDerived>& other)
35  : base(other)
36  {
37  }
38 
39  template <typename OtherDerived> Table& operator=(const Eigen::MatrixBase<OtherDerived>& other)
40  {
41  this->base::operator=(other);
42  return *this;
43  }
44 
45  template <typename OtherDerived>
46  explicit Table(const Eigen::ArrayBase<OtherDerived>& other)
47  : base(other)
48  {
49  }
50 
51  template <typename OtherDerived> Table& operator=(const Eigen::ArrayBase<OtherDerived>& other)
52  {
53  this->base::operator=(other);
54  return *this;
55  }
56 
57  void reInitializer(const Tvec& bw, const Tvec& lo, const Tvec& hi)
58  {
59  assert(bw.size() == 1 || bw.size() == 2);
60  assert(bw.size() == lo.size() && lo.size() == hi.size());
61  _bw = bw;
62  _lo = lo;
63  _hi = hi;
64  _rows = (_hi[0] - _lo[0]) / _bw[0] + 1.;
65  if (bw.size() == 2) {
66  _cols = (_hi[1] - _lo[1]) / _bw[1] + 1;
67  }
68  else {
69  _cols = 1;
70  }
71  base::resize(_rows, _cols);
72  base::setZero();
73  }
74 
75  void round(Tvec& v) const
76  {
77  for (Tvec::size_type i = 0; i != v.size(); ++i) {
78  v[i] =
79  (v[i] >= 0) ? int(v[i] / _bw[i] + 0.5) * _bw[i] : int(v[i] / _bw[i] - 0.5) * _bw[i];
80  }
81  }
82 
83  void to_index(Tvec& v) const
84  {
85  for (Tvec::size_type i = 0; i != v.size(); ++i) {
86  v[i] = (v[i] >= 0) ? int(v[i] / _bw[i] + 0.5) : int(v[i] / _bw[i] - 0.5);
87  v[i] = v[i] - _lo[i] / _bw[i];
88  }
89  v.resize(2, 0);
90  }
91 
92  Tcoeff& operator[](const Tvec& v)
93  {
94  return base::operator()(static_cast<index_t>(v[0]), static_cast<index_t>(v[1]));
95  }
96 
97  bool isInRange(const Tvec& v) const
98  {
99  bool in_range = true;
100  for (Tvec::size_type i = 0; i != v.size(); ++i) {
101  in_range = in_range && v[i] >= _lo[i] && v[i] <= _hi[i];
102  }
103  return in_range;
104  }
105 
106  Tvec hist2buf(int) const
107  {
108  Tvec sendBuf;
109  for (index_t i = 0; i < _cols; ++i) {
110  for (index_t j = 0; j < _rows; ++j) {
111  sendBuf.push_back(base::operator()(j, i));
112  }
113  }
114  return sendBuf;
115  }
116 
117  void buf2hist(const Tvec& v)
118  {
119  assert(!v.empty());
120  base::setZero();
121  auto p = static_cast<int>(v.size()) / this->size();
122  Tvec::size_type n = 0;
123  double nproc = p;
124  while (p-- > 0) {
125  for (index_t i = 0; i < _cols; ++i) {
126  for (index_t j = 0; j < _rows; ++j) {
127  base::operator()(j, i) += v.at(n++) / nproc;
128  }
129  }
130  }
131  }
132 
133  base getBlock(const Tvec& slice)
134  { // {xmin,xmax} or {xmin,xmax,ymin,ymax}
135  Tvec w(4, 0);
136  switch (slice.size()) {
137  case 1:
138  w[0] = w[1] = (slice[0] - _lo[0]) / _bw[0];
139  w[3] = _cols - 1;
140  break;
141  case 2:
142  w[0] = (slice[0] - _lo[0]) / _bw[0];
143  w[1] = (slice[1] - _lo[0]) / _bw[0];
144  break;
145  case 3:
146  w[0] = w[1] = _rows - 1;
147  w[2] = w[3] = _cols - 1;
148  break;
149  case 4:
150  w[0] = (slice[0] - _lo[0]) / _bw[0];
151  w[1] = (slice[1] - _lo[0]) / _bw[0];
152  w[2] = (slice[2] - _lo[1]) / _bw[1];
153  w[3] = (slice[3] - _lo[1]) / _bw[1];
154  }
155  return this->block(w[0], w[2], w[1] - w[0] + 1, w[3] - w[2] + 1); // xmin,ymin,rows,cols
156  }
157 
158  Tcoeff avg(const Tvec& v) const { return this->getBlock(v).mean(); }
159 
160  void save(const std::string& filename, Tcoeff scale = 1, Tcoeff translate = 0) const
161  {
162  Eigen::VectorXd v1(_cols + 1);
163  Eigen::VectorXd v2(_rows + 1);
164  v1(0) = v2(0) = base::size();
165  for (index_t i = 1; i != _cols + 1; ++i) {
166  v1(i) = (i - 1) * _bw[1] + _lo[1];
167  }
168  for (index_t i = 1; i != _rows + 1; ++i) {
169  v2(i) = (i - 1) * _bw[0] + _lo[0];
170  }
171  base m(_rows + 1, _cols + 1);
172  m.leftCols(1) = v2;
173  m.topRows(1) = v1.transpose();
174  m.bottomRightCorner(_rows, _cols) = *this;
175  if (scale != 1) {
176  m.bottomRightCorner(_rows, _cols) *= scale;
177  }
178  if (translate != 0) {
179  m.bottomRightCorner(_rows, _cols) += base::Constant(_rows, _cols, translate);
180  }
181  std::ofstream stream(filename.c_str());
182  if (stream) {
183  stream.precision(10);
184  if (_cols == 1) {
185  stream << "#";
186  }
187  stream << m;
188  }
189  }
190 
191  void saveRow(const std::string& filename, const Tvec& v, Tcoeff scale = 1, Tcoeff translate = 0)
192  {
193  if (!this->isInRange(v)) {
194  return;
195  }
196  auto b = this->getBlock(v);
197  auto size = b.size();
198  Eigen::VectorXd w(size);
199  for (index_t i = 0; i != size; ++i) {
200  w(i) = i * _bw[1] + _lo[1];
201  }
202  base m(size, 2);
203  m.leftCols(1) = w;
204  m.bottomRightCorner(size, 1) = b.transpose();
205  if (scale != 1) {
206  m.bottomRightCorner(size, 1) *= scale;
207  }
208  if (translate != 0) {
209  m.bottomRightCorner(size, 1) += base::Constant(size, 1, translate);
210  }
211  std::ofstream stream(filename.c_str());
212  if (stream) {
213  stream.precision(10);
214  stream << m;
215  }
216  }
217 
218  void load(const std::string& filename)
219  {
220  if (std::ifstream f(filename.c_str()); f) {
221  index_t i = 0;
222  index_t j = -1;
223  std::string line;
224  getline(f, line);
225  while (getline(f, line)) {
226  if (i > _rows - 1 || j > _cols - 1) {
227  throw std::runtime_error("file larger than expected:"s + filename);
228  }
229  j = -1;
230  const std::istringstream iss(line);
231  Tcoeff a;
232  Tcoeff b;
233  iss >> a;
234  while (iss >> b) {
235  base::operator()(i, ++j) = b;
236  }
237  ++i;
238  }
239  if (i != _rows || j != _cols - 1) {
240  throw std::runtime_error("file larger than expected:"s + filename);
241  }
242  }
243  }
244 };
245 
246 } // namespace Faunus
Dynamic table for 1d data.
Definition: table_1d.h:15
Cell list class templates.
Definition: actions.cpp:11