svFSIplus
Vector.h
1 /* Copyright (c) Stanford University, The Regents of the University of California, and others.
2  *
3  * All Rights Reserved.
4  *
5  * See Copyright-SimVascular.txt for additional details.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining
8  * a copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sublicense, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject
13  * to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef VECTOR_H
32 #define VECTOR_H
33 
34 #include <algorithm>
35 #include <float.h>
36 #include <iostream>
37 #include <string>
38 #include <vector>
39 
40 std::string build_file_prefix(const std::string& label);
41 
42 #ifdef ENABLE_ARRAY_INDEX_CHECKING
43 #define Vector_check_enabled
44 #endif
45 
46 /// @brief The Vector template class is used for storing int and double data.
47 //
48 template<typename T>
49 class Vector
50 {
51  public:
52 
53  static int num_allocated;
54  static int active;
55  static double memory_in_use;
56  static double memory_returned;
57  static bool write_enabled;
58  static bool show_index_check_message;
59  static void memory(const std::string& prefix="");
60  static void stats(const std::string& prefix="");
61 
62  Vector()
63  {
64  check_type();
65  size_ = 0;
66  data_ = nullptr;
67  num_allocated += 1;
68  active += 1;
69  };
70 
71  Vector(const int size)
72  {
73  // [NOTE] This is tfu but need to mimic Fortran that can allocate 0-sized arrays.
74  if (size <= 0) {
75  is_allocated_ = true;
76  return;
77  }
78  check_type();
79  allocate(size);
80  num_allocated += 1;
81  active += 1;
82  }
83 
84  Vector(const int size, T* data)
85  {
86  reference_data_ = true;
87  size_ = size;
88  data_ = data;
89  }
90 
91  Vector(std::initializer_list<T> values)
92  {
93  if (values.size() == 0) {
94  return;
95  }
96  check_type();
97  allocate(values.size());
98  std::copy(values.begin(), values.end(), data_);
99  num_allocated += 1;
100  active += 1;
101  }
102 
103  ~Vector()
104  {
105  if (data_ != nullptr) {
106  if (!reference_data_) {
107  delete[] data_;
108  }
109  memory_in_use -= sizeof(T)*size_;
110  memory_returned += sizeof(T)*size_;
111  active -= 1;
112  }
113 
114  size_ = 0;
115  data_ = nullptr;
116  }
117 
118  // Vector copy.
119  Vector(const Vector& rhs)
120  {
121  if (rhs.size_ <= 0) {
122  return;
123  }
124  allocate(rhs.size_);
125  for (int i = 0; i < rhs.size_; i++) {
126  data_[i] = rhs.data_[i];
127  }
128  num_allocated += 1;
129  active += 1;
130  }
131 
132  bool allocated() const
133  {
134  return is_allocated_ ;
135  }
136 
137  /// @brief Free the array data.
138  ///
139  /// This is to replicate the Fortran DEALLOCATE().
140  //
141  void clear()
142  {
143  if (data_ != nullptr) {
144  if (reference_data_) {
145  throw std::runtime_error("[Vector] Can't clear a Vector with reference data.");
146  }
147  delete [] data_;
148  memory_in_use -= sizeof(T) * size_;;
149  memory_returned += sizeof(T) * size_;;
150  }
151 
152  is_allocated_ = false;
153  size_ = 0;
154  data_ = nullptr;
155  }
156 
157  void print(const std::string& label)
158  {
159  printf("%s (%d): \n", label.c_str(), size_);
160  for (int i = 0; i < size_; i++) {
161  printf("%s %d %g\n", label.c_str(), i+1, data_[i]);
162  }
163  }
164 
165  /// @brief Resize the vector's memory.
166  //
167  void resize(const int size)
168  {
169  if (size <= 0) {
170  //throw std::runtime_error(+"Allocating a zero size Vector.");
171  return;
172  }
173  if (data_ != nullptr) {
174  if (reference_data_) {
175  throw std::runtime_error("[Vector] Can't resize a Vector with reference data.");
176  }
177  delete[] data_;
178  memory_in_use -= sizeof(T) * size_;;
179  memory_returned += sizeof(T) * size_;;
180  size_ = 0;
181  data_ = nullptr;
182  }
183  allocate(size);
184  }
185 
186  /// @brief Grow the vector.
187  //
188  void grow(const int size, T value={})
189  {
190  if (size <= 0) {
191  return;
192  }
193 
194  memory_in_use += sizeof(T) * size;;
195  int new_size = size_ + size;
196  T* new_data = new T [new_size];
197  for (int i = 0; i < size; i++) {
198  new_data[i+size_] = value;
199  }
200  memcpy(new_data, data_, sizeof(T)*size_);
201  if (reference_data_) {
202  throw std::runtime_error("[Vector] Can't grow a Vector with reference data.");
203  }
204  delete[] data_;
205  size_ = new_size;
206  data_ = new_data;
207  }
208 
209  void set_values(std::initializer_list<T> values)
210  {
211  if (values.size() == 0) {
212  return;
213  }
214  check_type();
215  allocate(values.size());
216  std::copy(values.begin(), values.end(), data_);
217  }
218 
219  void set_values(std::vector<T> values)
220  {
221  if (values.size() == 0) {
222  return;
223  }
224  check_type();
225  allocate(values.size());
226  std::copy(values.begin(), values.end(), data_);
227  }
228 
229  void read(const std::string& file_name)
230  {
231  auto fp = fopen(file_name.c_str(), "rb");
232  int size;
233  fread(&size, sizeof(int), 1, fp);
234  fread(data_, sizeof(T), size_, fp);
235  fclose(fp);
236  }
237 
238  void write(const std::string& label, const T offset={}) const
239  {
240  if (!write_enabled) {
241  return;
242  }
243 
244  auto file_prefix = build_file_prefix(label);
245  auto file_name = file_prefix + "_cm.bin";
246 
247  // Write binary file.
248  //
249  auto fp = fopen(file_name.c_str(), "wb");
250  fwrite(&size_, sizeof(int), 1, fp);
251  fwrite(data_, sizeof(T), size_, fp);
252  fclose(fp);
253  }
254 
255  /////////////////////////
256  // O p e r a t o r s //
257  /////////////////////////
258 
259  /// @brief Vector assigment.
260  ///
261  /// Note: There are two ways to do this:
262  ///
263  /// 1) Swap pointers to data_
264  ///
265  /// 2) Copy data_
266  ///
267  /// Fortran using 2) I think.
268  //
269  Vector& operator=(const Vector& rhs)
270  {
271  if (rhs.size_ <= 0) {
272  return *this;
273  }
274 
275  if (this == &rhs) {
276  return *this;
277  }
278 
279  if (size_ != rhs.size_) {
280  clear();
281  allocate(rhs.size_);
282  }
283 
284  memcpy(data_, rhs.data_, sizeof(T) * size_);
285 
286  return *this;
287  }
288 
289  Vector& operator=(const double value)
290  {
291  for (int i = 0; i < size_; i++) {
292  data_[i] = value;
293  }
294  return *this;
295  }
296 
297  int size() const {
298  return size_;
299  }
300 
301  int msize() const
302  {
303  return size_ * sizeof(T);
304  }
305 
306  // Index operators.
307  //
308  const T& operator()(const int i) const
309  {
310  #ifdef Vector_check_enabled
311  check_index(i);
312  #endif
313  return data_[i];
314  }
315 
316  T& operator()(const int i)
317  {
318  #ifdef Vector_check_enabled
319  check_index(i);
320  #endif
321  return data_[i];
322  }
323 
324  const T& operator[](const int i) const
325  {
326  #ifdef Vector_check_enabled
327  check_index(i);
328  #endif
329  return data_[i];
330  }
331 
332  T& operator[](const int i)
333  {
334  #ifdef Vector_check_enabled
335  check_index(i);
336  #endif
337  return data_[i];
338  }
339 
340  friend std::ostream& operator << (std::ostream& out, const Vector<T>& lhs)
341  {
342  for (int i = 0; i < lhs.size(); i++) {
343  out << lhs[i];
344  if (i != lhs.size()-1) {
345  out << ", ";
346  }
347  }
348  return out;
349  }
350 
351  ///////////////////////////////////////////////////
352  // M a t h e m a t i c a l o p e r a t o r s //
353  ///////////////////////////////////////////////////
354 
355  /// @brief Add and subtract vectors.
356  //
357  Vector<T> operator+(const Vector<T>& vec) const
358  {
359  if (size_ != vec.size()) {
360  throw std::runtime_error("[Vector dot product] Vectors have diffrenct sizes: " +
361  std::to_string(size_) + " != " + std::to_string(vec.size()) + ".");
362  }
363  Vector<T> result(size_);
364  for (int i = 0; i < size_; i++) {
365  result(i) = data_[i] + vec[i];
366  }
367  return result;
368  }
369 
370  Vector<T> operator-(const Vector<T>& x) const
371  {
372  Vector<T> result(size_);
373  for (int i = 0; i < size_; i++) {
374  result(i) = data_[i] - x(i);
375  }
376  return result;
377  }
378 
379  /// @brief Add and subtract a scalar from a vector.
380  //
381  Vector<T> operator+(const T value) const
382  {
383  Vector<T> result(size_);
384  for (int i = 0; i < size_; i++) {
385  result(i) = data_[i] + value;
386  }
387  return result;
388  }
389 
390  friend const Vector<T> operator+(const T value, const Vector& rhs)
391  {
392  Vector<T> result(rhs.size_);
393  for (int i = 0; i < rhs.size_; i++) {
394  result(i) = rhs.data_[i] + value;
395  }
396  return result;
397  }
398 
399  Vector<T> operator-(const T value) const
400  {
401  Vector<T> result(size_);
402  for (int i = 0; i < size_; i++) {
403  result(i) = data_[i] - value;
404  }
405  return result;
406  }
407 
408  friend Vector<T> operator-(T value, const Vector& rhs)
409  {
410  Vector<T> result(rhs.size_);
411  for (int i = 0; i < rhs.size_; i++) {
412  result(i) = value - rhs.data_[i];
413  }
414  return result;
415  }
416 
417  /// @brief Divide by a scalar.
418  //
419  Vector<T> operator/(const T value) const
420  {
421  Vector<T> result(size_);
422  for (int i = 0; i < size_; i++) {
423  result(i) = data_[i] / value;
424  }
425  return result;
426  }
427 
428  friend const Vector<T> operator/(const T value, const Vector& rhs)
429  {
430  Vector<T> result(rhs.size_);
431  for (int i = 0; i < rhs.size_; i++) {
432  result(i) = rhs.data_[i] / value;
433  }
434  return result;
435  }
436 
437  /// @brief Multiply by a scalar.
438  //
439  Vector<T> operator*(const T value) const
440  {
441  Vector<T> result(size_);
442  for (int i = 0; i < size_; i++) {
443  result(i) = value * data_[i];
444  }
445  return result;
446  }
447 
448  friend const Vector<T> operator*(const T value, const Vector& rhs)
449  {
450  Vector<T> result(rhs.size_);
451  for (int i = 0; i < rhs.size_; i++) {
452  result(i) = value * rhs.data_[i];
453  }
454  return result;
455  }
456 
457 
458  /// @brief Negate.
460  {
461  Vector<T> result(size_);
462  for (int i = 0; i < size_; i++) {
463  result(i) = -data_[i];
464  }
465  return result;
466  }
467 
468  /// @brief Absolute value.
469  Vector<T> abs() const
470  {
471  Vector<T> result(size_);
472  for (int i = 0; i < size_; i++) {
473  result(i) = std::abs(data_[i]);
474  }
475  return result;
476  }
477 
478  /// @brief Cross product
480  {
481  Vector<T> result(size_);
482 
483  result(0) = (*this)(1)*v2(2) - (*this)(2)*v2(1);
484  result(1) = (*this)(2)*v2(0) - (*this)(0)*v2(2);
485  result(2) = (*this)(0)*v2(1) - (*this)(1)*v2(0);
486 
487  return result;
488  }
489 
490  /// @brief Dot product.
491  T dot(const Vector<T>& v2)
492  {
493  if (size_ != v2.size()) {
494  throw std::runtime_error("[Vector dot product] Vectors have diffrenct sizes: " +
495  std::to_string(size_) + " != " + std::to_string(v2.size()) + ".");
496  }
497  T sum = 0.0;
498  for (int i = 0; i < size_; i++) {
499  sum += (*this)(i) * v2(i);
500  }
501  return sum;
502  }
503 
504  friend T operator*(const Vector& v1, const Vector& v2)
505  {
506  if (v1.size() != v2.size()) {
507  throw std::runtime_error("[Vector dot product] Vectors have diffrenct sizes: " +
508  std::to_string(v1.size()) + " != " + std::to_string(v2.size()) + ".");
509  }
510  T sum = 0.0;
511  for (int i = 0; i < v1.size(); i++) {
512  sum += v1[i] * v2[i];
513  }
514  return sum;
515  }
516 
517  T min() const
518  {
519  /*
520  if (size_ == 0) {
521  return std::numeric_limits<T>::max();
522  }
523  */
524  return *std::min_element((*this).begin(), (*this).end());
525  }
526 
527  T max() const
528  {
529  /*
530  if (size_ == 0) {
531  return -std::numeric_limits<T>::max();
532  }
533  */
534  return *std::max_element((*this).begin(), (*this).end());
535  }
536 
537  T sum() const
538  {
539  T sum = {};
540  for (int i = 0; i < size_; i++) {
541  sum += data_[i];
542  }
543  return sum;
544  }
545 
546  /////////////////////////////////////
547  // i t e r a t o r c l a s s s //
548  /////////////////////////////////////
549 
550  /// @brief This class provides an interface to access Vector like STL containers.
551  //
552  class Iterator
553  {
554  public:
555  typedef T value_type;
556  typedef T& reference;
557  typedef T* pointer;
558  typedef int difference_type;
559  typedef std::forward_iterator_tag iterator_category;
560 
561  Iterator(T* ptr) : ptr_{ptr} {}
562 
563  Iterator& operator++() { this->ptr_ ++; return *this; }
564  Iterator& operator--() { this->ptr_ --; return *this; }
565  Iterator& operator++(int) { this->ptr_ ++; return *this; }
566  Iterator& operator--(int) { this->ptr_ --; return *this; }
567  T& operator*() { return *this->ptr_; };
568  bool operator==(const Iterator& iter) { return this->ptr_ == iter.ptr_; }
569  bool operator!=(const Iterator& iter) { return this->ptr_ != iter.ptr_; }
570  private:
571  T* ptr_;
572  };
573 
574  Iterator begin() const
575  {
576  return Iterator(data_);
577  }
578 
579  Iterator end() const
580  {
581  return Iterator(data_+size_);
582  }
583 
584  T* data() const
585  {
586  return data_;
587  }
588 
589  void allocate(const int size)
590  {
591  if (size <= 0) {
592  //throw std::runtime_error(+"Allocating a zero size Vector.");
593  return;
594  }
595 
596  size_ = size;
597  data_ = new T [size_];
598  memset(data_, 0, sizeof(T)*(size_));
599  memory_in_use += sizeof(T)*size_;
600  }
601 
602  void check_index(const int i) const
603  {
604  if (show_index_check_message) {
605  std::cout << "[Vector] **********************************" << std::endl;
606  std::cout << "[Vector] WARNING: Index checking is enabled " << std::endl;
607  std::cout << "[Vector] **********************************" << std::endl;
608  show_index_check_message = false;
609  }
610 
611  if (data_ == nullptr) {
612  std::cout << "[Vector] WARNING: Accessing null data in Vector at " << i << std::endl;
613  return;
614  //throw std::runtime_error(+"Accessing null data in Vector.");
615  }
616 
617  if ((i < 0) || (i >= size_)) {
618  auto index_str = std::to_string(i);
619  auto dims = std::to_string(size_);
620  throw std::runtime_error( + "Index i=" + index_str + " is out of bounds for " + dims + " vector.");
621  }
622  }
623 
624  /// @brief Check that the Vector template type is int or double.
625  //
626  void check_type() const
627  {
628  if (!std::is_same<T, double>::value && !std::is_same<T, int>::value &&
629  !std::is_same<T, Vector<double>>::value && !std::is_same<T, float>::value) {
630  std::string msg = std::string("Cannot use Vector class template for type '") + typeid(T).name() + "'.";
631  throw std::runtime_error(msg);
632  }
633  }
634 
635  private:
636  bool is_allocated_ = false;
637  int size_ = 0;
638  bool reference_data_ = false;
639  T *data_ = nullptr;
640 };
641 
642 #endif
643 
This class provides an interface to access Vector like STL containers.
Definition: Vector.h:553
The Vector template class is used for storing int and double data.
Definition: Vector.h:50
void clear()
Free the array data.
Definition: Vector.h:141
Vector< T > operator-() const
Negate.
Definition: Vector.h:459
void check_type() const
Check that the Vector template type is int or double.
Definition: Vector.h:626
Vector< T > cross(const Vector< T > &v2)
Cross product.
Definition: Vector.h:479
T dot(const Vector< T > &v2)
Dot product.
Definition: Vector.h:491
Vector< T > operator+(const T value) const
Add and subtract a scalar from a vector.
Definition: Vector.h:381
Vector< T > operator+(const Vector< T > &vec) const
Add and subtract vectors.
Definition: Vector.h:357
Vector< T > abs() const
Absolute value.
Definition: Vector.h:469
Vector & operator=(const Vector &rhs)
Vector assigment.
Definition: Vector.h:269
void grow(const int size, T value={})
Grow the vector.
Definition: Vector.h:188
void resize(const int size)
Resize the vector's memory.
Definition: Vector.h:167
Vector< T > operator/(const T value) const
Divide by a scalar.
Definition: Vector.h:419
Vector< T > operator*(const T value) const
Multiply by a scalar.
Definition: Vector.h:439