Reference documentation for deal.II version 8.4.2
symmetric_tensor.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2005 - 2016 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii__symmetric_tensor_h
17 #define dealii__symmetric_tensor_h
18 
19 
20 #include <deal.II/base/tensor.h>
21 #include <deal.II/base/table_indices.h>
22 #include <deal.II/base/template_constraints.h>
23 
24 DEAL_II_NAMESPACE_OPEN
25 
26 template <int rank, int dim, typename Number=double> class SymmetricTensor;
27 
28 template <int dim, typename Number> SymmetricTensor<2,dim,Number>
30 template <int dim, typename Number> SymmetricTensor<4,dim,Number>
32 template <int dim, typename Number> SymmetricTensor<4,dim,Number>
34 template <int dim, typename Number> SymmetricTensor<4,dim,Number>
36 template <int dim2, typename Number> Number
38 
39 template <int dim, typename Number> SymmetricTensor<2,dim,Number>
41 template <int dim, typename Number> Number
43 
44 
45 
46 namespace internal
47 {
52  namespace SymmetricTensorAccessors
53  {
60  inline
61  TableIndices<2> merge (const TableIndices<2> &previous_indices,
62  const unsigned int new_index,
63  const unsigned int position)
64  {
65  Assert (position < 2, ExcIndexRange (position, 0, 2));
66 
67  if (position == 0)
68  return TableIndices<2>(new_index);
69  else
70  return TableIndices<2>(previous_indices[0], new_index);
71  }
72 
73 
74 
81  inline
82  TableIndices<4> merge (const TableIndices<4> &previous_indices,
83  const unsigned int new_index,
84  const unsigned int position)
85  {
86  Assert (position < 4, ExcIndexRange (position, 0, 4));
87 
88  switch (position)
89  {
90  case 0:
91  return TableIndices<4>(new_index);
92  case 1:
93  return TableIndices<4>(previous_indices[0],
94  new_index);
95  case 2:
96  return TableIndices<4>(previous_indices[0],
97  previous_indices[1],
98  new_index);
99  case 3:
100  return TableIndices<4>(previous_indices[0],
101  previous_indices[1],
102  previous_indices[2],
103  new_index);
104  }
105  Assert (false, ExcInternalError());
106  return TableIndices<4>();
107  }
108 
109 
118  template <int rank1, int rank2, int dim, typename Number>
120  {
121  typedef ::SymmetricTensor<rank1+rank2-4,dim,Number> type;
122  };
123 
124 
133  template <int dim, typename Number>
134  struct double_contraction_result<2,2,dim,Number>
135  {
136  typedef Number type;
137  };
138 
139 
140 
153  template <int rank, int dim, typename Number>
154  struct StorageType;
155 
159  template <int dim, typename Number>
160  struct StorageType<2,dim,Number>
161  {
166  static const unsigned int
167  n_independent_components = (dim*dim + dim)/2;
168 
173  };
174 
175 
176 
180  template <int dim, typename Number>
181  struct StorageType<4,dim,Number>
182  {
188  static const unsigned int
189  n_rank2_components = (dim*dim + dim)/2;
190 
194  static const unsigned int
195  n_independent_components = (n_rank2_components *
197 
205  };
206 
207 
208 
213  template <int rank, int dim, bool constness, typename Number>
215 
222  template <int rank, int dim, typename Number>
223  struct AccessorTypes<rank,dim,true,Number>
224  {
225  typedef const ::SymmetricTensor<rank,dim,Number> tensor_type;
226 
227  typedef Number reference;
228  };
229 
236  template <int rank, int dim, typename Number>
237  struct AccessorTypes<rank,dim,false,Number>
238  {
239  typedef ::SymmetricTensor<rank,dim,Number> tensor_type;
240 
241  typedef Number &reference;
242  };
243 
244 
279  template <int rank, int dim, bool constness, int P, typename Number>
280  class Accessor
281  {
282  public:
286  typedef typename AccessorTypes<rank,dim,constness,Number>::reference reference;
288 
289  private:
308  Accessor (tensor_type &tensor,
309  const TableIndices<rank> &previous_indices);
310 
314  Accessor ();
315 
319  Accessor (const Accessor &a);
320 
321  public:
322 
326  Accessor<rank,dim,constness,P-1,Number> operator [] (const unsigned int i);
327 
328  private:
332  tensor_type &tensor;
333  const TableIndices<rank> previous_indices;
334 
335  // declare some other classes
336  // as friends. make sure to
337  // work around bugs in some
338  // compilers
339  template <int,int,typename> friend class ::SymmetricTensor;
340  template <int,int,bool,int,typename>
341  friend class Accessor;
342 # ifndef DEAL_II_TEMPL_SPEC_FRIEND_BUG
343  friend class ::SymmetricTensor<rank,dim,Number>;
344  friend class Accessor<rank,dim,constness,P+1,Number>;
345 # endif
346  };
347 
348 
349 
359  template <int rank, int dim, bool constness, typename Number>
360  class Accessor<rank,dim,constness,1,Number>
361  {
362  public:
366  typedef typename AccessorTypes<rank,dim,constness,Number>::reference reference;
368 
369  private:
391  Accessor (tensor_type &tensor,
392  const TableIndices<rank> &previous_indices);
393 
397  Accessor ();
398 
402  Accessor (const Accessor &a);
403 
404  public:
405 
409  reference operator [] (const unsigned int);
410 
411  private:
415  tensor_type &tensor;
416  const TableIndices<rank> previous_indices;
417 
418  // declare some other classes
419  // as friends. make sure to
420  // work around bugs in some
421  // compilers
422  template <int,int,typename> friend class ::SymmetricTensor;
423  template <int,int,bool,int,typename>
424  friend class SymmetricTensorAccessors::Accessor;
425 # ifndef DEAL_II_TEMPL_SPEC_FRIEND_BUG
426  friend class ::SymmetricTensor<rank,dim,Number>;
427  friend class SymmetricTensorAccessors::Accessor<rank,dim,constness,2,Number>;
428 # endif
429  };
430  }
431 }
432 
433 
434 
497 template <int rank, int dim, typename Number>
498 class SymmetricTensor
499 {
500 public:
509  static const unsigned int dimension = dim;
510 
516  static const unsigned int n_independent_components
518  n_independent_components;
519 
523  SymmetricTensor ();
524 
536 
552  SymmetricTensor (const Number (&array) [n_independent_components]);
553 
559  template <typename OtherNumber>
560  explicit
562 
566  SymmetricTensor &operator = (const SymmetricTensor &);
567 
574  SymmetricTensor &operator = (const Number d);
575 
580  operator Tensor<rank,dim,Number> () const;
581 
585  bool operator == (const SymmetricTensor &) const;
586 
590  bool operator != (const SymmetricTensor &) const;
591 
595  SymmetricTensor &operator += (const SymmetricTensor &);
596 
600  SymmetricTensor &operator -= (const SymmetricTensor &);
601 
606  SymmetricTensor &operator *= (const Number factor);
607 
611  SymmetricTensor &operator /= (const Number factor);
612 
617  SymmetricTensor operator + (const SymmetricTensor &s) const;
618 
623  SymmetricTensor operator - (const SymmetricTensor &s) const;
624 
628  SymmetricTensor operator - () const;
629 
655  operator * (const SymmetricTensor<2,dim,Number> &s) const;
656 
662  operator * (const SymmetricTensor<4,dim,Number> &s) const;
663 
667  Number &operator() (const TableIndices<rank> &indices);
668 
676  Number operator() (const TableIndices<rank> &indices) const;
677 
682  internal::SymmetricTensorAccessors::Accessor<rank,dim,true,rank-1,Number>
683  operator [] (const unsigned int row) const;
684 
689  internal::SymmetricTensorAccessors::Accessor<rank,dim,false,rank-1,Number>
690  operator [] (const unsigned int row);
691 
695  Number
696  operator [] (const TableIndices<rank> &indices) const;
697 
701  Number &
702  operator [] (const TableIndices<rank> &indices);
703 
709  Number
710  access_raw_entry (const unsigned int unrolled_index) const;
711 
717  Number &
718  access_raw_entry (const unsigned int unrolled_index);
719 
729  Number norm () const;
730 
738  static
739  unsigned int
740  component_to_unrolled_index (const TableIndices<rank> &indices);
741 
747  static
749  unrolled_to_component_indices (const unsigned int i);
750 
763  void clear ();
764 
769  static std::size_t memory_consumption ();
770 
775  template <class Archive>
776  void serialize(Archive &ar, const unsigned int version);
777 
778 private:
782  typedef
785 
789  typedef typename base_tensor_descriptor::base_tensor_type base_tensor_type;
790 
794  base_tensor_type data;
795 
799  template <int, int, typename> friend class SymmetricTensor;
800 
804  template <int dim2, typename Number2>
805  friend Number2 trace (const SymmetricTensor<2,dim2,Number2> &d);
806 
807  template <int dim2, typename Number2>
808  friend Number2 determinant (const SymmetricTensor<2,dim2,Number2> &t);
809 
810  template <int dim2, typename Number2>
812  deviator (const SymmetricTensor<2,dim2,Number2> &t);
813 
814  template <int dim2, typename Number2>
816 
817  template <int dim2, typename Number2>
819 
820  template <int dim2, typename Number2>
822 
823  template <int dim2, typename Number2>
825 };
826 
827 
828 
829 // ------------------------- inline functions ------------------------
830 
831 #ifndef DOXYGEN
832 
833 namespace internal
834 {
835  namespace SymmetricTensorAccessors
836  {
837  template <int rank, int dim, bool constness, int P, typename Number>
838  Accessor<rank,dim,constness,P,Number>::
839  Accessor ()
840  :
841  tensor (*static_cast<tensor_type *>(0)),
842  previous_indices ()
843  {
844  Assert (false, ExcMessage ("You can't call the default constructor of this class."));
845  }
846 
847 
848  template <int rank, int dim, bool constness, int P, typename Number>
849  Accessor<rank,dim,constness,P,Number>::
850  Accessor (tensor_type &tensor,
851  const TableIndices<rank> &previous_indices)
852  :
853  tensor (tensor),
854  previous_indices (previous_indices)
855  {}
856 
857 
858  template <int rank, int dim, bool constness, int P, typename Number>
859  Accessor<rank,dim,constness,P,Number>::
860  Accessor (const Accessor &a)
861  :
862  tensor (a.tensor),
863  previous_indices (a.previous_indices)
864  {}
865 
866 
867 
868  template <int rank, int dim, bool constness, int P, typename Number>
869  Accessor<rank,dim,constness,P-1,Number>
870  Accessor<rank,dim,constness,P,Number>::operator[] (const unsigned int i)
871  {
872  return Accessor<rank,dim,constness,P-1,Number> (tensor,
873  merge (previous_indices, i, rank-P));
874  }
875 
876 
877 
878  template <int rank, int dim, bool constness, typename Number>
879  Accessor<rank,dim,constness,1,Number>::
880  Accessor ()
881  :
882  tensor (*static_cast<tensor_type *>(0)),
883  previous_indices ()
884  {
885  Assert (false, ExcMessage ("You can't call the default constructor of this class."));
886  }
887 
888 
889 
890  template <int rank, int dim, bool constness, typename Number>
891  Accessor<rank,dim,constness,1,Number>::
892  Accessor (tensor_type &tensor,
893  const TableIndices<rank> &previous_indices)
894  :
895  tensor (tensor),
896  previous_indices (previous_indices)
897  {}
898 
899 
900 
901  template <int rank, int dim, bool constness, typename Number>
902  Accessor<rank,dim,constness,1,Number>::
903  Accessor (const Accessor &a)
904  :
905  tensor (a.tensor),
906  previous_indices (a.previous_indices)
907  {}
908 
909 
910 
911  template <int rank, int dim, bool constness, typename Number>
912  typename Accessor<rank,dim,constness,1,Number>::reference
913  Accessor<rank,dim,constness,1,Number>::operator[] (const unsigned int i)
914  {
915  return tensor(merge (previous_indices, i, rank-1));
916  }
917 
918 
919  }
920 }
921 
922 
923 
924 template <int rank, int dim, typename Number>
925 inline
927 {}
928 
929 
930 
931 template <int rank, int dim, typename Number>
932 inline
934 {
935  Assert (rank == 2, ExcNotImplemented());
936  switch (dim)
937  {
938  case 2:
939  Assert (t[0][1] == t[1][0], ExcInternalError());
940 
941  data[0] = t[0][0];
942  data[1] = t[1][1];
943  data[2] = t[0][1];
944 
945  break;
946  case 3:
947  Assert (t[0][1] == t[1][0], ExcInternalError());
948  Assert (t[0][2] == t[2][0], ExcInternalError());
949  Assert (t[1][2] == t[2][1], ExcInternalError());
950 
951  data[0] = t[0][0];
952  data[1] = t[1][1];
953  data[2] = t[2][2];
954  data[3] = t[0][1];
955  data[4] = t[0][2];
956  data[5] = t[1][2];
957 
958  break;
959  default:
960  for (unsigned int d=0; d<dim; ++d)
961  for (unsigned int e=0; e<d; ++e)
962  Assert(t[d][e] == t[e][d], ExcInternalError());
963 
964  for (unsigned int d=0; d<dim; ++d)
965  data[d] = t[d][d];
966 
967  for (unsigned int d=0, c=0; d<dim; ++d)
968  for (unsigned int e=d+1; e<dim; ++e, ++c)
969  data[dim+c] = t[d][e];
970  }
971 }
972 
973 
974 
975 template <int rank, int dim, typename Number>
976 template <typename OtherNumber>
977 inline
980 {
981  for (unsigned int i=0; i<n_independent_components; ++i)
982  data[i] = initializer.data[i];
983 }
984 
985 
986 
987 
988 template <int rank, int dim, typename Number>
989 inline
991  :
992  data (*reinterpret_cast<const typename base_tensor_type::array_type *>(array))
993 {
994  // ensure that the reinterpret_cast above actually works
995  Assert (sizeof(typename base_tensor_type::array_type)
996  == sizeof(array),
997  ExcInternalError());
998 }
999 
1000 
1001 
1002 template <int rank, int dim, typename Number>
1003 inline
1006 {
1007  data = t.data;
1008  return *this;
1009 }
1010 
1011 
1012 
1013 template <int rank, int dim, typename Number>
1014 inline
1017 {
1018  Assert (d==0, ExcMessage ("Only assignment with zero is allowed"));
1019  (void) d;
1020 
1021  data = 0;
1022 
1023  return *this;
1024 }
1025 
1026 
1027 
1028 template <int rank, int dim, typename Number>
1029 inline
1031 operator Tensor<rank,dim,Number> () const
1032 {
1033  Assert (rank == 2, ExcNotImplemented());
1034  Number t[dim][dim];
1035  for (unsigned int d=0; d<dim; ++d)
1036  t[d][d] = data[d];
1037  for (unsigned int d=0, c=0; d<dim; ++d)
1038  for (unsigned int e=d+1; e<dim; ++e, ++c)
1039  {
1040  t[d][e] = data[dim+c];
1041  t[e][d] = data[dim+c];
1042  }
1043  return Tensor<2,dim,Number>(t);
1044 }
1045 
1046 
1047 
1048 template <int rank, int dim, typename Number>
1049 inline
1050 bool
1052 (const SymmetricTensor<rank,dim,Number> &t) const
1053 {
1054  return data == t.data;
1055 }
1056 
1057 
1058 
1059 template <int rank, int dim, typename Number>
1060 inline
1061 bool
1062 SymmetricTensor<rank,dim,Number>::operator !=
1063 (const SymmetricTensor<rank,dim,Number> &t) const
1064 {
1065  return data != t.data;
1066 }
1067 
1068 
1069 
1070 template <int rank, int dim, typename Number>
1071 inline
1073 SymmetricTensor<rank,dim,Number>::operator +=
1075 {
1076  data += t.data;
1077  return *this;
1078 }
1079 
1080 
1081 
1082 template <int rank, int dim, typename Number>
1083 inline
1085 SymmetricTensor<rank,dim,Number>::operator -=
1087 {
1088  data -= t.data;
1089  return *this;
1090 }
1091 
1092 
1093 
1094 template <int rank, int dim, typename Number>
1095 inline
1098 {
1099  data *= d;
1100  return *this;
1101 }
1102 
1103 
1104 
1105 template <int rank, int dim, typename Number>
1106 inline
1109 {
1110  data /= d;
1111  return *this;
1112 }
1113 
1114 
1115 
1116 template <int rank, int dim, typename Number>
1117 inline
1120 {
1121  SymmetricTensor tmp = *this;
1122  tmp.data += t.data;
1123  return tmp;
1124 }
1125 
1126 
1127 
1128 template <int rank, int dim, typename Number>
1129 inline
1132 {
1133  SymmetricTensor tmp = *this;
1134  tmp.data -= t.data;
1135  return tmp;
1136 }
1137 
1138 
1139 
1140 template <int rank, int dim, typename Number>
1141 inline
1144 {
1145  SymmetricTensor tmp = *this;
1146  tmp.data = -tmp.data;
1147  return tmp;
1148 }
1149 
1150 
1151 
1152 template <int rank, int dim, typename Number>
1153 inline
1154 void
1156 {
1157  data.clear ();
1158 }
1159 
1160 
1161 
1162 template <int rank, int dim, typename Number>
1163 inline
1164 std::size_t
1166 {
1167  return
1169 }
1170 
1171 
1172 
1173 namespace internal
1174 {
1175 
1176  template <int dim, typename Number>
1177  inline
1178  typename SymmetricTensorAccessors::double_contraction_result<2,2,dim,Number>::type
1179  perform_double_contraction (const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &data,
1180  const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &sdata)
1181  {
1182  switch (dim)
1183  {
1184  case 1:
1185  return data[0] * sdata[0];
1186  case 2:
1187  return (data[0] * sdata[0] +
1188  data[1] * sdata[1] +
1189  2*data[2] * sdata[2]);
1190  default:
1191  // Start with the non-diagonal part to avoid some multiplications by
1192  // 2.
1193  Number sum = data[dim] * sdata[dim];
1194  for (unsigned int d=dim+1; d<(dim*(dim+1)/2); ++d)
1195  sum += data[d] * sdata[d];
1196  sum *= 2.;
1197  for (unsigned int d=0; d<dim; ++d)
1198  sum += data[d] * sdata[d];
1199  return sum;
1200  }
1201  }
1202 
1203 
1204 
1205  template <int dim, typename Number>
1206  inline
1207  typename SymmetricTensorAccessors::double_contraction_result<4,2,dim,Number>::type
1208  perform_double_contraction (const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &data,
1209  const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &sdata)
1210  {
1211  const unsigned int data_dim =
1212  SymmetricTensorAccessors::StorageType<2,dim,Number>::n_independent_components;
1213  Number tmp [data_dim];
1214  for (unsigned int i=0; i<data_dim; ++i)
1215  tmp[i] = perform_double_contraction<dim,Number>(data[i], sdata);
1216  return ::SymmetricTensor<2,dim,Number>(tmp);
1217  }
1218 
1219 
1220 
1221  template <int dim, typename Number>
1222  inline
1223  typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type
1224  perform_double_contraction (const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &data,
1225  const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &sdata)
1226  {
1227  typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type tmp;
1228  for (unsigned int i=0; i<tmp.dimension; ++i)
1229  {
1230  for (unsigned int d=0; d<dim; ++d)
1231  tmp[i] += data[d] * sdata[d][i];
1232  for (unsigned int d=dim; d<(dim*(dim+1)/2); ++d)
1233  tmp[i] += 2 * data[d] * sdata[d][i];
1234  }
1235  return tmp;
1236  }
1237 
1238 
1239 
1240  template <int dim, typename Number>
1241  inline
1242  typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type
1243  perform_double_contraction (const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &data,
1244  const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &sdata)
1245  {
1246  const unsigned int data_dim =
1247  SymmetricTensorAccessors::StorageType<2,dim,Number>::n_independent_components;
1248  typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type tmp;
1249  for (unsigned int i=0; i<data_dim; ++i)
1250  for (unsigned int j=0; j<data_dim; ++j)
1251  {
1252  for (unsigned int d=0; d<dim; ++d)
1253  tmp[i][j] += data[i][d] * sdata[d][j];
1254  for (unsigned int d=dim; d<(dim*(dim+1)/2); ++d)
1255  tmp[i][j] += 2 * data[i][d] * sdata[d][j];
1256  }
1257  return tmp;
1258  }
1259 
1260 } // end of namespace internal
1261 
1262 
1263 
1264 template <int rank, int dim, typename Number>
1265 inline
1268 {
1269  // need to have two different function calls
1270  // because a scalar and rank-2 tensor are not
1271  // the same data type (see internal function
1272  // above)
1273  return internal::perform_double_contraction<dim,Number> (data, s.data);
1274 }
1275 
1276 
1277 
1278 template <int rank, int dim, typename Number>
1279 inline
1282 {
1283  typename internal::SymmetricTensorAccessors::
1284  double_contraction_result<rank,4,dim,Number>::type tmp;
1285  tmp.data = internal::perform_double_contraction<dim,Number> (data,s.data);
1286  return tmp;
1287 }
1288 
1289 
1290 
1291 // internal namespace to switch between the
1292 // access of different tensors. There used to
1293 // be explicit instantiations before for
1294 // different ranks and dimensions, but since
1295 // we now allow for templates on the data
1296 // type, and since we cannot partially
1297 // specialize the implementation, this got
1298 // into a separate namespace
1299 namespace internal
1300 {
1301  template <int dim, typename Number>
1302  inline
1303  Number &
1304  symmetric_tensor_access (const TableIndices<2> &indices,
1305  typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &data)
1306  {
1307  // 1d is very simple and done first
1308  if (dim == 1)
1309  return data[0];
1310 
1311  // first treat the main diagonal elements, which are stored consecutively
1312  // at the beginning
1313  if (indices[0] == indices[1])
1314  return data[indices[0]];
1315 
1316  // the rest is messier and requires a few switches.
1317  switch (dim)
1318  {
1319  case 2:
1320  // at least for the 2x2 case it is reasonably simple
1321  Assert (((indices[0]==1) && (indices[1]==0)) ||
1322  ((indices[0]==0) && (indices[1]==1)),
1323  ExcInternalError());
1324  return data[2];
1325 
1326  default:
1327  // to do the rest, sort our indices before comparing
1328  {
1329  TableIndices<2> sorted_indices (indices);
1330  sorted_indices.sort ();
1331 
1332  for (unsigned int d=0, c=0; d<dim; ++d)
1333  for (unsigned int e=d+1; e<dim; ++e, ++c)
1334  if ((sorted_indices[0]==d) && (sorted_indices[1]==e))
1335  return data[dim+c];
1336  Assert (false, ExcInternalError());
1337  }
1338  }
1339 
1340  static Number dummy_but_referenceable = Number();
1341  return dummy_but_referenceable;
1342  }
1343 
1344 
1345 
1346  template <int dim, typename Number>
1347  inline
1348  Number
1349  symmetric_tensor_access (const TableIndices<2> &indices,
1350  const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &data)
1351  {
1352  // 1d is very simple and done first
1353  if (dim == 1)
1354  return data[0];
1355 
1356  // first treat the main diagonal elements, which are stored consecutively
1357  // at the beginning
1358  if (indices[0] == indices[1])
1359  return data[indices[0]];
1360 
1361  // the rest is messier and requires a few switches.
1362  switch (dim)
1363  {
1364  case 2:
1365  // at least for the 2x2 case it is reasonably simple
1366  Assert (((indices[0]==1) && (indices[1]==0)) ||
1367  ((indices[0]==0) && (indices[1]==1)),
1368  ExcInternalError());
1369  return data[2];
1370 
1371  default:
1372  // to do the rest, sort our indices before comparing
1373  {
1374  TableIndices<2> sorted_indices (indices);
1375  sorted_indices.sort ();
1376 
1377  for (unsigned int d=0, c=0; d<dim; ++d)
1378  for (unsigned int e=d+1; e<dim; ++e, ++c)
1379  if ((sorted_indices[0]==d) && (sorted_indices[1]==e))
1380  return data[dim+c];
1381  Assert (false, ExcInternalError());
1382  }
1383  }
1384 
1385  static Number dummy_but_referenceable = Number();
1386  return dummy_but_referenceable;
1387  }
1388 
1389 
1390 
1391  template <int dim, typename Number>
1392  inline
1393  Number &
1394  symmetric_tensor_access (const TableIndices<4> &indices,
1395  typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &data)
1396  {
1397  switch (dim)
1398  {
1399  case 1:
1400  return data[0][0];
1401 
1402  case 2:
1403  // each entry of the tensor can be
1404  // thought of as an entry in a
1405  // matrix that maps the rolled-out
1406  // rank-2 tensors into rolled-out
1407  // rank-2 tensors. this is the
1408  // format in which we store rank-4
1409  // tensors. determine which
1410  // position the present entry is
1411  // stored in
1412  {
1413  unsigned int base_index[2] ;
1414  if ((indices[0] == 0) && (indices[1] == 0))
1415  base_index[0] = 0;
1416  else if ((indices[0] == 1) && (indices[1] == 1))
1417  base_index[0] = 1;
1418  else
1419  base_index[0] = 2;
1420 
1421  if ((indices[2] == 0) && (indices[3] == 0))
1422  base_index[1] = 0;
1423  else if ((indices[2] == 1) && (indices[3] == 1))
1424  base_index[1] = 1;
1425  else
1426  base_index[1] = 2;
1427 
1428  return data[base_index[0]][base_index[1]];
1429  }
1430 
1431  case 3:
1432  // each entry of the tensor can be
1433  // thought of as an entry in a
1434  // matrix that maps the rolled-out
1435  // rank-2 tensors into rolled-out
1436  // rank-2 tensors. this is the
1437  // format in which we store rank-4
1438  // tensors. determine which
1439  // position the present entry is
1440  // stored in
1441  {
1442  unsigned int base_index[2] ;
1443  if ((indices[0] == 0) && (indices[1] == 0))
1444  base_index[0] = 0;
1445  else if ((indices[0] == 1) && (indices[1] == 1))
1446  base_index[0] = 1;
1447  else if ((indices[0] == 2) && (indices[1] == 2))
1448  base_index[0] = 2;
1449  else if (((indices[0] == 0) && (indices[1] == 1)) ||
1450  ((indices[0] == 1) && (indices[1] == 0)))
1451  base_index[0] = 3;
1452  else if (((indices[0] == 0) && (indices[1] == 2)) ||
1453  ((indices[0] == 2) && (indices[1] == 0)))
1454  base_index[0] = 4;
1455  else
1456  {
1457  Assert (((indices[0] == 1) && (indices[1] == 2)) ||
1458  ((indices[0] == 2) && (indices[1] == 1)),
1459  ExcInternalError());
1460  base_index[0] = 5;
1461  }
1462 
1463  if ((indices[2] == 0) && (indices[3] == 0))
1464  base_index[1] = 0;
1465  else if ((indices[2] == 1) && (indices[3] == 1))
1466  base_index[1] = 1;
1467  else if ((indices[2] == 2) && (indices[3] == 2))
1468  base_index[1] = 2;
1469  else if (((indices[2] == 0) && (indices[3] == 1)) ||
1470  ((indices[2] == 1) && (indices[3] == 0)))
1471  base_index[1] = 3;
1472  else if (((indices[2] == 0) && (indices[3] == 2)) ||
1473  ((indices[2] == 2) && (indices[3] == 0)))
1474  base_index[1] = 4;
1475  else
1476  {
1477  Assert (((indices[2] == 1) && (indices[3] == 2)) ||
1478  ((indices[2] == 2) && (indices[3] == 1)),
1479  ExcInternalError());
1480  base_index[1] = 5;
1481  }
1482 
1483  return data[base_index[0]][base_index[1]];
1484  }
1485 
1486  default:
1487  Assert (false, ExcNotImplemented());
1488  }
1489 
1490  static Number dummy;
1491  return dummy;
1492  }
1493 
1494 
1495  template <int dim, typename Number>
1496  inline
1497  Number
1498  symmetric_tensor_access (const TableIndices<4> &indices,
1499  const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &data)
1500  {
1501  switch (dim)
1502  {
1503  case 1:
1504  return data[0][0];
1505 
1506  case 2:
1507  // each entry of the tensor can be
1508  // thought of as an entry in a
1509  // matrix that maps the rolled-out
1510  // rank-2 tensors into rolled-out
1511  // rank-2 tensors. this is the
1512  // format in which we store rank-4
1513  // tensors. determine which
1514  // position the present entry is
1515  // stored in
1516  {
1517  unsigned int base_index[2] ;
1518  if ((indices[0] == 0) && (indices[1] == 0))
1519  base_index[0] = 0;
1520  else if ((indices[0] == 1) && (indices[1] == 1))
1521  base_index[0] = 1;
1522  else
1523  base_index[0] = 2;
1524 
1525  if ((indices[2] == 0) && (indices[3] == 0))
1526  base_index[1] = 0;
1527  else if ((indices[2] == 1) && (indices[3] == 1))
1528  base_index[1] = 1;
1529  else
1530  base_index[1] = 2;
1531 
1532  return data[base_index[0]][base_index[1]];
1533  }
1534 
1535  case 3:
1536  // each entry of the tensor can be
1537  // thought of as an entry in a
1538  // matrix that maps the rolled-out
1539  // rank-2 tensors into rolled-out
1540  // rank-2 tensors. this is the
1541  // format in which we store rank-4
1542  // tensors. determine which
1543  // position the present entry is
1544  // stored in
1545  {
1546  unsigned int base_index[2] ;
1547  if ((indices[0] == 0) && (indices[1] == 0))
1548  base_index[0] = 0;
1549  else if ((indices[0] == 1) && (indices[1] == 1))
1550  base_index[0] = 1;
1551  else if ((indices[0] == 2) && (indices[1] == 2))
1552  base_index[0] = 2;
1553  else if (((indices[0] == 0) && (indices[1] == 1)) ||
1554  ((indices[0] == 1) && (indices[1] == 0)))
1555  base_index[0] = 3;
1556  else if (((indices[0] == 0) && (indices[1] == 2)) ||
1557  ((indices[0] == 2) && (indices[1] == 0)))
1558  base_index[0] = 4;
1559  else
1560  {
1561  Assert (((indices[0] == 1) && (indices[1] == 2)) ||
1562  ((indices[0] == 2) && (indices[1] == 1)),
1563  ExcInternalError());
1564  base_index[0] = 5;
1565  }
1566 
1567  if ((indices[2] == 0) && (indices[3] == 0))
1568  base_index[1] = 0;
1569  else if ((indices[2] == 1) && (indices[3] == 1))
1570  base_index[1] = 1;
1571  else if ((indices[2] == 2) && (indices[3] == 2))
1572  base_index[1] = 2;
1573  else if (((indices[2] == 0) && (indices[3] == 1)) ||
1574  ((indices[2] == 1) && (indices[3] == 0)))
1575  base_index[1] = 3;
1576  else if (((indices[2] == 0) && (indices[3] == 2)) ||
1577  ((indices[2] == 2) && (indices[3] == 0)))
1578  base_index[1] = 4;
1579  else
1580  {
1581  Assert (((indices[2] == 1) && (indices[3] == 2)) ||
1582  ((indices[2] == 2) && (indices[3] == 1)),
1583  ExcInternalError());
1584  base_index[1] = 5;
1585  }
1586 
1587  return data[base_index[0]][base_index[1]];
1588  }
1589 
1590  default:
1591  Assert (false, ExcNotImplemented());
1592  }
1593 
1594  static Number dummy;
1595  return dummy;
1596  }
1597 
1598 } // end of namespace internal
1599 
1600 
1601 
1602 template <int rank, int dim, typename Number>
1603 inline
1604 Number &
1606 {
1607  for (unsigned int r=0; r<rank; ++r)
1608  Assert (indices[r] < dimension, ExcIndexRange (indices[r], 0, dimension));
1609  return internal::symmetric_tensor_access<dim,Number> (indices, data);
1610 }
1611 
1612 
1613 
1614 template <int rank, int dim, typename Number>
1615 inline
1616 Number
1618 (const TableIndices<rank> &indices) const
1619 {
1620  for (unsigned int r=0; r<rank; ++r)
1621  Assert (indices[r] < dimension, ExcIndexRange (indices[r], 0, dimension));
1622  return internal::symmetric_tensor_access<dim,Number> (indices, data);
1623 }
1624 
1625 
1626 
1627 template <int rank, int dim, typename Number>
1628 internal::SymmetricTensorAccessors::Accessor<rank,dim,true,rank-1,Number>
1629 SymmetricTensor<rank,dim,Number>::operator [] (const unsigned int row) const
1630 {
1631  return
1632  internal::SymmetricTensorAccessors::
1633  Accessor<rank,dim,true,rank-1,Number> (*this, TableIndices<rank> (row));
1634 }
1635 
1636 
1637 
1638 template <int rank, int dim, typename Number>
1639 internal::SymmetricTensorAccessors::Accessor<rank,dim,false,rank-1,Number>
1640 SymmetricTensor<rank,dim,Number>::operator [] (const unsigned int row)
1641 {
1642  return
1643  internal::SymmetricTensorAccessors::
1644  Accessor<rank,dim,false,rank-1,Number> (*this, TableIndices<rank> (row));
1645 }
1646 
1647 
1648 
1649 template <int rank, int dim, typename Number>
1650 inline
1651 Number
1653 {
1654  return data[component_to_unrolled_index(indices)];
1655 }
1656 
1657 
1658 
1659 template <int rank, int dim, typename Number>
1660 inline
1661 Number &
1663 {
1664  return data[component_to_unrolled_index(indices)];
1665 }
1666 
1667 
1668 
1669 template <int rank, int dim, typename Number>
1670 inline
1671 Number
1672 SymmetricTensor<rank,dim,Number>::access_raw_entry (const unsigned int index) const
1673 {
1674  AssertIndexRange (index, data.dimension);
1675  return data[index];
1676 }
1677 
1678 
1679 
1680 template <int rank, int dim, typename Number>
1681 inline
1682 Number &
1683 SymmetricTensor<rank,dim,Number>::access_raw_entry (const unsigned int index)
1684 {
1685  AssertIndexRange (index, data.dimension);
1686  return data[index];
1687 }
1688 
1689 
1690 
1691 namespace internal
1692 {
1693  template <int dim, typename Number>
1694  inline
1695  Number
1696  compute_norm (const typename SymmetricTensorAccessors::StorageType<2,dim,Number>::base_tensor_type &data)
1697  {
1698  Number return_value;
1699  switch (dim)
1700  {
1701  case 1:
1702  return_value = std::fabs(data[0]);
1703  break;
1704  case 2:
1705  return_value = std::sqrt(data[0]*data[0] + data[1]*data[1] +
1706  2*data[2]*data[2]);
1707  break;
1708  case 3:
1709  return_value = std::sqrt(data[0]*data[0] + data[1]*data[1] +
1710  data[2]*data[2] + 2*data[3]*data[3] +
1711  2*data[4]*data[4] + 2*data[5]*data[5]);
1712  break;
1713  default:
1714  return_value = Number();
1715  for (unsigned int d=0; d<dim; ++d)
1716  return_value += data[d] * data[d];
1717  for (unsigned int d=dim; d<(dim*dim+dim)/2; ++d)
1718  return_value += 2 * data[d] * data[d];
1719  return_value = std::sqrt(return_value);
1720  }
1721  return return_value;
1722  }
1723 
1724 
1725 
1726  template <int dim, typename Number>
1727  inline
1728  Number
1729  compute_norm (const typename SymmetricTensorAccessors::StorageType<4,dim,Number>::base_tensor_type &data)
1730  {
1731  Number return_value;
1732  const unsigned int n_independent_components = data.dimension;
1733 
1734  switch (dim)
1735  {
1736  case 1:
1737  return_value = std::fabs (data[0][0]);
1738  break;
1739  default:
1740  return_value = Number();
1741  for (unsigned int i=0; i<dim; ++i)
1742  for (unsigned int j=0; j<dim; ++j)
1743  return_value += data[i][j] * data[i][j];
1744  for (unsigned int i=0; i<dim; ++i)
1745  for (unsigned int j=dim; j<n_independent_components; ++j)
1746  return_value += 2 * data[i][j] * data[i][j];
1747  for (unsigned int i=dim; i<n_independent_components; ++i)
1748  for (unsigned int j=0; j<dim; ++j)
1749  return_value += 2 * data[i][j] * data[i][j];
1750  for (unsigned int i=dim; i<n_independent_components; ++i)
1751  for (unsigned int j=dim; j<n_independent_components; ++j)
1752  return_value += 4 * data[i][j] * data[i][j];
1753  return_value = std::sqrt(return_value);
1754  }
1755 
1756  return return_value;
1757  }
1758 
1759 } // end of namespace internal
1760 
1761 
1762 
1763 template <int rank, int dim, typename Number>
1764 inline
1765 Number
1767 {
1768  return internal::compute_norm<dim,Number> (data);
1769 }
1770 
1771 
1772 
1773 namespace internal
1774 {
1775  namespace SymmetricTensor
1776  {
1777  namespace
1778  {
1779  // a function to do the unrolling from a set of indices to a
1780  // scalar index into the array in which we store the elements of
1781  // a symmetric tensor
1782  //
1783  // this function is for rank-2 tensors
1784  template <int dim>
1785  inline
1786  unsigned int
1788  (const TableIndices<2> &indices)
1789  {
1790  Assert (indices[0] < dim, ExcIndexRange(indices[0], 0, dim));
1791  Assert (indices[1] < dim, ExcIndexRange(indices[1], 0, dim));
1792 
1793  switch (dim)
1794  {
1795  case 1:
1796  {
1797  return 0;
1798  }
1799 
1800  case 2:
1801  {
1802  static const unsigned int table[2][2] = {{0, 2},
1803  {2, 1}
1804  };
1805  return table[indices[0]][indices[1]];
1806  }
1807 
1808  case 3:
1809  {
1810  static const unsigned int table[3][3] = {{0, 3, 4},
1811  {3, 1, 5},
1812  {4, 5, 2}
1813  };
1814  return table[indices[0]][indices[1]];
1815  }
1816 
1817  case 4:
1818  {
1819  static const unsigned int table[4][4] = {{0, 4, 5, 6},
1820  {4, 1, 7, 8},
1821  {5, 7, 2, 9},
1822  {6, 8, 9, 3}
1823  };
1824  return table[indices[0]][indices[1]];
1825  }
1826 
1827  default:
1828  // for the remainder, manually figure out the numbering
1829  {
1830  if (indices[0] == indices[1])
1831  return indices[0];
1832 
1833  TableIndices<2> sorted_indices (indices);
1834  sorted_indices.sort ();
1835 
1836  for (unsigned int d=0, c=0; d<dim; ++d)
1837  for (unsigned int e=d+1; e<dim; ++e, ++c)
1838  if ((sorted_indices[0]==d) && (sorted_indices[1]==e))
1839  return dim+c;
1840 
1841  // should never get here:
1842  AssertThrow(false, ExcInternalError());
1843  return 0;
1844  }
1845  }
1846  }
1847 
1848  // a function to do the unrolling from a set of indices to a
1849  // scalar index into the array in which we store the elements of
1850  // a symmetric tensor
1851  //
1852  // this function is for tensors of ranks not already handled
1853  // above
1854  template <int dim, int rank>
1855  inline
1856  unsigned int
1858  (const TableIndices<rank> &indices)
1859  {
1860  (void)indices;
1861  Assert (false, ExcNotImplemented());
1863  }
1864  }
1865  }
1866 }
1867 
1868 
1869 template <int rank, int dim, typename Number>
1870 inline
1871 unsigned int
1873 (const TableIndices<rank> &indices)
1874 {
1875  return internal::SymmetricTensor::component_to_unrolled_index<dim> (indices);
1876 }
1877 
1878 
1879 
1880 namespace internal
1881 {
1882  namespace SymmetricTensor
1883  {
1884  namespace
1885  {
1886  // a function to do the inverse of the unrolling from a set of
1887  // indices to a scalar index into the array in which we store
1888  // the elements of a symmetric tensor. in other words, it goes
1889  // from the scalar index into the array to a set of indices of
1890  // the tensor
1891  //
1892  // this function is for rank-2 tensors
1893  template <int dim>
1894  inline
1897  (const unsigned int i,
1898  const int2type<2> &)
1899  {
1902  switch (dim)
1903  {
1904  case 1:
1905  {
1906  return TableIndices<2>(0,0);
1907  }
1908 
1909  case 2:
1910  {
1911  const TableIndices<2> table[3] =
1912  {
1913  TableIndices<2> (0,0),
1914  TableIndices<2> (1,1),
1915  TableIndices<2> (0,1)
1916  };
1917  return table[i];
1918  }
1919 
1920  case 3:
1921  {
1922  const TableIndices<2> table[6] =
1923  {
1924  TableIndices<2> (0,0),
1925  TableIndices<2> (1,1),
1926  TableIndices<2> (2,2),
1927  TableIndices<2> (0,1),
1928  TableIndices<2> (0,2),
1929  TableIndices<2> (1,2)
1930  };
1931  return table[i];
1932  }
1933 
1934  default:
1935  if (i<dim)
1936  return TableIndices<2> (i,i);
1937 
1938  for (unsigned int d=0, c=0; d<dim; ++d)
1939  for (unsigned int e=d+1; e<dim; ++e, ++c)
1940  if (c==i)
1941  return TableIndices<2>(d,e);
1942 
1943  // should never get here:
1944  AssertThrow(false, ExcInternalError());
1945  return TableIndices<2>(0, 0);
1946  }
1947  }
1948 
1949  // a function to do the inverse of the unrolling from a set of
1950  // indices to a scalar index into the array in which we store
1951  // the elements of a symmetric tensor. in other words, it goes
1952  // from the scalar index into the array to a set of indices of
1953  // the tensor
1954  //
1955  // this function is for tensors of a rank not already handled
1956  // above
1957  template <int dim, int rank>
1958  inline
1961  (const unsigned int i,
1962  const int2type<rank> &)
1963  {
1964  (void)i;
1967  Assert (false, ExcNotImplemented());
1968  return TableIndices<rank>();
1969  }
1970 
1971  }
1972  }
1973 }
1974 
1975 template <int rank, int dim, typename Number>
1976 inline
1979 (const unsigned int i)
1980 {
1981  return
1982  internal::SymmetricTensor::unrolled_to_component_indices<dim> (i,
1984 }
1985 
1986 
1987 
1988 template <int rank, int dim, typename Number>
1989 template <class Archive>
1990 inline
1991 void
1992 SymmetricTensor<rank,dim,Number>::serialize(Archive &ar, const unsigned int)
1993 {
1994  ar &data;
1995 }
1996 
1997 
1998 #endif // DOXYGEN
1999 
2000 /* ----------------- Non-member functions operating on tensors. ------------ */
2001 
2002 
2009 template <int rank, int dim, typename Number, typename OtherNumber>
2010 inline
2013  const Tensor<rank, dim, OtherNumber> &right)
2014 {
2015  return Tensor<rank, dim, Number>(left) + right;
2016 }
2017 
2018 
2025 template <int rank, int dim, typename Number, typename OtherNumber>
2026 inline
2030 {
2031  return left + Tensor<rank, dim, OtherNumber>(right);
2032 }
2033 
2034 
2041 template <int rank, int dim, typename Number, typename OtherNumber>
2042 inline
2045  const Tensor<rank, dim, OtherNumber> &right)
2046 {
2047  return Tensor<rank, dim, Number>(left) - right;
2048 }
2049 
2050 
2057 template <int rank, int dim, typename Number, typename OtherNumber>
2058 inline
2062 {
2063  return left - Tensor<rank, dim, OtherNumber>(right);
2064 }
2065 
2066 
2067 
2081 template <int dim, typename Number>
2082 inline
2084 {
2085  switch (dim)
2086  {
2087  case 1:
2088  return t.data[0];
2089  case 2:
2090  return (t.data[0] * t.data[1] - t.data[2]*t.data[2]);
2091  case 3:
2092  // in analogy to general tensors, but
2093  // there's something to be simplified for
2094  // the present case
2095  return ( t.data[0]*t.data[1]*t.data[2]
2096  -t.data[0]*t.data[5]*t.data[5]
2097  -t.data[1]*t.data[4]*t.data[4]
2098  -t.data[2]*t.data[3]*t.data[3]
2099  +2*t.data[3]*t.data[4]*t.data[5] );
2100  default:
2101  Assert (false, ExcNotImplemented());
2102  return 0;
2103  }
2104 }
2105 
2106 
2107 
2117 template <int dim, typename Number>
2118 inline
2120 {
2121  return determinant (t);
2122 }
2123 
2124 
2125 
2133 template <int dim, typename Number>
2135 {
2136  Number t = d.data[0];
2137  for (unsigned int i=1; i<dim; ++i)
2138  t += d.data[i];
2139  return t;
2140 }
2141 
2142 
2152 template <int dim, typename Number>
2153 inline
2155 {
2156  return trace (t);
2157 }
2158 
2159 
2167 template <typename Number>
2168 inline
2170 {
2171  return 0;
2172 }
2173 
2174 
2175 
2183 template <typename Number>
2184 inline
2186 {
2187  return t[0][0]*t[1][1] - t[0][1]*t[0][1];
2188 }
2189 
2190 
2191 
2199 template <typename Number>
2200 inline
2202 {
2203  return (t[0][0]*t[1][1] + t[1][1]*t[2][2] + t[2][2]*t[0][0]
2204  - t[0][1]*t[0][1] - t[0][2]*t[0][2] - t[1][2]*t[1][2]);
2205 }
2206 
2207 
2208 
2209 
2219 template <int rank, int dim, typename Number>
2220 inline
2223 {
2224  return t;
2225 }
2226 
2227 
2228 
2238 template <int dim, typename Number>
2239 inline
2242 {
2244 
2245  // subtract scaled trace from the diagonal
2246  const Number tr = trace(t) / dim;
2247  for (unsigned int i=0; i<dim; ++i)
2248  tmp.data[i] -= tr;
2249 
2250  return tmp;
2251 }
2252 
2253 
2254 
2262 template <int dim, typename Number>
2263 inline
2266 {
2267  // create a default constructed matrix filled with
2268  // zeros, then set the diagonal elements to one
2270  switch (dim)
2271  {
2272  case 1:
2273  tmp.data[0] = 1;
2274  break;
2275  case 2:
2276  tmp.data[0] = tmp.data[1] = 1;
2277  break;
2278  case 3:
2279  tmp.data[0] = tmp.data[1] = tmp.data[2] = 1;
2280  break;
2281  default:
2282  for (unsigned int d=0; d<dim; ++d)
2283  tmp.data[d] = 1;
2284  }
2285  return tmp;
2286 }
2287 
2288 
2289 
2298 template <int dim>
2299 inline
2302 {
2303  return unit_symmetric_tensor<dim,double>();
2304 }
2305 
2306 
2307 
2322 template <int dim, typename Number>
2323 inline
2326 {
2328 
2329  // fill the elements treating the diagonal
2330  for (unsigned int i=0; i<dim; ++i)
2331  for (unsigned int j=0; j<dim; ++j)
2332  tmp.data[i][j] = (i==j ? 1 : 0) - 1./dim;
2333 
2334  // then fill the ones that copy over the
2335  // non-diagonal elements. note that during
2336  // the double-contraction, we handle the
2337  // off-diagonal elements twice, so simply
2338  // copying requires a weight of 1/2
2339  for (unsigned int i=dim;
2340  i<internal::SymmetricTensorAccessors::StorageType<4,dim,Number>::n_rank2_components;
2341  ++i)
2342  tmp.data[i][i] = 0.5;
2343 
2344  return tmp;
2345 }
2346 
2347 
2348 
2363 template <int dim>
2364 inline
2366 deviator_tensor ()
2367 {
2368  return deviator_tensor<dim,double>();
2369 }
2370 
2371 
2372 
2395 template <int dim, typename Number>
2396 inline
2399 {
2401 
2402  // fill the elements treating the diagonal
2403  for (unsigned int i=0; i<dim; ++i)
2404  tmp.data[i][i] = 1;
2405 
2406  // then fill the ones that copy over the
2407  // non-diagonal elements. note that during
2408  // the double-contraction, we handle the
2409  // off-diagonal elements twice, so simply
2410  // copying requires a weight of 1/2
2411  for (unsigned int i=dim;
2412  i<internal::SymmetricTensorAccessors::StorageType<4,dim,Number>::n_rank2_components;
2413  ++i)
2414  tmp.data[i][i] = 0.5;
2415 
2416  return tmp;
2417 }
2418 
2419 
2420 
2442 template <int dim>
2443 inline
2445 identity_tensor ()
2446 {
2447  return identity_tensor<dim,double>();
2448 }
2449 
2450 
2451 
2465 template <int dim, typename Number>
2466 inline
2469 {
2471  switch (dim)
2472  {
2473  case 1:
2474  tmp.data[0][0] = 1./t.data[0][0];
2475  break;
2476  case 2:
2477 
2478  // inverting this tensor is a little more
2479  // complicated than necessary, since we
2480  // store the data of 't' as a 3x3 matrix
2481  // t.data, but the product between a rank-4
2482  // and a rank-2 tensor is really not the
2483  // product between this matrix and the
2484  // 3-vector of a rhs, but rather
2485  //
2486  // B.vec = t.data * mult * A.vec
2487  //
2488  // where mult is a 3x3 matrix with
2489  // entries [[1,0,0],[0,1,0],[0,0,2]] to
2490  // capture the fact that we need to add up
2491  // both the c_ij12*a_12 and the c_ij21*a_21
2492  // terms
2493  //
2494  // in addition, in this scheme, the
2495  // identity tensor has the matrix
2496  // representation mult^-1.
2497  //
2498  // the inverse of 't' therefore has the
2499  // matrix representation
2500  //
2501  // inv.data = mult^-1 * t.data^-1 * mult^-1
2502  //
2503  // in order to compute it, let's first
2504  // compute the inverse of t.data and put it
2505  // into tmp.data; at the end of the
2506  // function we then scale the last row and
2507  // column of the inverse by 1/2,
2508  // corresponding to the left and right
2509  // multiplication with mult^-1
2510  {
2511  const Number t4 = t.data[0][0]*t.data[1][1],
2512  t6 = t.data[0][0]*t.data[1][2],
2513  t8 = t.data[0][1]*t.data[1][0],
2514  t00 = t.data[0][2]*t.data[1][0],
2515  t01 = t.data[0][1]*t.data[2][0],
2516  t04 = t.data[0][2]*t.data[2][0],
2517  t07 = 1.0/(t4*t.data[2][2]-t6*t.data[2][1]-
2518  t8*t.data[2][2]+t00*t.data[2][1]+
2519  t01*t.data[1][2]-t04*t.data[1][1]);
2520  tmp.data[0][0] = (t.data[1][1]*t.data[2][2]-t.data[1][2]*t.data[2][1])*t07;
2521  tmp.data[0][1] = -(t.data[0][1]*t.data[2][2]-t.data[0][2]*t.data[2][1])*t07;
2522  tmp.data[0][2] = -(-t.data[0][1]*t.data[1][2]+t.data[0][2]*t.data[1][1])*t07;
2523  tmp.data[1][0] = -(t.data[1][0]*t.data[2][2]-t.data[1][2]*t.data[2][0])*t07;
2524  tmp.data[1][1] = (t.data[0][0]*t.data[2][2]-t04)*t07;
2525  tmp.data[1][2] = -(t6-t00)*t07;
2526  tmp.data[2][0] = -(-t.data[1][0]*t.data[2][1]+t.data[1][1]*t.data[2][0])*t07;
2527  tmp.data[2][1] = -(t.data[0][0]*t.data[2][1]-t01)*t07;
2528  tmp.data[2][2] = (t4-t8)*t07;
2529 
2530  // scale last row and column as mentioned
2531  // above
2532  tmp.data[2][0] /= 2;
2533  tmp.data[2][1] /= 2;
2534  tmp.data[0][2] /= 2;
2535  tmp.data[1][2] /= 2;
2536  tmp.data[2][2] /= 4;
2537  }
2538  break;
2539  default:
2540  Assert (false, ExcNotImplemented());
2541  }
2542  return tmp;
2543 }
2544 
2545 
2546 
2560 template <>
2562 invert (const SymmetricTensor<4,3,double> &t);
2563 // this function is implemented in the .cc file for double data types
2564 
2565 
2566 
2581 template <int dim, typename Number>
2582 inline
2586 {
2588 
2589  // fill only the elements really needed
2590  for (unsigned int i=0; i<dim; ++i)
2591  for (unsigned int j=i; j<dim; ++j)
2592  for (unsigned int k=0; k<dim; ++k)
2593  for (unsigned int l=k; l<dim; ++l)
2594  tmp[i][j][k][l] = t1[i][j] * t2[k][l];
2595 
2596  return tmp;
2597 }
2598 
2599 
2600 
2609 template <int dim,typename Number>
2610 inline
2613 {
2614  Number array[(dim*dim+dim)/2];
2615  for (unsigned int d=0; d<dim; ++d)
2616  array[d] = t[d][d];
2617  for (unsigned int d=0, c=0; d<dim; ++d)
2618  for (unsigned int e=d+1; e<dim; ++e, ++c)
2619  array[dim+c] = (t[d][e]+t[e][d])*0.5;
2620  return SymmetricTensor<2,dim,Number>(array);
2621 }
2622 
2623 
2624 
2632 template <int rank, int dim, typename Number>
2633 inline
2636  const Number factor)
2637 {
2639  tt *= factor;
2640  return tt;
2641 }
2642 
2643 
2644 
2652 template <int rank, int dim, typename Number>
2653 inline
2655 operator * (const Number factor,
2657 {
2658  // simply forward to the other operator
2659  return t*factor;
2660 }
2661 
2662 
2663 #ifndef DEAL_II_WITH_CXX11
2664 
2665 template <typename T, typename U, int rank, int dim>
2666 struct ProductType<T,SymmetricTensor<rank,dim,U> >
2667 {
2669 };
2670 
2671 template <typename T, typename U, int rank, int dim>
2672 struct ProductType<SymmetricTensor<rank,dim,T>,U>
2673 {
2675 };
2676 
2677 #endif
2678 
2679 
2680 
2706 template <int rank, int dim, typename Number, typename OtherNumber>
2707 inline
2710  const OtherNumber factor)
2711 {
2712  // form the product. we have to convert the two factors into the final
2713  // type via explicit casts because, for awkward reasons, the C++
2714  // standard committee saw it fit to not define an
2715  // operator*(float,std::complex<double>)
2716  // (as well as with switched arguments and double<->float).
2717  typedef typename ProductType<Number,OtherNumber>::type product_type;
2719  tt *= product_type(factor);
2720  return tt;
2721 }
2722 
2723 
2724 
2733 template <int rank, int dim, typename Number, typename OtherNumber>
2734 inline
2736 operator * (const Number factor,
2738 {
2739  // simply forward to the other operator with switched arguments
2740  return (t*factor);
2741 }
2742 
2743 
2744 
2750 template <int rank, int dim, typename Number>
2751 inline
2754  const Number factor)
2755 {
2757  tt /= factor;
2758  return tt;
2759 }
2760 
2761 
2762 
2769 template <int rank, int dim>
2770 inline
2773  const double factor)
2774 {
2776  tt *= factor;
2777  return tt;
2778 }
2779 
2780 
2781 
2788 template <int rank, int dim>
2789 inline
2791 operator * (const double factor,
2792  const SymmetricTensor<rank,dim> &t)
2793 {
2795  tt *= factor;
2796  return tt;
2797 }
2798 
2799 
2800 
2806 template <int rank, int dim>
2807 inline
2810  const double factor)
2811 {
2813  tt /= factor;
2814  return tt;
2815 }
2816 
2826 template <int dim, typename Number>
2827 inline
2828 Number
2831 {
2832  return (t1*t2);
2833 }
2834 
2835 
2845 template <int dim, typename Number>
2846 inline
2847 Number
2849  const Tensor<2,dim,Number> &t2)
2850 {
2851  Number s = 0;
2852  for (unsigned int i=0; i<dim; ++i)
2853  for (unsigned int j=0; j<dim; ++j)
2854  s += t1[i][j] * t2[i][j];
2855  return s;
2856 }
2857 
2858 
2868 template <int dim, typename Number>
2869 inline
2870 Number
2873 {
2874  return scalar_product(t2, t1);
2875 }
2876 
2877 
2893 template <typename Number>
2894 inline
2895 void
2897  const SymmetricTensor<4,1,Number> &t,
2898  const SymmetricTensor<2,1,Number> &s)
2899 {
2900  tmp[0][0] = t[0][0][0][0] * s[0][0];
2901 }
2902 
2903 
2904 
2920 template <typename Number>
2921 inline
2922 void
2924  const SymmetricTensor<2,1,Number> &s,
2925  const SymmetricTensor<4,1,Number> &t)
2926 {
2927  tmp[0][0] = t[0][0][0][0] * s[0][0];
2928 }
2929 
2930 
2931 
2946 template <typename Number>
2947 inline
2948 void
2950  const SymmetricTensor<4,2,Number> &t,
2951  const SymmetricTensor<2,2,Number> &s)
2952 {
2953  const unsigned int dim = 2;
2954 
2955  for (unsigned int i=0; i<dim; ++i)
2956  for (unsigned int j=i; j<dim; ++j)
2957  tmp[i][j] = t[i][j][0][0] * s[0][0] +
2958  t[i][j][1][1] * s[1][1] +
2959  2 * t[i][j][0][1] * s[0][1];
2960 }
2961 
2962 
2963 
2979 template <typename Number>
2980 inline
2981 void
2983  const SymmetricTensor<2,2,Number> &s,
2984  const SymmetricTensor<4,2,Number> &t)
2985 {
2986  const unsigned int dim = 2;
2987 
2988  for (unsigned int i=0; i<dim; ++i)
2989  for (unsigned int j=i; j<dim; ++j)
2990  tmp[i][j] = s[0][0] * t[0][0][i][j] * +
2991  s[1][1] * t[1][1][i][j] +
2992  2 * s[0][1] * t[0][1][i][j];
2993 }
2994 
2995 
2996 
3012 template <typename Number>
3013 inline
3014 void
3016  const SymmetricTensor<4,3,Number> &t,
3017  const SymmetricTensor<2,3,Number> &s)
3018 {
3019  const unsigned int dim = 3;
3020 
3021  for (unsigned int i=0; i<dim; ++i)
3022  for (unsigned int j=i; j<dim; ++j)
3023  tmp[i][j] = t[i][j][0][0] * s[0][0] +
3024  t[i][j][1][1] * s[1][1] +
3025  t[i][j][2][2] * s[2][2] +
3026  2 * t[i][j][0][1] * s[0][1] +
3027  2 * t[i][j][0][2] * s[0][2] +
3028  2 * t[i][j][1][2] * s[1][2];
3029 }
3030 
3031 
3032 
3048 template <typename Number>
3049 inline
3050 void
3052  const SymmetricTensor<2,3,Number> &s,
3053  const SymmetricTensor<4,3,Number> &t)
3054 {
3055  const unsigned int dim = 3;
3056 
3057  for (unsigned int i=0; i<dim; ++i)
3058  for (unsigned int j=i; j<dim; ++j)
3059  tmp[i][j] = s[0][0] * t[0][0][i][j] +
3060  s[1][1] * t[1][1][i][j] +
3061  s[2][2] * t[2][2][i][j] +
3062  2 * s[0][1] * t[0][1][i][j] +
3063  2 * s[0][2] * t[0][2][i][j] +
3064  2 * s[1][2] * t[1][2][i][j];
3065 }
3066 
3067 
3068 
3084 template <int dim, typename Number>
3087  const Tensor<1,dim,Number> &src2)
3088 {
3089  Tensor<1,dim,Number> dest;
3090  for (unsigned int i=0; i<dim; ++i)
3091  for (unsigned int j=0; j<dim; ++j)
3092  dest[i] += src1[i][j] * src2[j];
3093  return dest;
3094 }
3095 
3096 
3106 template <int dim, typename Number>
3107 inline
3108 std::ostream &operator << (std::ostream &out,
3110 {
3111  //make out lives a bit simpler by outputing
3112  //the tensor through the operator for the
3113  //general Tensor class
3115 
3116  for (unsigned int i=0; i<dim; ++i)
3117  for (unsigned int j=0; j<dim; ++j)
3118  tt[i][j] = t[i][j];
3119 
3120  return out << tt;
3121 }
3122 
3123 
3124 
3134 template <int dim, typename Number>
3135 inline
3136 std::ostream &operator << (std::ostream &out,
3138 {
3139  //make out lives a bit simpler by outputing
3140  //the tensor through the operator for the
3141  //general Tensor class
3143 
3144  for (unsigned int i=0; i<dim; ++i)
3145  for (unsigned int j=0; j<dim; ++j)
3146  for (unsigned int k=0; k<dim; ++k)
3147  for (unsigned int l=0; l<dim; ++l)
3148  tt[i][j][k][l] = t[i][j][k][l];
3149 
3150  return out << tt;
3151 }
3152 
3153 
3154 DEAL_II_NAMESPACE_CLOSE
3155 
3156 #endif
friend SymmetricTensor< 4, dim2, Number2 > identity_tensor()
static const unsigned int invalid_unsigned_int
Definition: types.h:164
Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator+(const SymmetricTensor< rank, dim, Number > &left, const Tensor< rank, dim, OtherNumber > &right)
void double_contract(SymmetricTensor< 2, 2, Number > &tmp, const SymmetricTensor< 4, 2, Number > &t, const SymmetricTensor< 2, 2, Number > &s)
SymmetricTensor operator-() const
Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator+(const Tensor< rank, dim, Number > &left, const SymmetricTensor< rank, dim, OtherNumber > &right)
SymmetricTensor< rank, dim, Number > operator/(const SymmetricTensor< rank, dim, Number > &t, const Number factor)
static const unsigned int n_independent_components
SymmetricTensor< 2, dim, Number > symmetrize(const Tensor< 2, dim, Number > &t)
::ExceptionBase & ExcMessage(std::string arg1)
void double_contract(SymmetricTensor< 2, 3, Number > &tmp, const SymmetricTensor< 2, 3, Number > &s, const SymmetricTensor< 4, 3, Number > &t)
void double_contract(SymmetricTensor< 2, 1, Number > &tmp, const SymmetricTensor< 4, 1, Number > &t, const SymmetricTensor< 2, 1, Number > &s)
#define AssertIndexRange(index, range)
Definition: exceptions.h:1081
static TableIndices< rank > unrolled_to_component_indices(const unsigned int i)
base_tensor_type data
void double_contract(SymmetricTensor< 2, 1, Number > &tmp, const SymmetricTensor< 2, 1, Number > &s, const SymmetricTensor< 4, 1, Number > &t)
TableIndices< 2 > merge(const TableIndices< 2 > &previous_indices, const unsigned int new_index, const unsigned int position)
#define AssertThrow(cond, exc)
Definition: exceptions.h:358
void serialize(Archive &ar, const unsigned int version)
static unsigned int component_to_unrolled_index(const TableIndices< rank > &indices)
internal::SymmetricTensorAccessors::double_contraction_result< rank, 2, dim, Number >::type operator*(const SymmetricTensor< 2, dim, Number > &s) const
void double_contract(SymmetricTensor< 2, 2, Number > &tmp, const SymmetricTensor< 2, 2, Number > &s, const SymmetricTensor< 4, 2, Number > &t)
static std::size_t memory_consumption()
Number second_invariant(const SymmetricTensor< 2, 2, Number > &t)
Number first_invariant(const SymmetricTensor< 2, dim, Number > &t)
friend Number2 trace(const SymmetricTensor< 2, dim2, Number2 > &d)
#define Assert(cond, exc)
Definition: exceptions.h:294
base_tensor_descriptor::base_tensor_type base_tensor_type
SymmetricTensor< rank, dim, Number > transpose(const SymmetricTensor< rank, dim, Number > &t)
Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator-(const SymmetricTensor< rank, dim, Number > &left, const Tensor< rank, dim, OtherNumber > &right)
SymmetricTensor< 2, dim, Number > deviator(const SymmetricTensor< 2, dim, Number > &t)
Number trace(const SymmetricTensor< 2, dim, Number > &d)
Sacado::Fad::DFad< T > scalar_product(const SymmetricTensor< 2, dim, Sacado::Fad::DFad< T > > &t1, const Tensor< 2, dim, Number > &t2)
internal::SymmetricTensorAccessors::StorageType< rank, dim, Number > base_tensor_descriptor
friend SymmetricTensor< 2, dim2, Number2 > unit_symmetric_tensor()
Tensor< rank, dim, typename ProductType< Number, OtherNumber >::type > operator-(const Tensor< rank, dim, Number > &left, const SymmetricTensor< rank, dim, OtherNumber > &right)
SymmetricTensor< 4, dim, Number > outer_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
Number scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
std::ostream & operator<<(std::ostream &out, const SymmetricTensor< 2, dim, Number > &t)
Number access_raw_entry(const unsigned int unrolled_index) const
SymmetricTensor< rank, dim, Number > sum(const SymmetricTensor< rank, dim, Number > &local, const MPI_Comm &mpi_communicator)
Definition: mpi.h:672
void double_contract(SymmetricTensor< 2, 3, Number > &tmp, const SymmetricTensor< 4, 3, Number > &t, const SymmetricTensor< 2, 3, Number > &s)
Number scalar_product(const SymmetricTensor< 2, dim, Number > &t1, const Tensor< 2, dim, Number > &t2)
Number determinant(const SymmetricTensor< 2, dim, Number > &t)
internal::SymmetricTensorAccessors::Accessor< rank, dim, true, rank-1, Number > operator[](const unsigned int row) const
Definition: mpi.h:48
SymmetricTensor & operator/=(const Number factor)
SymmetricTensor operator+(const SymmetricTensor &s) const
Number & operator()(const TableIndices< rank > &indices)
Tensor< 1, n_independent_components, Number > base_tensor_type
SymmetricTensor< 4, dim, Number > invert(const SymmetricTensor< 4, dim, Number > &t)
SymmetricTensor & operator*=(const Number factor)
Number second_invariant(const SymmetricTensor< 2, 3, Number > &t)
friend SymmetricTensor< 4, dim2, Number2 > deviator_tensor()
Number scalar_product(const Tensor< 2, dim, Number > &t1, const SymmetricTensor< 2, dim, Number > &t2)
Number norm() const
double third_invariant(const SymmetricTensor< 2, dim, Number > &t)
Number second_invariant(const SymmetricTensor< 2, 1, Number > &)
SymmetricTensor & operator=(const SymmetricTensor &)