namespace ewalena
0.2.15
ewalena is not an acronym
|
00001 // ------------------------------------------------------------------- 00002 // @author Toby D. Young 00003 // @version $Id: tensor.h 999 2012-11-28 17:36:29Z oneliefleft $ 00004 // 00005 // Copyright 2012 namespace ewalena authors. All rights reserved. 00006 // 00007 // Redistribution and use in source and binary forms, with or without 00008 // modification, are permitted provided that the following conditions 00009 // are met: 00010 // 00011 // 1. Redistributions of source code must retain the above copyright 00012 // notice, this list of conditions and the following disclaimer. 00013 // 00014 // 2. Redistributions in binary form must reproduce the above 00015 // copyright notice, this list of conditions and the following 00016 // disclaimer in the documentation and/or other materials provided 00017 // with the distribution. 00018 // 00019 // THIS SOFTWARE IS PROVIDED BY THE NAMEPSACE EWALENA AUTHORS ``AS 00020 // IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00021 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00022 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00023 // NAMESPACE EWALENA AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 00024 // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00025 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00026 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00027 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 00028 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00029 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 00030 // OF THE POSSIBILITY OF SUCH DAMAGE. 00031 // 00032 // The views and conclusions contained in the software and 00033 // documentation are those of the authors and should not be 00034 // interpreted as representing official policies, either expressed or 00035 // implied, of the namespace ewalena authors. 00036 // ------------------------------------------------------------------- 00037 00038 #include <cassert> 00039 #include <cstdarg> 00040 #include <cstdlib> 00041 #include <cstring> 00042 #include <cmath> 00043 #include <vector> 00044 #include <iostream> 00045 00046 #ifndef __ewalena_tensor_h 00047 #define __ewalena_tensor_h 00048 00049 #ifdef EWALENA_HAVE_CONFIG_H 00050 #include <ewalena/base/config.h> 00051 #endif 00052 00053 #include <ewalena/base/utilities.h> 00054 00055 #ifdef EWALENA_HAVE_DEAL_II 00056 #include <deal.II/base/tensor.h> 00057 #endif 00058 00059 namespace ewalena 00060 { 00061 00068 template <int dim, int rank, typename ValueType = double> 00069 class Tensor 00070 { 00071 00072 public: 00073 00077 Tensor (const bool zero = true); 00078 00082 ~Tensor (); 00083 00088 Tensor (const Tensor &T); 00089 00094 ValueType& operator () (const unsigned int index, ...); 00095 00100 const ValueType& operator () (const unsigned int index, ...) const; 00101 00105 unsigned int n_components () const; 00106 00110 void reinit (); 00111 00116 void clone (const Tensor<dim, rank, ValueType> &T); 00117 00123 void invert (const Tensor<dim, rank, ValueType> &T); 00124 00128 void sadd (const ValueType &a, 00129 const Tensor<dim, rank, ValueType> &T_a); 00130 00135 void sadd (const ValueType &a, 00136 const Tensor<dim, rank, ValueType> &T_a, 00137 const ValueType &b, 00138 const Tensor<dim, rank, ValueType> &T_b); 00139 00144 void sadd (const ValueType &a, 00145 const Tensor<dim, rank, ValueType> &T_a, 00146 const ValueType &b, 00147 const Tensor<dim, rank, ValueType> &T_b, 00148 const ValueType &c, 00149 const Tensor<dim, rank, ValueType> &T_c); 00150 00155 void sadd (const std::vector<ValueType> &a, 00156 const std::vector<Tensor<dim, rank, ValueType> > &T_a); 00157 00162 Tensor<dim, rank, ValueType> operator + (const Tensor<dim, rank, ValueType> &T); 00163 00168 Tensor<dim, rank, ValueType> operator - (const Tensor<dim, rank, ValueType> &T); 00169 00174 void operator += (const Tensor<dim, rank, ValueType> &T); 00175 00180 void operator -= (const Tensor<dim, rank, ValueType> &T); 00181 00186 void operator *= (const ValueType &scalar); 00187 00192 void operator /= (const ValueType &scalar); 00193 00198 bool operator == (const Tensor<dim, rank, ValueType> &T) const; 00199 00203 bool is_symmetric () const; 00204 00209 std::pair<unsigned int, unsigned int> voight_components () const; 00210 00214 friend std::ostream& operator << (std::ostream &output, 00215 const Tensor<dim, rank, ValueType> &T) 00216 { 00217 for (unsigned int i=0; i<T.__n_components; ++i) 00218 00219 /* Try to pretty print */ 00220 (T.data[i]<(ValueType) 0) 00221 ? 00222 output << T.data[i] << " " 00223 : 00224 output << " " 00225 << T.data[i] << " "; 00226 00227 return output; 00228 } 00229 00234 inline 00235 const 00236 ValueType* operator* () const 00237 { 00238 return (*this).data; 00239 } 00240 00245 inline 00246 ValueType* operator* () 00247 { 00248 return (*this).data; 00249 } 00250 00251 protected: 00252 00258 unsigned int __n_components; 00259 00263 int __dim; 00264 00268 int __rank; 00269 00270 private: 00271 00276 ValueType *data; 00277 00278 }; /* Tensor */ 00279 00280 /*-------------- Inline and Other Functions -----------------------*/ 00281 00282 template <int dim, int rank, typename ValueType> 00283 inline 00284 ValueType& 00285 Tensor<dim, rank, ValueType>::operator () (const unsigned int index, ...) 00286 { 00287 /* Assert this object is initialised. */ 00288 assert (__n_components != 0); 00289 assert (index < dim); 00290 00291 /* Indices imply rank > zero. */ 00292 unsigned int decimal = index; 00293 00294 /* Initialise value list. */ 00295 va_list index_list; 00296 va_start (index_list, index); 00297 00298 /* Count from one, as is done in base conversions, and to 00299 prevent a compiler warning: comparison of unsigned expression 00300 < 0 is always false. */ 00301 for (unsigned int i=1; i<rank; ++i) 00302 { 00303 00304 /* Read index from list and convert base_dim to base_10. */ 00305 unsigned int base_dim = va_arg (index_list, unsigned int); 00306 decimal += static_cast<unsigned int> (Math::pow (dim, i) * base_dim); 00307 00308 assert (base_dim < dim); 00309 } 00310 00311 /* Finalise value list. */ 00312 va_end (index_list); 00313 00314 /* Check that this index is in bounds. */ 00315 assert (decimal < __n_components); 00316 return data[decimal]; 00317 } 00318 00319 /* This operator works in exactly the same way as the read-write 00320 operator above. Perhaps there is a way to simply call the above 00321 routine instead of duplicating that code? */ 00322 template <int dim, int rank, typename ValueType> 00323 inline 00324 const ValueType& 00325 Tensor<dim, rank, ValueType>::operator () (const unsigned int index, ...) const 00326 { 00327 assert (__n_components != 0); 00328 assert (index < dim); 00329 00330 unsigned int decimal = index; 00331 00332 va_list index_list; 00333 va_start (index_list, index); 00334 for (unsigned int i=1; i<rank; ++i) 00335 { 00336 unsigned int base_dim = va_arg (index_list, unsigned int); 00337 decimal += static_cast<unsigned int> (Math::pow (dim, i) * base_dim); 00338 00339 assert (base_dim < dim); 00340 } 00341 va_end (index_list); 00342 00343 assert (decimal < __n_components); 00344 return data[decimal]; 00345 } 00346 00347 template <int dim, int rank, typename ValueType> 00348 inline 00349 unsigned int 00350 Tensor<dim, rank, ValueType>::n_components () const 00351 { 00352 return __n_components; 00353 } 00354 00355 template <int dim, int rank, typename ValueType> 00356 inline 00357 Tensor<dim, rank, ValueType> 00358 Tensor<dim, rank, ValueType>::operator + (const Tensor<dim, rank, ValueType> &T) 00359 { 00360 assert (__n_components != 0); 00361 assert (T.__n_components == __n_components); 00362 00363 Tensor<dim, rank, ValueType> tensor; 00364 tensor.reinit (); 00365 00366 for (unsigned int i=0; i<__n_components; ++i) 00367 tensor.data[i] = data[i] + T.data[i]; 00368 00369 return tensor; 00370 } 00371 00372 template <int dim, int rank, typename ValueType> 00373 inline 00374 Tensor<dim, rank, ValueType> 00375 Tensor<dim, rank, ValueType>::operator - (const Tensor<dim, rank, ValueType> &T) 00376 { 00377 assert (__n_components != 0); 00378 assert (T.__n_components == __n_components); 00379 00380 Tensor<dim, rank, ValueType> tensor; 00381 tensor.reinit (); 00382 00383 for (unsigned int i=0; i<__n_components; ++i) 00384 tensor.data[i] = data[i] - T.data[i]; 00385 00386 return tensor; 00387 } 00388 00389 template <int dim, int rank, typename ValueType> 00390 inline 00391 void 00392 Tensor<dim, rank, ValueType>::operator += (const Tensor<dim, rank, ValueType> &T) 00393 { 00394 assert (__n_components != 0); 00395 assert (T.__n_components == __n_components); 00396 00397 for (unsigned int i=0; i<__n_components; ++i) 00398 data[i] += T.data[i]; 00399 } 00400 00401 template <int dim, int rank, typename ValueType> 00402 inline 00403 void 00404 Tensor<dim, rank, ValueType>::operator -= (const Tensor<dim, rank, ValueType> &T) 00405 { 00406 assert (__n_components != 0); 00407 assert (T.__n_components == __n_components); 00408 00409 for (unsigned int i=0; i<__n_components; ++i) 00410 data[i] -= T.data[i]; 00411 } 00412 00413 template <int dim, int rank, typename ValueType> 00414 inline 00415 void 00416 Tensor<dim, rank, ValueType>::operator *= (const ValueType &scalar) 00417 { 00418 assert (__n_components != 0); 00419 00420 for (unsigned int i=0; i<__n_components; ++i) 00421 data[i] *= scalar; 00422 } 00423 00424 template <int dim, int rank, typename ValueType> 00425 inline 00426 void 00427 Tensor<dim, rank, ValueType>::operator /= (const ValueType &scalar) 00428 { 00429 assert (__n_components != 0); 00430 00431 for (unsigned int i=0; i<__n_components; ++i) 00432 data[i] /= scalar; 00433 } 00434 00435 template <int dim, int rank, typename ValueType> 00436 inline 00437 bool 00438 Tensor<dim, rank, ValueType>::operator == (const Tensor<dim, rank, ValueType> &T) const 00439 { 00440 assert (T.__n_components == __n_components); 00441 00442 return static_cast<bool> (!std::memcmp (this->data, T.data, sizeof(ValueType)*__n_components)); 00443 } 00444 00445 template <int dim, int rank, typename ValueType> 00446 inline 00447 void 00448 Tensor<dim, rank, ValueType>::sadd (const ValueType &a, 00449 const Tensor<dim, rank, ValueType> &T_a) 00450 { 00451 /* Check this tensor is fo non-zero size and also check the 00452 input tensors are also of the same size as that. */ 00453 assert (__n_components != 0); 00454 assert (T_a.__n_components == __n_components); 00455 00456 /* Scale add these tensors thus: */ 00457 for (unsigned int i=0; i<n_components (); ++i) 00458 this->data[i] += a*T_a.data[i]; 00459 } 00460 00461 template <int dim, int rank, typename ValueType> 00462 inline 00463 void 00464 Tensor<dim, rank, ValueType>::sadd (const ValueType &a, 00465 const Tensor<dim, rank, ValueType> &T_a, 00466 const ValueType &b, 00467 const Tensor<dim, rank, ValueType> &T_b) 00468 { 00469 /* Same as above but for two tensors. */ 00470 assert (__n_components != 0); 00471 assert (T_a.__n_components == __n_components); 00472 assert (T_b.__n_components == __n_components); 00473 00474 for (unsigned int i=0; i<n_components (); ++i) 00475 this->data[i] += a*T_a.data[i] + b*T_b.data[i]; 00476 } 00477 00478 template <int dim, int rank, typename ValueType> 00479 inline 00480 void 00481 Tensor<dim, rank, ValueType>::sadd (const ValueType &a, 00482 const Tensor<dim, rank, ValueType> &T_a, 00483 const ValueType &b, 00484 const Tensor<dim, rank, ValueType> &T_b, 00485 const ValueType &c, 00486 const Tensor<dim, rank, ValueType> &T_c) 00487 { 00488 /* Same as above but for two tensors. */ 00489 assert (__n_components != 0); 00490 assert (T_a.__n_components == __n_components); 00491 assert (T_b.__n_components == __n_components); 00492 assert (T_c.__n_components == __n_components); 00493 00494 for (unsigned int i=0; i<n_components (); ++i) 00495 this->data[i] += a*T_a.data[i] + b*T_b.data[i] + c*T_c.data[i]; 00496 } 00497 00498 template <int dim, int rank, typename ValueType> 00499 inline 00500 void 00501 Tensor<dim, rank, ValueType>::sadd (const std::vector<ValueType> &a, 00502 const std::vector<Tensor<dim, rank, ValueType> > &T_a) 00503 { 00504 /* Same as above but for a std::vector of tensors. */ 00505 assert (__n_components != 0); 00506 00507 /* Insist that the number of constants and the number of tensors 00508 to scale-add are of the same size. */ 00509 assert (T_a.size () == a.size ()); 00510 00511 for (unsigned int i=0; i<a.size (); ++i) 00512 { 00513 assert (__n_components != 0); 00514 assert (T_a[i].__n_components == __n_components); 00515 00516 /* Iteratively call the single scale-add (above). */ 00517 this->sadd (a[i], T_a[i]); 00518 } 00519 } 00520 00521 /*-------------- Rank 2 --------------------------------------------*/ 00522 00523 /* This routine is a definiative plagarism from the class 00524 Matrix<ValueType>. Thus, if anything goes wrong here, it will 00525 probably need to be reported there too. */ 00526 template <int dim, int rank, typename ValueType> 00527 inline 00528 void 00529 Tensor<dim, rank, ValueType>::invert (const Tensor<dim, rank, ValueType> &T) 00530 { 00531 /* This should always be true */ 00532 assert (dim < 4); 00533 assert (rank == 2); 00534 00535 assert (T.data); 00536 assert ((*this).data); 00537 00538 switch (dim) 00539 { 00540 case 0: 00541 { 00542 /* Undefined operation. */ 00543 assert (false); 00544 } 00545 00546 case 1: 00547 { 00548 assert (T(0,0)!=ValueType (0)); 00549 (*this)(0,0) = ValueType (1) / T(0,0); 00550 break; 00551 } 00552 00553 case 2: 00554 { 00555 const ValueType determinant = T(0,0)*T(1,1) - T(0,1)*T(1,0); 00556 assert (determinant!=ValueType (0)); 00557 00558 (*this)(0,0) = T(1,1) / determinant; 00559 (*this)(0,1) = -T(0,1) / determinant; 00560 (*this)(1,0) = -T(1,0) / determinant; 00561 (*this)(1,1) = T(0,0) / determinant; 00562 00563 break; 00564 } 00565 00566 case 3: 00567 { 00568 const ValueType determinant 00569 = T(0,0)*(T(2,2)*T(1,1) - T(2,1)*T(1,2)) 00570 - T(1,0)*(T(2,2)*T(0,1) - T(2,1)*T(0,2)) 00571 + T(2,0)*(T(1,2)*T(0,1) - T(1,1)*T(0,2)); 00572 assert (determinant!=ValueType (0)); 00573 00574 (*this)(0,0) = (T(2,2)*T(1,1) - T(2,1)*T(1,2)) / determinant; 00575 (*this)(0,1) = - (T(2,2)*T(0,1) - T(2,1)*T(0,2)) / determinant; 00576 (*this)(0,2) = (T(1,2)*T(0,1) - T(1,1)*T(0,2)) / determinant; 00577 00578 (*this)(1,0) = - (T(2,2)*T(1,0) - T(2,0)*T(1,2)) / determinant; 00579 (*this)(1,1) = (T(2,2)*T(0,0) - T(2,0)*T(0,2)) / determinant; 00580 (*this)(1,2) = - (T(1,2)*T(0,0) - T(1,0)*T(0,2)) / determinant; 00581 00582 (*this)(2,0) = (T(2,1)*T(1,0) - T(2,0)*T(1,1)) / determinant; 00583 (*this)(2,1) = - (T(2,1)*T(0,0) - T(2,0)*T(0,1)) / determinant; 00584 (*this)(2,2) = (T(1,1)*T(0,0) - T(1,0)*T(0,1)) / determinant; 00585 00586 break; 00587 00588 } 00589 00590 /* This is not likely to work well for big or even medium 00591 sized matrices - so don't do it. */ 00592 default: 00593 assert (false); 00594 } 00595 00596 } 00597 00598 /*-------------- Rank 2 --------------------------------------------*/ 00599 00604 template <int dim, typename ValueType> 00605 inline 00606 Tensor<dim, 2, ValueType> contract (const Tensor<dim, 2, ValueType> &T_a, 00607 const Tensor<dim, 4, ValueType> &T_b) 00608 { 00609 Tensor<dim, 2, ValueType> tensor; 00610 00611 for (unsigned int i=0; i<dim; ++i) 00612 for (unsigned int j=0; j<dim; ++j) 00613 for (unsigned int k=0; k<dim; ++k) 00614 for (unsigned int l=0; l<dim; ++l) 00615 tensor(k,l) += T_a(i,j)*T_b(i,j,k,l); 00616 00617 return tensor; 00618 } 00619 00624 template <int dim, typename ValueType> 00625 inline 00626 Tensor<dim, 2, ValueType> contract (const Tensor<dim, 4, ValueType> &T_a, 00627 const Tensor<dim, 2, ValueType> &T_b) 00628 { 00629 Tensor<dim, 2, ValueType> tensor; 00630 00631 for (unsigned int i=0; i<dim; ++i) 00632 for (unsigned int j=0; j<dim; ++j) 00633 for (unsigned int k=0; k<dim; ++k) 00634 for (unsigned int l=0; l<dim; ++l) 00635 tensor(i,j) += T_a(i,j,k,l)*T_b(k,l); 00636 00637 return tensor; 00638 } 00639 00640 /*-------------- Rank 1 --------------------------------------------*/ 00641 00646 template <int dim, typename ValueType> 00647 inline 00648 Tensor<dim, 1, ValueType> contract (const Tensor<dim, 3, ValueType> &T_a, 00649 const Tensor<dim, 2, ValueType> &T_b) 00650 { 00651 Tensor<dim, 1, ValueType> tensor; 00652 00653 for (unsigned int i=0; i<dim; ++i) 00654 for (unsigned int j=0; j<dim; ++j) 00655 for (unsigned int k=0; k<dim; ++k) 00656 tensor(i) += T_a(i,j,k)*T_b(j,k); 00657 00658 return tensor; 00659 } 00660 00661 /*-------------- Scalar --------------------------------------------*/ 00662 00663 00664 } /* namespace ewalena */ 00665 00666 #endif /* __ewalena_tensor_h */ 00667