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