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