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