v0.14.0
Tensor2_antisymmetric_value.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 /* A general version, not for pointers. */
4 
5 #include <ostream>
6 
7 namespace FTensor
8 {
9  template <class T, int Tensor_Dim> class Tensor2_antisymmetric
10  {
11  T data[(Tensor_Dim * (Tensor_Dim - 1)) / 2];
12 
13  public:
14  template <class... U> Tensor2_antisymmetric(U... d) : data{d...}
15  {
16  static_assert(sizeof...(d) == sizeof(data) / sizeof(T),
17  "Incorrect number of Arguments. Constructor should "
18  "initialize the entire Tensor");
19  }
20 
22 
23  /* There are two ways of accessing the values inside,
24  unsafe(int,int) and operator(int,int). unsafe(int,int) will give
25  you a wrong answer if you aren't careful. The problem is that we
26  only store the minimal set of components, but some have different
27  signs. We can't return the negative of a component, and assign
28  something to it, because that would assign something to a
29  temporary. To get the correct answer if you don't want to change
30  the value, just use operator(int,int). */
31 
32  T &unsafe(const int N1, const int N2)
33  {
34 #ifdef FTENSOR_DEBUG
35  if(N1 >= Tensor_Dim || N1 < 0 || N2 >= Tensor_Dim || N2 < 0 || N1 >= N2)
36  {
37  std::stringstream s;
38  s << "Bad index in Tensor2_antisymmetric<T," << Tensor_Dim
39  << ">.operator(" << N1 << "," << N2 << ")" << std::endl;
40  throw std::out_of_range(s.str());
41  }
42 #endif
43  return data[(N2 - 1) + (N1 * (2 * (Tensor_Dim - 1) - N1 - 1)) / 2];
44  }
45 
46  T operator()(const int N1, const int N2) const
47  {
48 #ifdef FTENSOR_DEBUG
49  if(N1 >= Tensor_Dim || N1 < 0 || N2 >= Tensor_Dim || N2 < 0)
50  {
51  std::stringstream s;
52  s << "Bad index in Tensor2_antisymmetric<T," << Tensor_Dim
53  << ">.operator(" << N1 << "," << N2 << ") const" << std::endl;
54  throw std::out_of_range(s.str());
55  }
56 #endif
57  return N1 == N2
58  ? 0
59  : (N1 < N2
60  ? data[(N2 - 1)
61  + (N1 * (2 * (Tensor_Dim - 1) - N1 - 1)) / 2]
62  : -data[(N1 - 1)
63  + (N2 * (2 * (Tensor_Dim - 1) - N2 - 1)) / 2]);
64  }
65 
66  /* These operator()'s are the first part in constructing template
67  expressions. They can be used to slice off lower dimensional
68  parts. They are not entirely safe, since you can accidently use a
69  higher dimension than what is really allowed (like Dim=5). */
70 
71  /* This returns a Tensor2_Expr, since the indices are not really
72  antisymmetric anymore since they cover different dimensions. */
73 
74  template <char i, char j, int Dim0, int Dim1>
75  typename std::enable_if<(Tensor_Dim >= Dim0 && Tensor_Dim >= Dim1),
77  T, Dim0, Dim1, i, j>>::type
78  operator()(const Index<i, Dim0>, const Index<j, Dim1>)
79  {
81  i, j>(*this);
82  }
83 
84  template <char i, char j, int Dim0, int Dim1>
85  typename std::enable_if<
86  (Tensor_Dim >= Dim0 && Tensor_Dim >= Dim1),
88  i, j>>::type
89  operator()(const Index<i, Dim0>, const Index<j, Dim1>) const
90  {
92  Dim1, i, j>(*this);
93  }
94 
95  /* This returns a Tensor2_antisymmetric_Expr, since the indices are still
96  antisymmetric on the lower dimensions. */
97 
98  template <char i, char j, int Dim>
99  typename std::enable_if<
100  (Tensor_Dim >= Dim),
102  i, j>>::type
103  operator()(const Index<i, Dim> index1, const Index<j, Dim> index2)
104  {
106  T, Dim, i, j>(*this);
107  }
108 
109  template <char i, char j, int Dim>
110  typename std::enable_if<
111  (Tensor_Dim >= Dim),
113  Dim, i, j>>::type
114  operator()(const Index<i, Dim> index1, const Index<j, Dim> index2) const
115  {
117  const Tensor2_antisymmetric<T, Tensor_Dim>, T, Dim, i, j>(*this);
118  }
119 
120  /* This is for expressions where a number is used for one slot, and
121  an index for another, yielding a Tensor1_Expr. The non-const
122  versions don't actually create a Tensor2_number_rhs_[01] object.
123  They create a Tensor1_Expr directly, which provides the
124  appropriate indexing operators. The const versions do create a
125  Tensor2_number_[01]. */
126 
127  template <char i, int N, int Dim>
128  typename std::enable_if<
129  (Tensor_Dim >= Dim && Tensor_Dim > N),
130  Tensor1_Expr<
132  Dim, i>>::type
133  operator()(const Index<i, Dim> index1, const Number<N>)
134  {
135  using TensorExpr
138  }
139 
140  template <char i, int N, int Dim>
141  typename std::enable_if<
142  (Tensor_Dim >= Dim && Tensor_Dim > N),
145  T, Dim, i>>::type
146  operator()(const Index<i, Dim> index1, const Number<N>) const
147  {
148  using TensorExpr
150  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
151  }
152 
153  template <char i, int N, int Dim>
154  typename std::enable_if<
155  (Tensor_Dim > N && Tensor_Dim >= Dim),
156  Tensor1_Expr<
158  Dim, i>>::type
159  operator()(const Number<N>, const Index<i, Dim> index1)
160  {
161  using TensorExpr
164  }
165 
166  template <char i, int N, int Dim>
167  typename std::enable_if<
168  (Tensor_Dim > N && Tensor_Dim >= Dim),
171  T, Dim, i>>::type
172  operator()(const Number<N> &n1, const Index<i, Dim> index1) const
173  {
174  using TensorExpr
176  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this));
177  }
178 
179  /* Specializations for using actual numbers instead of Number<> */
180 
181  template <char i, int Dim>
182  typename std::enable_if<
183  (Tensor_Dim >= Dim),
184  Tensor1_Expr<
186  T, Dim, i>>::type
187  operator()(const Index<i, Dim> index1, const int N) const
188  {
189  using TensorExpr
191  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
192  }
193 
194  template <char i, int Dim>
195  typename std::enable_if<
196  (Tensor_Dim >= Dim),
197  Tensor1_Expr<
199  T, Dim, i>>::type
200  operator()(const int N, const Index<i, Dim> index1) const
201  {
202  using TensorExpr
204  return Tensor1_Expr<TensorExpr, T, Dim, i>(TensorExpr(*this, N));
205  }
206 
207  /* These two operator()'s return the Tensor2 with internal
208  contractions, yielding a T. I have to specify one for both
209  const and non-const because otherwise the compiler will use the
210  operator() which gives a Tensor2_Expr<>. */
211 
212  /* TODO Here is a good question. It wont create a problem if i put
213  a higher dimension Index in here but it would be
214  grammatically wrong. Im gonna add it for now, we can discuss it*/
215 
216  template <char i, int Dim>
217  typename std::enable_if<(Tensor_Dim >= Dim), T>::type
218  operator()(const Index<i, Dim> index1, const Index<i, Dim> index2)
219  {
220  return 0;
221  }
222 
223  template <char i, int Dim>
224  typename std::enable_if<(Tensor_Dim >= Dim), T>::type
225  operator()(const Index<i, Dim> index1, const Index<i, Dim> index2) const
226  {
227  return 0;
228  }
229  };
230 }
231 
232 /// JSON compatible output. It only outputs unique, non-zero elments,
233 /// so a 3x3 antisymmetric matrix only outputs 3 elements.
234 
235 namespace FTensor
236 {
237  template <class T, int Tensor_Dim>
239  std::ostream &os, const FTensor::Tensor2_antisymmetric<T, Tensor_Dim> &t,
240  const int &i)
241  {
242  os << '[';
243  for(int j = i + 1; j + 1 < Tensor_Dim; ++j)
244  {
245  os << t(i, j) << ',';
246  }
247  if(Tensor_Dim > 0)
248  {
249  os << t(i, Tensor_Dim - 1);
250  }
251  os << ']';
252  return os;
253  }
254 }
255 
256 template <class T, int Tensor_Dim>
257 std::ostream &
258 operator<<(std::ostream &os,
260 {
261  os << '[';
262  for(int i = 0; i + 2 < Tensor_Dim; ++i)
263  {
265  os << ',';
266  }
267  if(Tensor_Dim > 1)
268  {
269  FTensor::Tensor2_antisymmetric_ostream_row(os, t, Tensor_Dim - 2);
270  }
271  os << ']';
272  return os;
273 }
274 
275 namespace FTensor
276 {
277  template <class T, int Tensor_Dim>
280  const int &i)
281  {
282  char c;
283  is >> c;
284  for(int j = i + 1; j + 1 < Tensor_Dim; ++j)
285  {
286  is >> t.unsafe(i, j) >> c;
287  }
288  if(Tensor_Dim > 0)
289  {
290  is >> t.unsafe(i, Tensor_Dim - 1);
291  }
292  is >> c;
293  return is;
294  }
295 }
296 
297 template <class T, int Tensor_Dim>
298 std::istream &
300 {
301  char c;
302  is >> c;
303  for(int i = 0; i + 2 < Tensor_Dim; ++i)
304  {
306  is >> c;
307  }
308  if(Tensor_Dim > 1)
309  {
310  FTensor::Tensor2_antisymmetric_istream_row(is, t, Tensor_Dim - 2);
311  }
312  is >> c;
313  return is;
314 }
FTensor
JSON compatible output.
Definition: Christof_constructor.hpp:6
FTensor::Tensor2_antisymmetric_Expr
Definition: Tensor2_antisymmetric_Expr.hpp:9
FTensor::Tensor2_antisymmetric::unsafe
T & unsafe(const int N1, const int N2)
Definition: Tensor2_antisymmetric_value.hpp:32
FTensor::Tensor2_number_rhs_1
Definition: Tensor2_number.hpp:29
FTensor::Tensor2_numeral_1
Definition: Tensor2_numeral.hpp:8
FTensor::Tensor2_Expr
Definition: Tensor2_Expr.hpp:26
FTensor::d
const Tensor1_Expr< const dTensor0< T, Dim, i >, typename promote< T, double >::V, Dim, i > d(const Tensor0< T * > &a, const Index< i, Dim > index, const Tensor1< int, Dim > &d_ijk, const Tensor1< double, Dim > &d_xyz)
Definition: dTensor0.hpp:27
FTensor::Tensor2_antisymmetric::Tensor2_antisymmetric
Tensor2_antisymmetric(U... d)
Definition: Tensor2_antisymmetric_value.hpp:14
operator<<
std::ostream & operator<<(std::ostream &os, const FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t)
Definition: Tensor2_antisymmetric_value.hpp:258
FTensor::Tensor2_number_1
Definition: Tensor2_number.hpp:8
c
const double c
speed of light (cm/ns)
Definition: initial_diffusion.cpp:39
FTensor::Tensor2_antisymmetric_istream_row
std::istream & Tensor2_antisymmetric_istream_row(std::istream &is, FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t, const int &i)
Definition: Tensor2_antisymmetric_value.hpp:278
FTensor::Tensor2_antisymmetric::Tensor2_antisymmetric
Tensor2_antisymmetric()
Definition: Tensor2_antisymmetric_value.hpp:21
FTensor::Number
Definition: Number.hpp:11
FTensor::Tensor1_Expr
Definition: Tensor1_Expr.hpp:27
convert.type
type
Definition: convert.py:64
FTensor::Tensor2_antisymmetric
Definition: Tensor2_antisymmetric_value.hpp:9
FTensor::Tensor2_number_0
Definition: Tensor2_number.hpp:17
t
constexpr double t
plate stiffness
Definition: plate.cpp:59
i
FTensor::Index< 'i', SPACE_DIM > i
Definition: hcurl_divergence_operator_2d.cpp:27
FTensor::Index
Definition: Index.hpp:23
FTensor::Tensor2_antisymmetric::data
T data[(Tensor_Dim *(Tensor_Dim - 1))/2]
Definition: Tensor2_antisymmetric_value.hpp:11
std::enable_if
Definition: enable_if.hpp:7
N
const int N
Definition: speed_test.cpp:3
FTensor::Tensor2_antisymmetric::operator()
T operator()(const int N1, const int N2) const
Definition: Tensor2_antisymmetric_value.hpp:46
j
FTensor::Index< 'j', 3 > j
Definition: matrix_function.cpp:19
FTensor::Tensor2_antisymmetric_ostream_row
std::ostream & Tensor2_antisymmetric_ostream_row(std::ostream &os, const FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t, const int &i)
Definition: Tensor2_antisymmetric_value.hpp:238
FTensor::Tensor2_number_rhs_0
Definition: Tensor2_number.hpp:26
operator>>
std::istream & operator>>(std::istream &is, FTensor::Tensor2_antisymmetric< T, Tensor_Dim > &t)
Definition: Tensor2_antisymmetric_value.hpp:299
EshelbianPlasticity::U
@ U
Definition: EshelbianContact.cpp:193
FTensor::Tensor2_numeral_0
Definition: Tensor2_numeral.hpp:18