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