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