SSAGES  0.9.3
Software Suite for Advanced General Ensemble Simulations
Grid.h
1 
20 #pragma once
21 
22 #include <exception>
23 #include <fstream>
24 #include <istream>
25 
26 #include "Drivers/DriverException.h"
27 #include "GridBase.h"
28 #include "schema.h"
29 #include "Validator/ObjectRequirement.h"
30 
31 namespace SSAGES
32 {
33 
35 
57 template<typename T>
58 class Grid : public GridBase<T>
59 {
60 private:
62 
70  size_t mapTo1d(const std::vector<int> &indices) const override
71  {
72  // Check if an index is out of bounds
73  for (size_t i = 0; i < GridBase<T>::GetDimension(); ++i) {
74  int index = indices.at(i);
75  int numpoints = GridBase<T>::numPoints_[i];
76  if ( index < 0 || index >= numpoints )
77  {
78  throw std::out_of_range("Grid index out of range.");
79  }
80  }
81 
82  size_t idx = 0;
83  size_t fac = 1;
84  for (size_t i = 0; i < GridBase<T>::GetDimension(); ++i) {
85  idx += indices.at(i) * fac;
86  fac *= GridBase<T>::numPoints_[i];
87  }
88  return idx;
89  }
90 
91 public:
93 
103  Grid(std::vector<int> numPoints,
104  std::vector<double> lower,
105  std::vector<double> upper,
106  std::vector<bool> isPeriodic)
107  : GridBase<T>(numPoints, lower, upper, isPeriodic)
108  {
109  size_t data_size = 1;
110  for (size_t d = 0; d < GridBase<T>::GetDimension(); ++d) {
111  size_t storage_size = GridBase<T>::numPoints_[d];
112  data_size *= storage_size;
113  }
114 
115  GridBase<T>::data_.resize(data_size);
116  }
117 
119 
127  static Grid<T>* BuildGrid(const Json::Value& json)
128  {
129  return BuildGrid(json, "#/Grid");
130  }
131 
133 
142  static Grid<T>* BuildGrid(const Json::Value& json, const std::string& path)
143  {
144  Json::ObjectRequirement validator;
145  Json::Value schema;
146  Json::CharReaderBuilder rbuilder;
147  Json::CharReader* reader = rbuilder.newCharReader();
148 
149  reader->parse(JsonSchema::grid.c_str(),
150  JsonSchema::grid.c_str() + JsonSchema::grid.size(),
151  &schema, nullptr);
152  validator.Parse(schema, path);
153 
154  // Validate inputs.
155  validator.Validate(json, path);
156  if (validator.HasErrors()) {
157  throw BuildException(validator.GetErrors());
158  }
159 
160  // Read in Lower Grid edges.
161  std::vector<double> lower;
162  for (auto &lv : json["lower"]) {
163  lower.push_back(lv.asDouble());
164  }
165 
166  size_t dimension = lower.size();
167 
168  // Read in upper grid edges.
169  std::vector<double> upper;
170  for (auto &uv : json["upper"]) {
171  upper.push_back(uv.asDouble());
172  }
173 
174  if (upper.size() != dimension) {
175  throw BuildException({"Number of upper values does not match "
176  "number of lower values!"});
177  }
178 
179  // Read in number of points.
180  std::vector<int> number_points;
181  for (auto &np : json["number_points"]) {
182  number_points.push_back(np.asInt());
183  }
184 
185  if (number_points.size() != dimension) {
186  throw BuildException({"Arrays \"lower\" and \"number_points\" do "
187  "not have the same size!"});
188  }
189 
190  // Read in periodicity.
191  std::vector<bool> isPeriodic;
192  for (auto &periodic : json["periodic"]) {
193  isPeriodic.push_back(periodic.asBool());
194  }
195 
196  if (isPeriodic.size() == 0) {
197  isPeriodic = std::vector<bool>(dimension, false);
198  } else if (isPeriodic.size() != dimension) {
199  throw BuildException({"Arrays \"lower\" and \"periodic\" do not "
200  "have the same size!"});
201  }
202 
203  // Construct the grid.
204  Grid<T>* grid = new Grid(number_points, lower, upper, isPeriodic);
205 
206  return grid;
207  }
208 
210 
246  template<typename R>
247  class GridIterator {
248  public:
251 
253  typedef int difference_type;
254 
256  typedef R value_type;
257 
259  typedef R* pointer;
260 
262  typedef R& reference;
263 
265  typedef std::bidirectional_iterator_tag iterator_category;
266 
268  GridIterator() = default;
269 
271 
276  GridIterator(const std::vector<int> &indices, Grid<T> *grid)
277  : indices_(indices), grid_(grid)
278  {
279  }
280 
282 
287  GridIterator(const std::vector<int> &indices, const Grid<T> *grid)
288  : indices_(indices), grid_(grid)
289  {
290  }
291 
293 
297  : indices_(other.indices_), grid_(other.grid_)
298  {
299  }
300 
302 
305  reference operator*() { return grid_->at(indices_); }
306 
308 
316  {
317  indices_.at(0) += 1;
318  for (size_t i = 0; i < grid_->GetDimension() - 1; ++i) {
319  if (indices_.at(i) >= grid_->numPoints_[i]) {
320  indices_.at(i) = 0;
321  indices_.at(i+1) += 1;
322  }
323  }
324 
325  return *this;
326  }
327 
329 
333  {
334  GridIterator it(*this);
335  ++(*this);
336  return it;
337  }
338 
340 
356  self_type &operator+=(std::vector<int> shift)
357  {
358  if (shift.size() != grid_->GetDimension()) {
359  throw std::invalid_argument("Vector to shift iterator does not "
360  "match grid dimension.");
361  }
362 
363  for (size_t i = 0; i < grid_->GetDimension(); ++i) {
364  indices_.at(i) += shift.at(i);
365  }
366 
367  return *this;
368  }
369 
371 
377  const self_type operator+(std::vector<int> shift)
378  {
379  return GridIterator(*this) += shift;
380  }
381 
383 
390  {
391  indices_.at(0) -= 1;
392  for (size_t i = 0; i < grid_->GetDimension() - 1; ++i) {
393  if (indices_.at(i) < 0) {
394  indices_.at(i) = grid_->numPoints_[i]-1;
395  indices_.at(i+1) -= 1;
396  }
397  }
398 
399  return *this;
400  }
401 
403 
407  {
408  GridIterator it(*this);
409  --(*this);
410  return it;
411  }
412 
414 
418  self_type &operator-=(std::vector<int> shift)
419  {
420  if (shift.size() != grid_->GetDimension()) {
421  throw std::invalid_argument("Vector to shift iterator does not "
422  "match histogram dimension.");
423  }
424 
425  for (size_t i = 0; i < grid_->GetDimension(); ++i) {
426  indices_.at(i) -= shift.at(i);
427  }
428 
429  return *this;
430  }
431 
433 
437  const self_type operator-(std::vector<int> shift)
438  {
439  return GridIterator(*this) -= shift;
440  }
441 
443 
448  bool operator==(const self_type &rhs) const
449  {
450  return indices_ == rhs.indices_ && grid_ == rhs.grid_;
451  }
452 
454 
459  bool operator!=(const self_type &rhs) const
460  {
461  return !( (*this) == rhs );
462  }
463 
465 
471  std::vector<int> &indices()
472  {
473  return indices_;
474  }
475 
477 
482  int &index(size_t d)
483  {
484  return indices()[d];
485  }
486 
488 
491  std::vector<double> coordinates() const
492  {
493  return grid_->GetCoordinates(indices_);
494  }
495 
497 
501  double coordinate(size_t d) const
502  {
503  return coordinates()[d];
504  }
505 
506  private:
508  std::vector<int> indices_;
509 
512  };
513 
516 
519 
521 
528  {
529  std::vector<int> indices(GridBase<T>::GetDimension(), 0);
530 
531  return iterator(indices, this);
532  }
533 
535 
541  {
542  std::vector<int> indices(GridBase<T>::GetDimension());
543  for (size_t i = 0; i < indices.size(); ++i) {
544  indices.at(i) = GridBase<T>::numPoints_[i] - 1;
545  }
546 
547  iterator it(indices, this);
548  return ++it;
549  }
550 
552 
559  {
560  std::vector<int> indices(GridBase<T>::GetDimension(), 0);
561 
562  return iterator(indices, this);
563  }
564 
566 
572  {
573  std::vector<int> indices(GridBase<T>::GetDimension());
574  for (size_t i = 0; i < indices.size(); ++i) {
575  indices.at(i) = GridBase<T>::numPoints_[i] - 1;
576  }
577 
578  iterator it(indices, this);
579  return ++it;
580  }
581 
583 
586  void WriteToFile(const std::string& filename)
587  {
588  std::ofstream output(filename.c_str(), std::ofstream::out);
589 
590  // Print out header.
591  output << "#! type grid\n";
592  output << "#! dim " << GridBase<T>::dimension_ << "\n";
593  output << "#! count ";
594  for(auto& c : this->GetNumPoints())
595  output << c << " ";
596  output << "\n";
597  output << "#! lower ";
598  for(auto& l : this->GetLower())
599  output << l << " ";
600  output << "\n";
601  output << "#! upper ";
602  for(auto& u : this->GetUpper())
603  output << u << " ";
604  output << "\n";
605  output << "#! periodic ";
606  for(auto p : GridBase<T>::isPeriodic_)
607  output << p << " ";
608  output << "\n";
609 
610  for(auto it = this->begin(); it != this->end(); ++it)
611  {
612  auto coords = it.coordinates();
613  for(auto& c : coords)
614  output << std::setprecision(8) << std::fixed << c << " ";
615  output.unsetf(std::ios_base::fixed);
616  output << std::setprecision(16) << *it << "\n";
617  }
618 
619  output.close();
620  }
621 
623 
629  void LoadFromFile(const std::string& filename)
630  {
631  std::ifstream file(filename);
632  if (!file)
633  throw BuildException ({"Attempt to load grid " + filename + " unsuccessful."});
634 
635  std::string line, buff;
636 
637  // Skip type for now.
638  std::getline(file, line);
639 
640  // Get dimension.
641  {
642  size_t dim = 0;
643  std::getline(file, line);
644  std::istringstream iss(line);
645  iss >> buff >> buff >> dim;
646  if(dim != GridBase<T>::dimension_)
647  throw std::invalid_argument(filename +
648  ": Expected dimension " + std::to_string(GridBase<T>::dimension_) +
649  " but got " + std::to_string(dim) + " instead.");
650  }
651 
652  // Get size.
653  {
654  std::getline(file, line);
655  std::istringstream iss(line);
656  int count = 0;
657  auto counts = GridBase<T>::numPoints_;
658  iss >> buff >> buff;
659  for(int i = 0; iss >> count; ++i)
660  {
661  if((count) != counts[i])
662  throw std::invalid_argument(filename +
663  ": Expected count " + std::to_string(counts[i]) +
664  " on dimension " + std::to_string(i) + " but got " +
665  std::to_string(count) + " instead.");
666  }
667  }
668 
669  // Get lower bounds.
670  {
671  std::getline(file, line);
672  std::istringstream iss(line);
673  double lower = 0;
674  auto lowers = GridBase<T>::edges_.first;
675  iss >> buff >> buff;
676  for(int i = 0; iss >> lower; ++i)
677  {
678  double spacing = 0;
680  {
681  spacing = (GridBase<T>::edges_.second[i] - GridBase<T>::edges_.first[i]) / (GridBase<T>::numPoints_[i]);
682  }
683  if(std::abs(lower-spacing/2 - lowers[i]) > 1e-8)
684  throw std::invalid_argument(filename +
685  ": Expected lower " + std::to_string(lowers[i]+spacing/2) +
686  " on dimension " + std::to_string(i) + " but got " +
687  std::to_string(lower) + " instead.");
688  }
689  }
690 
691  // Get upper bounds.
692  {
693  std::getline(file, line);
694  std::istringstream iss(line);
695  double upper = 0;
696  auto uppers = GridBase<T>::edges_.second;
697  iss >> buff >> buff;
698  for(int i = 0; iss >> upper; ++i)
699  {
700  double spacing = 0;
702  {
703  spacing = (GridBase<T>::edges_.second[i] - GridBase<T>::edges_.first[i]) / (GridBase<T>::numPoints_[i]);
704  }
705  if(std::abs((upper+spacing/2) - uppers[i]) > 1e-8)
706  throw std::invalid_argument(filename +
707  ": Expected upper " + std::to_string(uppers[i]-spacing/2) +
708  " on dimension " + std::to_string(i) + " but got " +
709  std::to_string(upper) + " instead.");
710  }
711  }
712 
713  // Get periodic.
714  {
715  std::getline(file, line);
716  std::istringstream iss(line);
717  bool periodic;
718  auto periodics = GridBase<T>::isPeriodic_;
719  iss >> buff >> buff;
720  for(int i = 0; iss >> periodic; ++i)
721  {
722  if(periodic != periodics[i])
723  throw std::invalid_argument(filename +
724  ": Expected periodic " + std::to_string(periodics[i]) +
725  " on dimension " + std::to_string(i) + " but got " +
726  std::to_string(periodic) + " instead.");
727  }
728  }
729 
730  // Finally load data.
731  for(auto& d : GridBase<T>::data_)
732  {
733  std::getline(file, line);
734  std::istringstream iss(line);
735 
736  // Skip coordinates.
737  for(size_t i = 0; i < GridBase<T>::dimension_; ++i)
738  iss >> buff;
739 
740  iss >> d;
741  }
742  }
743 };
744 
745 } // End namespace SSAGES
Requirements on an object.
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.
std::vector< std::string > GetErrors()
Get list of error messages.
Definition: Requirement.h:92
bool HasErrors()
Check if errors have occured.
Definition: Requirement.h:86
Exception to be thrown when building the Driver fails.
Base class for Grids.
Definition: GridBase.h:39
const std::vector< double > GetLower() const
Return the lower edges of the Grid.
Definition: GridBase.h:231
size_t size() const
Get the size of the internal storage vector.
Definition: GridBase.h:326
const std::vector< double > GetUpper() const
Return the upper edges of the Grid.
Definition: GridBase.h:262
const std::vector< int > GetNumPoints() const
Get the number of points for all dimensions.
Definition: GridBase.h:205
Custom Iterator.
Definition: Grid.h:247
bool operator==(const self_type &rhs) const
Equality operator.
Definition: Grid.h:448
GridIterator(const std::vector< int > &indices, const Grid< T > *grid)
Const constructor.
Definition: Grid.h:287
GridIterator()=default
Use default constructor.
self_type & operator--()
Pre-decrement operator.
Definition: Grid.h:389
std::bidirectional_iterator_tag iterator_category
HistIterator is a bidirectional iterator.
Definition: Grid.h:265
const self_type operator-(std::vector< int > shift)
Subtraction iterator.
Definition: Grid.h:437
GridIterator(const GridIterator &other)
Copy constructor.
Definition: Grid.h:296
R * pointer
Either T* or T const* for iterator and const_iterator, respectively.
Definition: Grid.h:259
Grid< T > * grid_
Pointer to grid to iterate over.
Definition: Grid.h:511
bool operator!=(const self_type &rhs) const
Non-equality operator.
Definition: Grid.h:459
std::vector< int > indices_
Indices of current grid point.
Definition: Grid.h:508
const self_type operator+(std::vector< int > shift)
Addition operator.
Definition: Grid.h:377
self_type & operator-=(std::vector< int > shift)
Subtraction assignment operator.
Definition: Grid.h:418
std::vector< int > & indices()
Access indices.
Definition: Grid.h:471
double coordinate(size_t d) const
Access specific coordinate dimension.
Definition: Grid.h:501
R value_type
Either T or const T for iterator and const_iterator, respectively.
Definition: Grid.h:256
reference operator*()
Dereference operator.
Definition: Grid.h:305
std::vector< double > coordinates() const
Access coordinates.
Definition: Grid.h:491
self_type & operator+=(std::vector< int > shift)
Addition assignment operator.
Definition: Grid.h:356
GridIterator(const std::vector< int > &indices, Grid< T > *grid)
Constructor.
Definition: Grid.h:276
R & reference
Either T& or T const& for iterator and const_iterator, respectively.
Definition: Grid.h:262
GridIterator self_type
Type name of the iterator.
Definition: Grid.h:250
self_type operator--(int)
Post-decrement operator.
Definition: Grid.h:406
self_type & operator++()
Pre-increment operator.
Definition: Grid.h:315
self_type operator++(int)
Post-increment operator.
Definition: Grid.h:332
int difference_type
Difference type is an int.
Definition: Grid.h:253
int & index(size_t d)
Access a specific index.
Definition: Grid.h:482
Basic Grid.
Definition: Grid.h:59
const_iterator begin() const
Return const iterator at first grid point.
Definition: Grid.h:558
static Grid< T > * BuildGrid(const Json::Value &json)
Set up the grid.
Definition: Grid.h:127
void LoadFromFile(const std::string &filename)
Builds a grid from file.
Definition: Grid.h:629
iterator begin()
Return iterator at first grid point.
Definition: Grid.h:527
GridIterator< const T > const_iterator
Custom constant iterator over a grid.
Definition: Grid.h:518
GridIterator< T > iterator
Custom iterator over a grid.
Definition: Grid.h:515
static Grid< T > * BuildGrid(const Json::Value &json, const std::string &path)
Set up the grid.
Definition: Grid.h:142
Grid(std::vector< int > numPoints, std::vector< double > lower, std::vector< double > upper, std::vector< bool > isPeriodic)
Constructor.
Definition: Grid.h:103
void WriteToFile(const std::string &filename)
Write grid out to file.
Definition: Grid.h:586
iterator end()
Return iterator after last valid grid point.
Definition: Grid.h:540
size_t mapTo1d(const std::vector< int > &indices) const override
Map d-dimensional indices to 1-d data vector.
Definition: Grid.h:70
const_iterator end() const
Return const iterator after last valid grid point.
Definition: Grid.h:571