BALL  1.4.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
regularData1D.h
Go to the documentation of this file.
1 // -*- Mode: C++; tab-width: 2; -*-
2 // vi: set ts=2:
3 //
4 
5 #ifndef BALL_DATATYPE_REGULARDATA1D_H
6 #define BALL_DATATYPE_REGULARDATA1D_H
7 
8 #ifndef BALL_COMMON_H
9 # include <BALL/common.h>
10 #endif
11 
12 #ifndef BALL_SYSTEM_FILE_H
13 # include <BALL/SYSTEM/file.h>
14 #endif
15 
16 #ifndef BALL_SYSTEM_BINARYFILEADAPTOR_H
18 #endif
19 
20 #include <vector>
21 #include <iostream>
22 #include <fstream>
23 #include <iterator>
24 #include <algorithm>
25 
26 namespace BALL
27 {
39  template <typename ValueType>
41  {
42  public:
43 
45 
46 
49 
53  typedef std::vector<ValueType> VectorType;
55  typedef double CoordinateType;
57  typedef typename std::vector<ValueType>::iterator Iterator;
59  typedef typename std::vector<ValueType>::const_iterator ConstIterator;
61 
62  // STL compatibility types
63  //
64  typedef ValueType value_type;
65  typedef typename std::vector<ValueType>::iterator iterator;
66  typedef typename std::vector<ValueType>::const_iterator const_iterator;
67  typedef typename std::vector<ValueType>::reference reference;
68  typedef typename std::vector<ValueType>::const_reference const_reference;
69  typedef typename std::vector<ValueType>::pointer pointer;
70  typedef typename std::vector<ValueType>::difference_type difference_type;
71  typedef typename std::vector<ValueType>::size_type size_type;
72 
76 
79 
83  TRegularData1D(const TRegularData1D& data);
84 
88  TRegularData1D(const CoordinateType& origin, const CoordinateType& dimension, const CoordinateType& spacing);
89 
93  TRegularData1D(const IndexType& size);
94 
98  TRegularData1D(const VectorType& data, const CoordinateType& origin = 0.0, const CoordinateType& dimension = 1.0);
99 
101  virtual ~TRegularData1D();
102 
104  virtual void clear();
106 
107 
111 
116  TRegularData1D& operator = (const TRegularData1D<ValueType>& data);
117 
122  TRegularData1D& operator = (const VectorType& data);
123 
125 
129 
130  bool operator == (const TRegularData1D& data) const;
131 
133  BALL_INLINE bool operator != (const TRegularData1D& data) const { return !this->operator == (data); }
134 
136  BALL_INLINE bool empty() const { return data_.empty(); }
137 
139  bool isInside(const CoordinateType& x) const;
141 
145 
146  BALL_INLINE ConstIterator begin() const { return data_.begin(); }
148  BALL_INLINE ConstIterator end() const { return data_.end(); }
150  BALL_INLINE Iterator begin() { return data_.begin(); }
152  BALL_INLINE Iterator end() { return data_.end(); }
154 
158 
159  // STL compatibility
160  BALL_INLINE size_type size() const { return data_.size(); }
161  BALL_INLINE size_type max_size() const { return data_.max_size(); }
162  BALL_INLINE void swap(TRegularData1D<ValueType>& data) { std::swap(*this, data); }
163 
168  const ValueType& getData(const IndexType& index) const;
169 
174  ValueType& getData(const IndexType& index);
175 
180  const ValueType& operator [] (const IndexType& index) const { return data_[index]; }
181 
186  ValueType& operator [] (const IndexType& index) { return data_[index]; }
187 
196  ValueType operator () (const CoordinateType& x) const;
197 
204  ValueType getInterpolatedValue(const CoordinateType& x) const;
205 
212  void getEnclosingIndices(const CoordinateType& x, Position& lower, Position& upper) const;
213 
218  void getEnclosingValues(const CoordinateType& x, ValueType& lower, ValueType& upper) const;
219 
224  CoordinateType getCoordinates(const IndexType& index) const;
225 
232  IndexType getClosestIndex(const CoordinateType& x) const;
233 
240  IndexType getLowerIndex(const CoordinateType& x) const;
241 
248  const ValueType& getClosestValue(const CoordinateType& x) const;
249 
256  ValueType& getClosestValue(const CoordinateType& x);
257 
259  BALL_INLINE IndexType getSize() const { return (IndexType)data_.size(); }
260 
265  BALL_INLINE const CoordinateType& getOrigin() const { return origin_; }
266 
271  BALL_INLINE const CoordinateType& getSpacing() const { return spacing_; }
272 
275  BALL_INLINE void setOrigin(const CoordinateType& origin) { origin_ = origin; }
276 
283 
289  BALL_INLINE void setDimension(const CoordinateType& dimension) { dimension_ = dimension; }
290 
303  void resize(const IndexType& size);
304 
314  void rescale(const IndexType& new_size);
315 
319  ValueType calculateMean() const;
320 
324  ValueType calculateSD() const;
325 
329  void binaryWrite(const String& filename) const;
330 
334  void binaryRead(const String& filename);
336 
337 
338  protected:
341 
344 
347 
350 
352  typedef struct { ValueType bt[1024]; } BlockValueType;
353  };
354 
358 
359  template <typename ValueType>
361  : origin_(0.0),
362  dimension_(0.0),
363  spacing_(1.0),
364  data_()
365  {
366  }
367 
368  template <typename ValueType>
370  {
371  }
372 
373  template <typename ValueType>
375  : origin_(data.origin_),
376  dimension_(data.dimension_),
377  spacing_(data.spacing_),
378  data_()
379  {
380  // Try to catch allocation errors and rethrow them as OutOfMemory
381  try
382  {
383  data_ = data.data_;
384  }
385  catch (std::bad_alloc&)
386  {
387  throw Exception::OutOfMemory(__FILE__, __LINE__, data.size() * sizeof(ValueType));
388  }
389  }
390 
391  template <typename ValueType>
393  (const typename TRegularData1D<ValueType>::CoordinateType& origin,
394  const typename TRegularData1D<ValueType>::CoordinateType& dimension,
395  const typename TRegularData1D<ValueType>::CoordinateType& spacing)
396  : origin_(origin),
397  dimension_(dimension),
398  spacing_(spacing),
399  data_()
400  {
401  // Determine the size of the vector
403 
404  // Try to catch allocation errors and rethrow them as OutOfMemory
405  try
406  {
407  data_.resize(size);
408  }
409  catch (std::bad_alloc&)
410  {
411  throw Exception::OutOfMemory(__FILE__, __LINE__, size * sizeof(ValueType));
412  }
413  }
414 
415  template <typename ValueType>
417  (const typename TRegularData1D<ValueType>::VectorType& data,
418  const typename TRegularData1D<ValueType>::CoordinateType& origin,
419  const typename TRegularData1D<ValueType>::CoordinateType& dimension)
420  : origin_(origin),
421  dimension_(dimension),
422  spacing_(dimension / ((double)data.size()-1)),
423  data_()
424  {
425  // Try to catch allocation errors and rethrow them as OutOfMemory
426  try
427  {
428  data_ = data;
429  }
430  catch (std::bad_alloc&)
431  {
432  throw Exception::OutOfMemory(__FILE__, __LINE__, data.size() * sizeof(ValueType));
433  }
434  }
435 
436 
437  template <class ValueType>
439  (const typename TRegularData1D<ValueType>::IndexType& size)
440  : origin_(0.0),
441  dimension_(1.0),
442  data_()
443  {
444  // Compute the grid spacing
445  spacing_ = dimension_ / (double)(size - 1);
446 
447  try
448  {
449  data_.resize(size);
450  }
451  catch (std::bad_alloc&)
452  {
453  data_.resize(0);
454  throw Exception::OutOfMemory(__FILE__, __LINE__, size * sizeof(ValueType));
455  }
456  }
457 
458  template <typename ValueType>
460  {
461  // iterate over the data and reset all values to their default
462  // boundaries and vector size remain unchanged
463  static ValueType default_value = ValueType();
464  std::fill(data_.begin(), data_.end(), default_value);
465  }
466 
467  template <typename ValueType>
469  {
470  // copy all members...
471  origin_ = rhs.origin_;
472  dimension_ = rhs.dimension_;
473  spacing_ = rhs.spacing_;
474  try
475  {
476  data_ = rhs.data_;
477  }
478  catch (std::bad_alloc&)
479  {
480  data_.resize(0);
481  throw Exception::OutOfMemory(__FILE__, __LINE__, rhs.size() * sizeof(ValueType));
482  }
483 
484  return *this;
485  }
486 
487  template <typename ValueType>
489  {
490  // Copy the data. The boundaries remain unchanged.
491  try
492  {
493  data_ = rhs;
494  }
495  catch (std::bad_alloc&)
496  {
497  data_.resize(0);
498  throw Exception::OutOfMemory(__FILE__, __LINE__, rhs.size() * sizeof(ValueType));
499  }
500 
501  return *this;
502  }
503 
504  template <typename ValueType>
506  {
507  return (origin_ == data.origin_
508  && dimension_ == data.dimension_
509  && data_ == data.data_);
510  }
511 
512  template <class ValueType>
515  {
516  return ((r >= origin_) && (r <= (origin_ + dimension_)));
517  }
518 
519  template <typename ValueType>
521  const ValueType& TRegularData1D<ValueType>::getData(const IndexType& index) const
522  {
523  if (index >= data_.size())
524  {
525  throw Exception::OutOfGrid(__FILE__, __LINE__);
526  }
527  return data_[index];
528  }
529 
530  template <typename ValueType>
533  {
534  if (index >= data_.size())
535  {
536  throw Exception::OutOfGrid(__FILE__, __LINE__);
537  }
538  return data_[index];
539  }
540 
541  template <typename ValueType>
544  Position& lower, Position& upper) const
545  {
546  if (!isInside(x) || (data_.size() < 2))
547  {
548  throw Exception::OutOfGrid(__FILE__, __LINE__);
549  }
550  lower = (Position)floor((x - origin_) / spacing_);
551  if (lower == data_.size() - 1)
552  {
553  // If we are on the right most data point, we cannot interpolate to the right!
554  lower = data_.size() - 2;
555  }
556  upper = lower + 1;
557  }
558 
559  template <typename ValueType>
562  ValueType& lower, ValueType& upper) const
563  {
564  Position lower_index;
565  Position upper_index;
566  getEnclosingIndices(x, lower_index, upper_index);
567  lower = data_[lower_index];
568  upper = data_[upper_index];
569  }
570 
571  template <typename ValueType>
574  {
575  if (!isInside(x))
576  {
577  throw Exception::OutOfGrid(__FILE__, __LINE__);
578  }
579  return operator () (x);
580  }
581 
582  template <typename ValueType>
585  (const typename TRegularData1D<ValueType>::IndexType& index) const
586  {
587  if ((index >= data_.size()) || (data_.size() == 0))
588  {
589  throw Exception::OutOfGrid(__FILE__, __LINE__);
590  }
591 
592  return (CoordinateType)(origin_ + (double)index / ((double)data_.size()-1) * dimension_);
593  }
594 
595  template <typename ValueType>
598  {
599  if ((x < origin_) || (x > (origin_ + dimension_)))
600  {
601  throw Exception::OutOfGrid(__FILE__, __LINE__);
602  }
603 
604  return (IndexType)(size_type)floor((x - origin_) / spacing_ + 0.5);
605  }
606 
607  template <typename ValueType>
610  {
611  if ((x < origin_) || (x > (origin_ + dimension_)))
612  {
613  throw Exception::OutOfGrid(__FILE__, __LINE__);
614  }
615 
616  return (IndexType)(size_type)floor((x - origin_) / spacing_);
617  }
618 
619  template <typename ValueType>
622  {
623  if ((x < origin_) || (x > (origin_ + dimension_)))
624  {
625  throw Exception::OutOfGrid(__FILE__, __LINE__);
626  }
627 
628  // Round to the closest data point.
629  size_type index = (size_type)floor((x - origin_) / spacing_ + 0.5);
630  return data_[index];
631  }
632 
633  template <typename ValueType>
636  {
637  if ((x < origin_) || (x > (origin_ + dimension_)))
638  {
639  throw Exception::OutOfGrid(__FILE__, __LINE__);
640  }
641 
642  // Round to the closest data point.
643  size_type index = (size_type)floor((x - origin_) / spacing_ + 0.5);
644  return data_[index];
645  }
646 
647  template <typename ValueType>
650  {
651  IndexType data_points = this->getSize();
652  ValueType mean = 0;
653  for (IndexType i = 0; i < data_points; i++)
654  {
655  mean += data_[i];
656  }
657  mean /= data_points;
658  return mean;
659  }
660 
661  template <typename ValueType>
664  {
665  IndexType data_points = this->getSize();
666  ValueType stddev = 0;
667  ValueType mean = this->calculateMean();
668  for (IndexType i = 0; i < data_points; i++)
669  {
670  stddev += (pow(data_[i]-mean,2));
671  }
672  stddev /= (data_points-1);
673  stddev = sqrt(stddev);
674  return stddev;
675  }
676 
677  template <typename ValueType>
680  {
681  size_type left_index = (size_type)floor((x - origin_) / spacing_);
682  if (left_index == data_.size() - 1)
683  {
684  // If we are on the right most data point, we cannot interpolate to the right!
685  return data_[data_.size() - 1];
686  }
687 
688  // Interpolate between the point to the left and the point to the right.
689  double d = 1.0 - (((x - origin_) - (double)left_index * spacing_) / spacing_);
690  return data_[left_index] * d + (1.0 - d) * data_[left_index + 1];
691  }
692 
693  template <typename ValueType>
695  (const typename TRegularData1D<ValueType>::IndexType& new_size)
696  {
697  // Rescale dimension to the new size.
698  if (data_.size() > 0)
699  {
700  dimension_ *= (double)new_size / (double)data_.size();
701  }
702 
703  // Try to resize the vactor and rethrow any bad_allocs.
704  try
705  {
706  data_.resize(new_size);
707  }
708  catch (std::bad_alloc&)
709  {
710  // The resulting vector is empty and thus well-defined.
711  data_.resize(0);
712  throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * sizeof(ValueType));
713  }
714  }
715 
716  template <typename ValueType>
718  (const typename TRegularData1D<ValueType>::IndexType& new_size)
719  {
720  // if the new and the old size coincide: done.
721  if (new_size == (IndexType)data_.size())
722  {
723  return;
724  }
725 
726  // Catch any bad_allocs throw by vector::resize
727  try
728  {
729  // if the data set is empty...
730  if (data_.size() == 0)
731  {
732  // ...there's nothing to do: a resize was requested
733  data_.resize(new_size);
734  return;
735  }
736 
737  // if the data set contains only a single value,
738  // we fill everything with this value
739  if ((data_.size() == 1) && (new_size > 1))
740  {
741  ValueType old_value = data_[0];
742  data_.resize(new_size);
743  for (IndexType i = 1; i < new_size; i++)
744  {
745  data_[i] = old_value;
746  }
747 
748  return;
749  }
750 
751  // that's the default case: use linear interpolation
752  // to determine the values at the new positions
753  VectorType new_data(new_size);
754  CoordinateType factor1 = (CoordinateType)data_.size() / (CoordinateType)new_size;
755  CoordinateType factor2 = (CoordinateType)(data_.size() - 1) / (new_size - 1);
756 
757  for (Size i = 0; i < new_size; i++)
758  {
759  // determine the interval of the old data set we are currently in
760  // ([old_idx, old_idx + 1])
761  IndexType old_idx = (IndexType)((CoordinateType)i * factor1);
762 
763  // consider numerical inaccuracies...
764  if (old_idx >= (data_.size() - 1))
765  {
766  old_idx = data_.size() - 2;
767  }
768  CoordinateType factor3 = (CoordinateType)i * factor2 - (CoordinateType)old_idx;
769  new_data[i] = data_[old_idx] * (1 - factor3) + factor3 * data_[old_idx + 1];
770  }
771 
772  // assign the new data
773  data_ = new_data;
774  }
775  catch (std::bad_alloc&)
776  {
777  // Make sure we are in a well-defined state.
778  data_.resize(0);
779  throw Exception::OutOfMemory(__FILE__, __LINE__, new_size * sizeof(ValueType));
780  }
781  }
782 
785 
786  template <typename ValueType>
787  std::ostream& operator << (std::ostream& os, const TRegularData1D<ValueType>& data)
788  {
789  // Write the grid origin, dimension, and number of grid points
790  os << data.getOrigin() << std::endl
791  << data.getOrigin() + data.getDimension() << std::endl
792  << data.getSize() - 1 << std::endl;
793 
794  // Write the array contents.
795  std::copy(data.begin(), data.end(), std::ostream_iterator<ValueType>(os, "\n"));
796  return os;
797  }
798 
800  template <typename ValueType>
801  std::istream& operator >> (std::istream& is, TRegularData1D<ValueType>& grid)
802  {
806 
807  is >> origin;
808  is >> dimension;
809  is >> size;
810 
811  dimension -= origin;
812  size++;
813 
814  grid.resize(size);
815  grid.setOrigin(origin);
816  grid.setDimension(dimension);
817 
818  std::copy(std::istream_iterator<ValueType>(is),
819  std::istream_iterator<ValueType>(),
820  grid.begin());
821  // std::copy_n(std::istream_iterator<ValueType>(is), grid.size(), grid.begin());
822 
823  return is;
824  }
825 
826  template <typename ValueType>
827  void TRegularData1D<ValueType>::binaryWrite(const String& filename) const
828  {
829  File outfile(filename, std::ios::out|std::ios::binary);
830  if (!outfile.isValid())
831  {
832  throw Exception::FileNotFound(__FILE__, __LINE__, filename);
833  }
834 
836  BinaryFileAdaptor<ValueType> adapt_single;
837 
838  // write all information we need to recreate the grid
839  BinaryFileAdaptor<CoordinateType> adapt_coordinate;
840  BinaryFileAdaptor<Size> adapt_size;
841 
842  adapt_size.setData(data_.size());
843  outfile << adapt_size;
844 
845  adapt_coordinate.setData(origin_);
846  outfile << adapt_coordinate;
847 
848  adapt_coordinate.setData(dimension_);
849  outfile << adapt_coordinate;
850 
851  adapt_coordinate.setData(spacing_);
852  outfile << adapt_coordinate;
853 
854  // we slide a window of size 1024 over our data
855  Index window_pos = 0;
856  while (((int)data_.size() - (1024 + window_pos)) >= 0 )
857  {
858  adapt_block.setData(*(BlockValueType*)&(data_[window_pos]));
859  outfile << adapt_block;
860  window_pos += 1024;
861  }
862 
863  // now we have to write the remaining data one by one
864  for (Size i = window_pos; i < data_.size(); i++)
865  {
866  adapt_single.setData(data_[i]);
867  outfile << adapt_single;
868  }
869 
870  // that's it. I hope...
871  outfile.close();
872  }
873 
874  template <typename ValueType>
876  {
877  File infile(filename, std::ios::in|std::ios::binary);
878  if (!infile.isValid()) throw Exception::FileNotFound(__FILE__, __LINE__, filename);
879 
881  BinaryFileAdaptor<ValueType> adapt_single;
882 
883  // read all information we need to recreate the grid
884  BinaryFileAdaptor<CoordinateType> adapt_coordinate;
885  BinaryFileAdaptor<Size> adapt_size;
886 
887  infile >> adapt_size;
888  Size new_size = adapt_size.getData();
889 
890  infile >> adapt_coordinate;
891  origin_ = adapt_coordinate.getData();
892 
893  infile >> adapt_coordinate;
894  dimension_ = adapt_coordinate.getData();
895 
896  infile >> adapt_coordinate;
897  spacing_ = adapt_coordinate.getData();
898 
899  data_.resize(new_size);
900 
901  // we slide a window of size 1024 over our data
902  Index window_pos = 0;
903 
904  while ( ((int)data_.size() - (1024 + window_pos)) >= 0 )
905  {
906  infile >> adapt_block;
907  *(BlockValueType*)(&(data_[window_pos])) = adapt_block.getData();
908  /*
909  for (Size i=0; i<1024; i++)
910  {
911  data_[i+window_pos] = adapt_block.getData().bt[i];
912  }
913  */
914  window_pos+=1024;
915  }
916 
917  // now we have to read the remaining data one by one
918  for (Size i=window_pos; i<data_.size(); i++)
919  {
920  infile >> adapt_single;
921  data_[i] = adapt_single.getData();
922  }
923 
924  // that's it. I hope...
925  infile.close();
926  }
927 } // namespace BALL
928 
929 #endif // BALL_DATATYPE_REGULARDATA1D_H