svMultiPhysics
Loading...
Searching...
No Matches
Array3.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#include "Array.h"
5
6#ifndef ARRAY3_H
7#define ARRAY3_H
8
9#include <float.h>
10#include <iostream>
11#include <string>
12#include <cstring>
13
14#ifdef ENABLE_ARRAY_INDEX_CHECKING
15#define Array3_check_enabled
16#endif
17
18template<typename T>
19
20/*! @brief The Array3 template class implements a simple interface to 3D arrays.
21*
22* A 3D array is defined by (num_rows * num_cols) * num_slices values.
23*/
24class Array3
25{
26 public:
27
28 static int num_allocated;
29 static int active;
30 static double memory_in_use;
31 static double memory_returned;
32 static bool write_enabled;
33 static void memory(const std::string& prefix="");
34 static void stats(const std::string& prefix="");
35
36 Array3()
37 {
38 nrows_ = 0;
39 ncols_ = 0;
40 nslices_ = 0;
41 slice_size_ = 0;
42 size_ = 0;
43 data_ = nullptr;
44 num_allocated += 1;
45 active += 1;
46 };
47
48 Array3(const int num_rows, const int num_cols, const int num_slices, bool row_major=true)
49 {
50 // [NOTE] This is tfu but need to mimic fortran.
51 nrows_ = num_rows;
52 ncols_ = num_cols;
53 nslices_ = num_slices;
54
55 if ((num_rows <= 0) || (num_cols <= 0) || (num_slices <= 0)) {
56 return;
57 //throw std::runtime_error(+"Allocating zero size Array3.");
58 }
59
60 allocate(num_rows, num_cols, num_slices, row_major);
61 num_allocated += 1;
62 active += 1;
63 }
64
65 /// @brief Array copy
66 Array3(const Array3 &rhs)
67 {
68 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0) || (rhs.nslices_ <= 0)) {
69 return;
70 }
71
72 allocate(rhs.nrows_, rhs.ncols_, rhs.nslices_);
73 memcpy(data_, rhs.data_, size_*sizeof(T));
74 num_allocated += 1;
75 active += 1;
76 }
77
78 ~Array3()
79 {
80 if (data_ != nullptr) {
81 memory_in_use -= sizeof(T) * size_;;
82 memory_returned += sizeof(T) * size_;;
83 active -= 1;
84 delete [] data_;
85 data_ = nullptr;
86 }
87 }
88
89 int ncols() const { return ncols_; }
90 int nrows() const { return nrows_; }
91 int nslices() const { return nslices_; }
92
93 void allocate(const int num_rows, const int num_cols, const int num_slices, const bool row_major=true)
94 {
95 nrows_ = num_rows;
96 ncols_ = num_cols;
97 nslices_ = num_slices;
98 slice_size_ = ncols_ * nrows_;
99 size_ = nrows_ * ncols_ * nslices_;
100 data_ = new T [size_];
101 memset(data_, 0, sizeof(T)*size_);
102 memory_in_use += sizeof(T) * size_;;
103 }
104
105 void check_index(const int i, const int j, const int k) const
106 {
107 if (data_ == nullptr) {
108 throw std::runtime_error(+"Accessing null data in Array3.");
109 }
110
111 if ((i < 0) || (i >= nrows_) or (j < 0) || (j >= ncols_) or (k < 0) || (k >= nslices_)) {
112 auto i_str = std::to_string(nrows_);
113 auto j_str = std::to_string(ncols_);
114 auto k_str = std::to_string(nslices_);
115 auto dims = i_str + " x " + j_str + " x " + k_str;
116 auto index_str = " " + std::to_string(i) + "," + std::to_string(j) + "," + std::to_string(k) + " ";
117 throw std::runtime_error("Index (i,j,k)=" + index_str + " is out of bounds for " + dims + " array.");
118 }
119 }
120
121 friend std::ostream& operator << (std::ostream& out, const Array3<T>& lhs)
122 {
123 if (lhs.data_ == nullptr) {
124 throw std::runtime_error("[Array3] Accessing null data in ostream.");
125 }
126
127 for (int i = 0; i < lhs.size(); i++) {
128 out << lhs.data_[i];
129 if (i != lhs.size()-1) {
130 out << ", ";
131 }
132 }
133 return out;
134 }
135
136 /// @brief Free the array data
137 ///
138 /// This is to replicate the Fortran DEALLOCATE().
139 void clear()
140 {
141 if (data_ != nullptr) {
142 delete [] data_;
143 memory_in_use -= sizeof(T) * size_;;
144 memory_returned += sizeof(T) * size_;;
145 }
146
147 nrows_ = 0;
148 ncols_ = 0;
149 nslices_ = 0;
150 slice_size_ = 0;
151 size_ = 0;
152 data_ = nullptr;
153 }
154
155 /// @brief rslice
156 ///
157 /// Return an Array with data pointing into the Array3 internal data.
158 Array<T> rslice(const int slice) const
159 {
160 #ifdef Array3_check_enabled
161 check_index(0, 0, slice);
162 #endif
163
164 Array<T> array_slice(nrows_, ncols_, &data_[slice*slice_size_]);
165
166 return array_slice;
167 }
168
169 T* slice_data(const int slice) {
170 return &data_[slice*slice_size_];
171 }
172
173 void print(const std::string& label)
174 {
175 printf("%s (%d): \n", label.c_str(), size_);
176 for (int i = 0; i < size_; i++) {
177 if (data_[i] != 0.0) {
178 printf("%s %d %g\n", label.c_str(), i+1, data_[i]);
179 }
180 }
181 }
182
183 /// @brief Get a slice.
184 Array<T> slice(const int slice) const
185 {
186 #ifdef Array3_check_enabled
187 check_index(0, 0, slice);
188 #endif
189 Array<T> array_slice(nrows_, ncols_);
190
191 for (int col = 0; col < ncols_; col++) {
192 for (int row = 0; row < nrows_; row++) {
193 array_slice(row, col) = data_[row + col*nrows_ + slice*slice_size_];
194 }
195 }
196
197 return array_slice;
198 }
199
200 void set_row(const int col, const int slice, const std::vector<T>& values) const
201 {
202 #ifdef Array3_check_enabled
203 check_index(0, col, slice);
204 #endif
205 for (int row = 0; row < values.size(); row++) {
206 data_[row + col*nrows_ + slice*slice_size_] = values[row];
207 }
208 }
209
210 void set_slice(const int slice, const Array<T>& values) const
211 {
212 #ifdef Array3_check_enabled
213 check_index(0, 0, slice);
214 #endif
215 for (int col = 0; col < ncols_; col++) {
216 for (int row = 0; row < nrows_; row++) {
217 data_[row + col*nrows_ + slice*slice_size_] = values(row,col);
218 }
219 }
220 }
221
222 int size() const
223 {
224 return size_;
225 }
226
227 /// @brief Test if an array has rows or columns or slices set but no data.
228 ///
229 /// [NOTE] This is tfu but need to mimic fortran.
231 {
232 if ((nrows_ > 0) || (ncols_ > 0) || nslices_ > 0) {
233 return true;
234 }
235
236 return false;
237 }
238
239 int msize() const
240 {
241 return size_ * sizeof(T);
242 }
243
244 /// @brief Resize the array.
245 void resize(const int num_rows, const int num_cols, const int num_slices)
246 {
247 // [NOTE] This is tfu but need to mimic fortran.
248 nrows_ = num_rows;
249 ncols_ = num_cols;
250 nslices_ = num_slices;
251
252 if ((num_rows <= 0) || (num_cols <= 0) || (num_slices <= 0)) {
253 return;
254 }
255
256 if (data_ != nullptr) {
257 delete [] data_;
258 memory_in_use -= sizeof(T) * size_;;
259 memory_returned += sizeof(T) * size_;;
260 data_ = nullptr;
261 }
262
263 allocate(num_rows, num_cols, num_slices);
264 }
265
266 /// @brief Set the array values from an Array with the equivalent number of values.
267 ///
268 /// This sort of replicates the Fortan reshape function.
269 void set_values(Array<T>& rhs)
270 {
271 int rhs_size = rhs.size();
272
273 if (size_ != rhs_size) {
274 throw std::runtime_error("The RHS size " + std::to_string(rhs_size) + " does not have the same size " +
275 std::to_string(size_) + " of this array.");
276 }
277
278 auto rhs_data = rhs.data();
279
280 for (int i = 0; i < size_; i++) {
281 data_[i] = rhs_data[i];
282 }
283 }
284
285 void read(const std::string& file_name)
286 {
287 auto fp = fopen(file_name.c_str(), "rb");
288 fread(&size_, sizeof(int), 1, fp);
289 fread(data_, sizeof(double), size_, fp);
290 fclose(fp);
291 }
292
293 void write(const std::string& label, bool memory=true)
294 {
295 if (!write_enabled) {
296 return;
297 }
298
299 auto file_prefix = build_file_prefix(label);
300 auto file_name = file_prefix + "_cm.bin";
301
302 // Write binary file.
303 auto fp = fopen(file_name.c_str(), "wb");
304 fwrite(&size_, sizeof(int), 1, fp);
305 fwrite(data_, sizeof(double), size_, fp);
306 fclose(fp);
307 }
308
309 void append(const std::string& label, bool memory=true)
310 {
311 if (!write_enabled) {
312 return;
313 }
314
315 auto file_prefix = build_file_prefix(label);
316 auto file_name = file_prefix + "_cm.bin";
317
318 // Append to binary file.
319 auto fp = fopen(file_name.c_str(), "ab");
320 fwrite(data_, sizeof(double), size_, fp);
321 fclose(fp);
322 }
323
324 /////////////////////////
325 // O p e r a t o r s //
326 /////////////////////////
327
328 /// @brief Array assignment
329 ///
330 /// Copy data to replicate Fortran behavior.
332 {
333 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0) || (rhs.nslices_ <= 0)) {
334 return *this;
335 }
336
337 if (rhs.data_ == nullptr) {
338 throw std::runtime_error(+"RHS has null data.");
339 }
340
341 if (this == &rhs) {
342 return *this;
343 }
344
345 if (size_ != rhs.size_) {
346 delete [] data_;
347 allocate(rhs.nrows_, rhs.ncols_, rhs.nslices_);
348 }
349
350 memcpy(data_, rhs.data_, sizeof(T) * size_);
351
352 return *this;
353 }
354
355 /// @brief Get the array value at (row,col).
356 const T& operator()(const int row, const int col, const int slice) const
357 {
358 #ifdef Array3_check_enabled
359 check_index(row, col, slice);
360 #endif
361 return data_[row + col*nrows_ + slice*slice_size_];
362 }
363
364 /// @brief Set the array value at (row,col).
365 T& operator()(const int row, const int col, const int slice)
366 {
367 #ifdef Array3_check_enabled
368 check_index(row, col, slice);
369 #endif
370 return data_[row + col*nrows_ + slice*slice_size_];
371 }
372
373 Array3& operator=(const double value)
374 {
375 for (int i = 0; i < size_; i++) {
376 data_[i] = value;
377 }
378 return *this;
379 }
380
381 ///////////////////////////////////////////////////
382 // M a t h e m a t i c a l o p e r a t o r s //
383 ///////////////////////////////////////////////////
384
385 /// @brief Multiply by a scalar.
386 Array3<T> operator * (const T value) const
387 {
388 Array3<T> result(nrows_, ncols_, nslices_);
389 for (int i = 0; i < size_; i++) {
390 result.data_[i] = value * data_[i];
391 }
392 return result;
393 }
394
395 Array3<T>& operator *= (const T value)
396 {
397 for (int i = 0; i < size_; i++) {
398 data_[i] *= value;
399 }
400 return *this;
401 }
402
403 friend const Array3<T> operator * (const T value, const Array3& rhs)
404 {
405 if (rhs.data_ == nullptr) {
406 throw std::runtime_error("Null data for rhs Array3.");
407 }
408 Array3<T> result(rhs.nrows_, rhs.ncols_, rhs.nslices_);
409 for (int i = 0; i < rhs.size_; i++) {
410 result.data_[i] = value * rhs.data_[i];
411 }
412 return result;
413 }
414
415 T* data() const {
416 return data_;
417 }
418
419 private:
420 int nrows_ = 0;
421 int ncols_ = 0;
422 int nslices_ = 0;
423 int slice_size_ = 0;
424 int size_ = 0;
425 T *data_ = nullptr;
426
427};
428
429#endif
430
The Array3 template class implements a simple interface to 3D arrays.
Definition Array3.h:25
Array3 & operator=(const Array3 &rhs)
Array assignment.
Definition Array3.h:331
void clear()
Free the array data.
Definition Array3.h:139
Array< T > rslice(const int slice) const
rslice
Definition Array3.h:158
void set_values(Array< T > &rhs)
Set the array values from an Array with the equivalent number of values.
Definition Array3.h:269
Array< T > slice(const int slice) const
Get a slice.
Definition Array3.h:184
const T & operator()(const int row, const int col, const int slice) const
Get the array value at (row,col).
Definition Array3.h:356
void resize(const int num_rows, const int num_cols, const int num_slices)
Resize the array.
Definition Array3.h:245
bool allocated()
Test if an array has rows or columns or slices set but no data.
Definition Array3.h:230
T & operator()(const int row, const int col, const int slice)
Set the array value at (row,col).
Definition Array3.h:365
Array3(const Array3 &rhs)
Array copy.
Definition Array3.h:66