svFSIplus
Tensor4.h
1 /**
2  * Copyright (c) Stanford University, The Regents of the University of California, and others.
3  *
4  * All Rights Reserved.
5  *
6  * See Copyright-SimVascular.txt for additional details.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining
9  * a copy of this software and associated documentation files (the
10  * "Software"), to deal in the Software without restriction, including
11  * without limitation the rights to use, copy, modify, merge, publish,
12  * distribute, sublicense, and/or sell copies of the Software, and to
13  * permit persons to whom the Software is furnished to do so, subject
14  * to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
23  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #ifndef TENSOR4_H
33 #define TENSOR4_H
34 
35 #include <cstring>
36 
37 #define Tensor4_check_enabled
38 
39 /// @brief The Tensor4 template class implements a simple interface to 4th order tensors.
40 //
41 template<typename T>
42 class Tensor4
43 {
44  public:
45  std::string name_ = "";
46  int ni_ = 0;
47  int nj_ = 0;
48  int nk_ = 0;
49  int nl_ = 0;
50  int p1_ = 0;
51  int p2_ = 0;
52  int size_ = 0;
53  T *data_ = nullptr;
54 
55  Tensor4()
56  {
57  std::string name_ = "";
58  int ni_ = 0;
59  int nj_ = 0;
60  int nk_ = 0;
61  int nl_ = 0;
62  int p1_ = 0;
63  int p2_ = 0;
64  int size_ = 0;
65  T *data_ = nullptr;
66  };
67 
68  Tensor4(const int num_i, const int num_j, const int num_k, const int num_l)
69  {
70  allocate(num_i, num_j, num_k, num_l);
71  }
72 
73  ~Tensor4()
74  {
75  //std::cout << "- - - - - Tensor4 dtor - - - - - " << std::endl;
76  if (data_ != nullptr) {
77  //std::cout << "[Tensor4 dtor] delete[] data: " << data_ << std::endl;
78  delete [] data_;
79  data_ = nullptr;
80  }
81  }
82 
83  // Copy
84  Tensor4(const Tensor4& rhs)
85  {
86  if (rhs.ni_ <= 0 || rhs.nj_ <= 0 || rhs.nk_ <= 0 || rhs.nl_ <= 0) {
87  return;
88  }
89  allocate(rhs.ni_, rhs.nj_, rhs.nk_, rhs.nl_);
90  memcpy(data_, rhs.data_, size_*sizeof(T));
91  }
92 
93  int num_i() { return ni_; }
94  int num_j() { return nj_; }
95  int num_k() { return nk_; }
96  int num_l() { return nl_; }
97 
98  // Tensor4 assignment.
99  //
100  Tensor4& operator=(const Tensor4& rhs)
101  {
102  if (this == &rhs) {
103  return *this;
104  }
105 
106  if (rhs.ni_ <= 0 || rhs.nj_ <= 0 || rhs.nk_ <= 0 || rhs.nl_ <= 0) {
107  return *this;
108  }
109 
110  if (ni_ != rhs.ni_ || nj_ != rhs.nj_ || nk_ != rhs.nk_ || nl_ != rhs.nl_ <= 0) {
111  clear();
112  //delete [] data_;
113  //data_ = nullptr;
114  allocate(rhs.ni_, rhs.nj_, rhs.nk_, rhs.nl_);
115  }
116 
117  memcpy(data_, rhs.data_, sizeof(T) * size_);
118  return *this;
119  }
120 
121  Tensor4& operator=(const double value)
122  {
123  for (int i = 0; i < size_; i++) {
124  data_[i] = value;
125  }
126  return *this;
127  }
128 
129  void write(const std::string& label, bool memory=true, T offset={}) const
130  {
131  int n = 0;
132  char file_prefix[1000];
133  for (auto c : label) {
134  if (c == '[') {
135  continue;
136  }
137  if (c == ']') {
138  file_prefix[n] = '_';
139  n += 1;
140  continue;
141  }
142  if (c == ' ') {
143  continue;
144  }
145  if (c == ':') {
146  c = '_';
147  }
148  file_prefix[n] = c;
149  n += 1;
150  }
151  file_prefix[n] = '\0';
152 
153  FILE* fp;
154  std::string file_name;
155 
156  // Write binary file.
157  file_name = std::string(file_prefix) + "_cm.bin";
158  std::cout << "[Tensor4::write] file_name: " << file_name << std::endl;
159  fp = fopen(file_name.c_str(), "wb");
160  fwrite(&size_, sizeof(int), 1, fp);
161  fwrite(data_, sizeof(double), size_, fp);
162  fclose(fp);
163  }
164 
165  friend std::ostream& operator << (std::ostream& out, const Tensor4<T>& lhs)
166  {
167  for (int i = 0; i < lhs.size_; i++) {
168  out << lhs.data_[i];
169  if (i != lhs.size_-1) {
170  out << ", ";
171  }
172  }
173  return out;
174  }
175 
176  //----------
177  // allocate
178  //----------
179  //
180  void allocate(const int num_i, const int num_j, const int num_k, const int num_l)
181  {
182  //std::cout << "----- Tensor4::allocate -----" << std::endl;
183  ni_ = num_i;
184  nj_ = num_j;
185  nk_ = num_k;
186  nl_ = num_l;
187  p1_ = num_i * num_j;
188  p2_ = p1_ * num_l;
189  size_ = ni_ * nj_ * nk_ * nl_;
190  data_ = new T [size_];
191  memset(data_, 0, sizeof(T)*size_);
192  //std::cout << "[Tensor4::allocate] data_: " << data_ << std::endl;
193  }
194 
195  //-------------
196  // check_index
197  //-------------
198  //
199  void check_index(const int i, const int j, const int k, const int l) const
200  {
201  if (data_ == nullptr) {
202  throw std::runtime_error(name_+"Accessing null data in Tensor4.");
203  }
204  if ((i < 0) || (i >= ni_) || (j < 0) || (j >= nj_) || (k < 0) || (k >= nk_) || (l < 0) || (l >= nl_)) {
205  auto i_str = std::to_string(ni_);
206  auto j_str = std::to_string(nj_);
207  auto k_str = std::to_string(nk_);
208  auto l_str = std::to_string(nl_);
209  auto dims = i_str + " x " + j_str + " x " + k_str + " x " + l_str;
210  auto index_str = " " + std::to_string(i) + "," + std::to_string(j) + "," + std::to_string(k) + "," + std::to_string(l);
211  throw std::runtime_error("Index (i,j,k,l)=" + index_str + " is out of bounds for " + dims + " array.");
212  }
213  }
214 
215  //-------
216  // clear
217  //-------
218  // Free the array data.
219  //
220  // This is to replicate the Fortran DEALLOCATE().
221  //
222  void clear()
223  {
224  //std::cout << "----- Tensor4::erase -----" << std::endl;
225  if (data_ != nullptr) {
226  //std::cout << "[Tensor4::erase] data_: " << data_ << std::endl;
227  delete [] data_;
228  }
229 
230  ni_ = 0;
231  nj_ = 0;
232  nk_ = 0;
233  nl_ = 0;
234  p1_ = 0;
235  p2_ = 0;
236  size_ = 0;
237  data_ = nullptr;
238  }
239 
240  //--------
241  // resize
242  //--------
243  // Resize the array.
244  //
245  void resize(const int num_i, const int num_j, const int num_k, const int num_l)
246  {
247  if (data_ != nullptr) {
248  //std::cout << "[Tensor4::resize] data_: " << data_ << std::endl;
249  delete [] data_;
250  data_ = nullptr;
251  }
252 
253  allocate(num_i, num_j, num_k, num_l);
254  }
255 
256  /////////////////////////
257  // O p e r a t o r s //
258  /////////////////////////
259 
260  const T& operator()(const int i, const int j, const int k, const int l) const
261  {
262  #ifdef Tensor4_check_enabled
263  check_index(i, j, k , l);
264  #endif
265  return data_[i + j*ni_ + p1_*k + p2_*l ];
266  }
267 
268  T& operator()(const int i, const int j, const int k, const int l)
269  {
270  #ifdef Tensor4_check_enabled
271  check_index(i, j, k , l);
272  #endif
273  return data_[i + j*ni_ + p1_*k + p2_*l ];
274  }
275 
276  ///////////////////////////////////////////////////
277  // M a t h e m a t i c a l o p e r a t o r s //
278  ///////////////////////////////////////////////////
279 
280  // Multiply by a scalar.
281  //
282  Tensor4<T> operator*(const T value) const
283  {
284  Tensor4<T> result(ni_, nj_, nk_, nl_);
285  for (int i = 0; i < size_; i++) {
286  result.data_[i] = value * data_[i];
287  }
288  return result;
289  }
290 
291  friend const Tensor4<T> operator * (const T value, const Tensor4& rhs)
292  {
293  if (rhs.data_ == nullptr) {
294  throw std::runtime_error("Null data for rhs Tensor4.");
295  }
296  Tensor4<T> result(rhs.ni_, rhs.nj_, rhs.nk_, rhs.nl_);
297  for (int i = 0; i < rhs.size_; i++) {
298  result.data_[i] = value * rhs.data_[i];
299  }
300  return result;
301  }
302 
303  // Compound add assignment.
304  //
305  Tensor4<T> operator+=(const Tensor4<T>& rhs) const
306  {
307  for (int i = 0; i < size_; i++) {
308  data_[i] += rhs.data_[i];
309  }
310  return *this;
311  }
312 
313  // Compound subtract assignment.
314  //
315  Tensor4<T> operator-=(const Tensor4<T>& rhs) const
316  {
317  for (int i = 0; i < size_; i++) {
318  data_[i] -= rhs.data_[i];
319  }
320  return *this;
321  }
322 
323  // Add and subtract arrays.
324  //
325  Tensor4<T> operator+(const Tensor4<T>& rhs) const
326  {
327  Tensor4<T> result(rhs.ni_, rhs.nj_, rhs.nk_, rhs.nl_);
328  for (int i = 0; i < size_; i++) {
329  result.data_[i] = data_[i] + rhs.data_[i];
330  }
331  return result;
332  }
333 
334  Tensor4<T> operator-(const Tensor4<T>& rhs) const
335  {
336  Tensor4<T> result(rhs.ni_, rhs.nj_, rhs.nk_, rhs.nl_);
337  for (int i = 0; i < size_; i++) {
338  result.data_[i] = data_[i] - rhs.data_[i];
339  }
340  return result;
341  }
342 
343 };
344 
345 #endif
346 
The Tensor4 template class implements a simple interface to 4th order tensors.
Definition: Tensor4.h:43