svMultiPhysics
All Classes Namespaces Files Functions Variables Pages
Array3.h
1/* Copyright (c) Stanford University, The Regents of the University of California, and others.
2 *
3 * All Rights Reserved.
4 *
5 * See Copyright-SimVascular.txt for additional details.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation the rights to use, copy, modify, merge, publish,
11 * distribute, sublicense, and/or sell copies of the Software, and to
12 * permit persons to whom the Software is furnished to do so, subject
13 * to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "Array.h"
32
33#ifndef ARRAY3_H
34#define ARRAY3_H
35
36#include <float.h>
37#include <iostream>
38#include <string>
39#include <cstring>
40
41#ifdef ENABLE_ARRAY_INDEX_CHECKING
42#define Array3_check_enabled
43#endif
44
45template<typename T>
46
47/*! @brief The Array3 template class implements a simple interface to 3D arrays.
48*
49* A 3D array is defined by (num_rows * num_cols) * num_slices values.
50*/
51class Array3
52{
53 public:
54
55 static int num_allocated;
56 static int active;
57 static bool show_index_check_message;
58 static double memory_in_use;
59 static double memory_returned;
60 static bool write_enabled;
61 static void memory(const std::string& prefix="");
62 static void stats(const std::string& prefix="");
63
64 Array3()
65 {
66 nrows_ = 0;
67 ncols_ = 0;
68 nslices_ = 0;
69 slice_size_ = 0;
70 size_ = 0;
71 data_ = nullptr;
72 num_allocated += 1;
73 active += 1;
74 };
75
76 Array3(const int num_rows, const int num_cols, const int num_slices, bool row_major=true)
77 {
78 // [NOTE] This is tfu but need to mimic fortran.
79 nrows_ = num_rows;
80 ncols_ = num_cols;
81 nslices_ = num_slices;
82
83 if ((num_rows <= 0) || (num_cols <= 0) || (num_slices <= 0)) {
84 return;
85 //throw std::runtime_error(+"Allocating zero size Array3.");
86 }
87
88 allocate(num_rows, num_cols, num_slices, row_major);
89 num_allocated += 1;
90 active += 1;
91 }
92
93 /// @brief Array copy
94 Array3(const Array3 &rhs)
95 {
96 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0) || (rhs.nslices_ <= 0)) {
97 return;
98 }
99
100 allocate(rhs.nrows_, rhs.ncols_, rhs.nslices_);
101 memcpy(data_, rhs.data_, size_*sizeof(T));
102 num_allocated += 1;
103 active += 1;
104 }
105
106 ~Array3()
107 {
108 if (data_ != nullptr) {
109 memory_in_use -= sizeof(T) * size_;;
110 memory_returned += sizeof(T) * size_;;
111 active -= 1;
112 delete [] data_;
113 data_ = nullptr;
114 }
115 }
116
117 int ncols() const { return ncols_; }
118 int nrows() const { return nrows_; }
119 int nslices() const { return nslices_; }
120
121 void allocate(const int num_rows, const int num_cols, const int num_slices, const bool row_major=true)
122 {
123 nrows_ = num_rows;
124 ncols_ = num_cols;
125 nslices_ = num_slices;
126 slice_size_ = ncols_ * nrows_;
127 size_ = nrows_ * ncols_ * nslices_;
128 data_ = new T [size_];
129 memset(data_, 0, sizeof(T)*size_);
130 memory_in_use += sizeof(T) * size_;;
131 }
132
133 void check_index(const int i, const int j, const int k) const
134 {
135 if (show_index_check_message) {
136 std::cout << "[Array3] **********************************" << std::endl;
137 std::cout << "[Array3] WARNING: Index checking is enabled " << std::endl;
138 std::cout << "[Array3] **********************************" << std::endl;
139 show_index_check_message = false;
140 }
141
142 if (data_ == nullptr) {
143 throw std::runtime_error(+"Accessing null data in Array3.");
144 }
145
146 if ((i < 0) || (i >= nrows_) or (j < 0) || (j >= ncols_) or (k < 0) || (k >= nslices_)) {
147 auto i_str = std::to_string(nrows_);
148 auto j_str = std::to_string(ncols_);
149 auto k_str = std::to_string(nslices_);
150 auto dims = i_str + " x " + j_str + " x " + k_str;
151 auto index_str = " " + std::to_string(i) + "," + std::to_string(j) + "," + std::to_string(k) + " ";
152 throw std::runtime_error("Index (i,j,k)=" + index_str + " is out of bounds for " + dims + " array.");
153 }
154 }
155
156 friend std::ostream& operator << (std::ostream& out, const Array3<T>& lhs)
157 {
158 if (lhs.data_ == nullptr) {
159 throw std::runtime_error("[Array3] Accessing null data in ostream.");
160 }
161
162 for (int i = 0; i < lhs.size(); i++) {
163 out << lhs.data_[i];
164 if (i != lhs.size()-1) {
165 out << ", ";
166 }
167 }
168 return out;
169 }
170
171 /// @brief Free the array data
172 ///
173 /// This is to replicate the Fortran DEALLOCATE().
174 void clear()
175 {
176 if (data_ != nullptr) {
177 delete [] data_;
178 memory_in_use -= sizeof(T) * size_;;
179 memory_returned += sizeof(T) * size_;;
180 }
181
182 nrows_ = 0;
183 ncols_ = 0;
184 nslices_ = 0;
185 slice_size_ = 0;
186 size_ = 0;
187 data_ = nullptr;
188 }
189
190 /// @brief rslice
191 ///
192 /// Return an Array with data pointing into the Array3 internal data.
193 Array<T> rslice(const int slice) const
194 {
195 #ifdef Array3_check_enabled
196 check_index(0, 0, slice);
197 #endif
198
199 Array<T> array_slice(nrows_, ncols_, &data_[slice*slice_size_]);
200
201 return array_slice;
202 }
203
204 T* slice_data(const int slice) {
205 return &data_[slice*slice_size_];
206 }
207
208 void print(const std::string& label)
209 {
210 printf("%s (%d): \n", label.c_str(), size_);
211 for (int i = 0; i < size_; i++) {
212 if (data_[i] != 0.0) {
213 printf("%s %d %g\n", label.c_str(), i+1, data_[i]);
214 }
215 }
216 }
217
218 /// @brief Get a slice.
219 Array<T> slice(const int slice) const
220 {
221 #ifdef Array3_check_enabled
222 check_index(0, 0, slice);
223 #endif
224 Array<T> array_slice(nrows_, ncols_);
225
226 for (int col = 0; col < ncols_; col++) {
227 for (int row = 0; row < nrows_; row++) {
228 array_slice(row, col) = data_[row + col*nrows_ + slice*slice_size_];
229 }
230 }
231
232 return array_slice;
233 }
234
235 void set_row(const int col, const int slice, const std::vector<T>& values) const
236 {
237 #ifdef Array3_check_enabled
238 check_index(0, col, slice);
239 #endif
240 for (int row = 0; row < values.size(); row++) {
241 data_[row + col*nrows_ + slice*slice_size_] = values[row];
242 }
243 }
244
245 void set_slice(const int slice, const Array<T>& values) const
246 {
247 #ifdef Array3_check_enabled
248 check_index(0, 0, slice);
249 #endif
250 for (int col = 0; col < ncols_; col++) {
251 for (int row = 0; row < nrows_; row++) {
252 data_[row + col*nrows_ + slice*slice_size_] = values(row,col);
253 }
254 }
255 }
256
257 int size() const
258 {
259 return size_;
260 }
261
262 /// @brief Test if an array has rows or columns or slices set but no data.
263 ///
264 /// [NOTE] This is tfu but need to mimic fortran.
266 {
267 if ((nrows_ > 0) || (ncols_ > 0) || nslices_ > 0) {
268 return true;
269 }
270
271 return false;
272 }
273
274 int msize() const
275 {
276 return size_ * sizeof(T);
277 }
278
279 /// @brief Resize the array.
280 void resize(const int num_rows, const int num_cols, const int num_slices)
281 {
282 // [NOTE] This is tfu but need to mimic fortran.
283 nrows_ = num_rows;
284 ncols_ = num_cols;
285 nslices_ = num_slices;
286
287 if ((num_rows <= 0) || (num_cols <= 0) || (num_slices <= 0)) {
288 return;
289 }
290
291 if (data_ != nullptr) {
292 delete [] data_;
293 memory_in_use -= sizeof(T) * size_;;
294 memory_returned += sizeof(T) * size_;;
295 data_ = nullptr;
296 }
297
298 allocate(num_rows, num_cols, num_slices);
299 }
300
301 /// @brief Set the array values from an Array with the equivalent number of values.
302 ///
303 /// This sort of replicates the Fortan reshape function.
304 void set_values(Array<T>& rhs)
305 {
306 int rhs_size = rhs.size();
307
308 if (size_ != rhs_size) {
309 throw std::runtime_error("The RHS size " + std::to_string(rhs_size) + " does not have the same size " +
310 std::to_string(size_) + " of this array.");
311 }
312
313 auto rhs_data = rhs.data();
314
315 for (int i = 0; i < size_; i++) {
316 data_[i] = rhs_data[i];
317 }
318 }
319
320 void read(const std::string& file_name)
321 {
322 auto fp = fopen(file_name.c_str(), "rb");
323 fread(&size_, sizeof(int), 1, fp);
324 fread(data_, sizeof(double), size_, fp);
325 fclose(fp);
326 }
327
328 void write(const std::string& label, bool memory=true)
329 {
330 if (!write_enabled) {
331 return;
332 }
333
334 auto file_prefix = build_file_prefix(label);
335 auto file_name = file_prefix + "_cm.bin";
336
337 // Write binary file.
338 auto fp = fopen(file_name.c_str(), "wb");
339 fwrite(&size_, sizeof(int), 1, fp);
340 fwrite(data_, sizeof(double), size_, fp);
341 fclose(fp);
342 }
343
344 void append(const std::string& label, bool memory=true)
345 {
346 if (!write_enabled) {
347 return;
348 }
349
350 auto file_prefix = build_file_prefix(label);
351 auto file_name = file_prefix + "_cm.bin";
352
353 // Append to binary file.
354 auto fp = fopen(file_name.c_str(), "ab");
355 fwrite(data_, sizeof(double), size_, fp);
356 fclose(fp);
357 }
358
359 /////////////////////////
360 // O p e r a t o r s //
361 /////////////////////////
362
363 /// @brief Array assignment
364 ///
365 /// Copy data to replicate Fortran behavior.
367 {
368 if ((rhs.nrows_ <= 0) || (rhs.ncols_ <= 0) || (rhs.nslices_ <= 0)) {
369 return *this;
370 }
371
372 if (rhs.data_ == nullptr) {
373 throw std::runtime_error(+"RHS has null data.");
374 }
375
376 if (this == &rhs) {
377 return *this;
378 }
379
380 if (size_ != rhs.size_) {
381 delete [] data_;
382 allocate(rhs.nrows_, rhs.ncols_, rhs.nslices_);
383 }
384
385 memcpy(data_, rhs.data_, sizeof(T) * size_);
386
387 return *this;
388 }
389
390 /// @brief Get the array value at (row,col).
391 const T& operator()(const int row, const int col, const int slice) const
392 {
393 #ifdef Array3_check_enabled
394 check_index(row, col, slice);
395 #endif
396 return data_[row + col*nrows_ + slice*slice_size_];
397 }
398
399 /// @brief Set the array value at (row,col).
400 T& operator()(const int row, const int col, const int slice)
401 {
402 #ifdef Array3_check_enabled
403 check_index(row, col, slice);
404 #endif
405 return data_[row + col*nrows_ + slice*slice_size_];
406 }
407
408 Array3& operator=(const double value)
409 {
410 for (int i = 0; i < size_; i++) {
411 data_[i] = value;
412 }
413 return *this;
414 }
415
416 ///////////////////////////////////////////////////
417 // M a t h e m a t i c a l o p e r a t o r s //
418 ///////////////////////////////////////////////////
419
420 /// @brief Multiply by a scalar.
421 Array3<T> operator * (const T value) const
422 {
423 Array3<T> result(nrows_, ncols_, nslices_);
424 for (int i = 0; i < size_; i++) {
425 result.data_[i] = value * data_[i];
426 }
427 return result;
428 }
429
430 Array3<T>& operator *= (const T value)
431 {
432 for (int i = 0; i < size_; i++) {
433 data_[i] *= value;
434 }
435 return *this;
436 }
437
438 friend const Array3<T> operator * (const T value, const Array3& rhs)
439 {
440 if (rhs.data_ == nullptr) {
441 throw std::runtime_error("Null data for rhs Array3.");
442 }
443 Array3<T> result(rhs.nrows_, rhs.ncols_, rhs.nslices_);
444 for (int i = 0; i < rhs.size_; i++) {
445 result.data_[i] = value * rhs.data_[i];
446 }
447 return result;
448 }
449
450 T* data() const {
451 return data_;
452 }
453
454 private:
455 int nrows_ = 0;
456 int ncols_ = 0;
457 int nslices_ = 0;
458 int slice_size_ = 0;
459 int size_ = 0;
460 T *data_ = nullptr;
461
462};
463
464#endif
465
The Array3 template class implements a simple interface to 3D arrays.
Definition Array3.h:52
Array3 & operator=(const Array3 &rhs)
Array assignment.
Definition Array3.h:366
void clear()
Free the array data.
Definition Array3.h:174
Array< T > rslice(const int slice) const
rslice
Definition Array3.h:193
void set_values(Array< T > &rhs)
Set the array values from an Array with the equivalent number of values.
Definition Array3.h:304
Array< T > slice(const int slice) const
Get a slice.
Definition Array3.h:219
const T & operator()(const int row, const int col, const int slice) const
Get the array value at (row,col).
Definition Array3.h:391
void resize(const int num_rows, const int num_cols, const int num_slices)
Resize the array.
Definition Array3.h:280
bool allocated()
Test if an array has rows or columns or slices set but no data.
Definition Array3.h:265
T & operator()(const int row, const int col, const int slice)
Set the array value at (row,col).
Definition Array3.h:400
Array3(const Array3 &rhs)
Array copy.
Definition Array3.h:94