|
Intrepid
|
00001 // @HEADER 00002 // ************************************************************************ 00003 // 00004 // Intrepid Package 00005 // Copyright (2007) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions: Alejandro Mota (amota@sandia.gov) 00038 // 00039 // ************************************************************************ 00040 // @HEADER 00041 00042 #if !defined(Intrepid_MiniTensor_Tensor_i_h) 00043 #define Intrepid_MiniTensor_Tensor_i_h 00044 00045 namespace Intrepid { 00046 00047 // 00048 // Constructor that initializes to NaNs 00049 // 00050 template<typename T, Index N> 00051 inline 00052 Tensor<T, N>::Tensor() : 00053 TensorBase<T, Store>::TensorBase() 00054 { 00055 return; 00056 } 00057 00058 template<typename T, Index N> 00059 inline 00060 Tensor<T, N>::Tensor(Index const dimension) : 00061 TensorBase<T, Store>::TensorBase(dimension, ORDER) 00062 { 00063 return; 00064 } 00065 00069 template<typename T, Index N> 00070 inline 00071 Tensor<T, N>::Tensor(ComponentValue const value) : 00072 TensorBase<T, Store>::TensorBase(N, ORDER, value) 00073 { 00074 return; 00075 } 00076 00077 template<typename T, Index N> 00078 inline 00079 Tensor<T, N>::Tensor(Index const dimension, ComponentValue const value) : 00080 TensorBase<T, Store>::TensorBase(dimension, ORDER, value) 00081 { 00082 return; 00083 } 00084 00085 // 00086 // Create tensor from array 00087 // 00088 template<typename T, Index N> 00089 inline 00090 Tensor<T, N>::Tensor(T const * data_ptr) : 00091 TensorBase<T, Store>::TensorBase(N, ORDER, data_ptr) 00092 { 00093 return; 00094 } 00095 00096 template<typename T, Index N> 00097 inline 00098 Tensor<T, N>::Tensor(Index const dimension, T const * data_ptr) : 00099 TensorBase<T, Store>::TensorBase(dimension, ORDER, data_ptr) 00100 { 00101 return; 00102 } 00103 00104 // 00105 // Copy constructor 00106 // 00107 template<typename T, Index N> 00108 inline 00109 Tensor<T, N>::Tensor(Tensor<T, N> const & A) : 00110 TensorBase<T, Store>::TensorBase(A) 00111 { 00112 return; 00113 } 00114 00115 // 00116 // Create tensor specifying components 00117 // \param s00, s01, ... components in the R^2 canonical basis 00118 // 00119 template<typename T, Index N> 00120 inline 00121 Tensor<T, N>::Tensor( 00122 T const & s00, T const & s01, 00123 T const & s10, T const & s11) 00124 { 00125 Tensor<T, N> & 00126 self = (*this); 00127 00128 self.set_dimension(2); 00129 00130 self[0] = s00; 00131 self[1] = s01; 00132 00133 self[2] = s10; 00134 self[3] = s11; 00135 00136 return; 00137 } 00138 00139 // 00140 // Create tensor specifying components 00141 // \param s00, s01, ... components in the R^3 canonical basis 00142 // 00143 template<typename T, Index N> 00144 inline 00145 Tensor<T, N>::Tensor( 00146 T const & s00, T const & s01, T const & s02, 00147 T const & s10, T const & s11, T const & s12, 00148 T const & s20, T const & s21, T const & s22) 00149 { 00150 Tensor<T, N> & 00151 self = (*this); 00152 00153 self.set_dimension(3); 00154 00155 self[0] = s00; 00156 self[1] = s01; 00157 self[2] = s02; 00158 00159 self[3] = s10; 00160 self[4] = s11; 00161 self[5] = s12; 00162 00163 self[6] = s20; 00164 self[7] = s21; 00165 self[8] = s22; 00166 00167 return; 00168 } 00169 00170 // 00171 // Create tensor from array with component order 00172 // 00173 template<typename T, Index N> 00174 inline 00175 Tensor<T, N>::Tensor(T const * data_ptr, ComponentOrder const component_order) 00176 { 00177 assert(data_ptr != NULL); 00178 00179 fill(data_ptr, component_order); 00180 00181 return; 00182 } 00183 00184 template<typename T, Index N> 00185 inline 00186 Tensor<T, N>::Tensor( 00187 Index const dimension, 00188 T const * data_ptr, 00189 ComponentOrder const component_order) 00190 { 00191 assert(data_ptr != NULL); 00192 00193 Tensor<T, N> & 00194 self = (*this); 00195 00196 self.set_dimension(dimension); 00197 00198 fill(data_ptr, component_order); 00199 00200 return; 00201 } 00202 00203 // 00204 // 2nd-order tensor from 4th-order tensor 00205 // 00206 template<typename T, Index N> 00207 inline 00208 Tensor<T, N>::Tensor(Tensor4<T, dimension_sqrt<N>::value> const & A) 00209 { 00210 Index const 00211 dimension_4th = A.get_dimension(); 00212 00213 Index const 00214 dimension_2nd = dimension_4th * dimension_4th; 00215 00216 Tensor<T, N> & 00217 self = (*this); 00218 00219 self.set_dimension(dimension_2nd); 00220 00221 Index const 00222 number_components = dimension_2nd * dimension_2nd; 00223 00224 for (Index i = 0; i < number_components; ++i) { 00225 self[i] = A[i]; 00226 } 00227 00228 return; 00229 } 00230 00231 // 00232 // Simple destructor 00233 // 00234 template<typename T, Index N> 00235 inline 00236 Tensor<T, N>::~Tensor() 00237 { 00238 return; 00239 } 00240 00241 // 00242 // Get dimension 00243 // 00244 template<typename T, Index N> 00245 inline 00246 Index 00247 Tensor<T, N>::get_dimension() const 00248 { 00249 return IS_DYNAMIC == true ? TensorBase<T, Store>::get_dimension() : N; 00250 } 00251 00252 // 00253 // Set dimension 00254 // 00255 template<typename T, Index N> 00256 inline 00257 void 00258 Tensor<T, N>::set_dimension(Index const dimension) 00259 { 00260 if (IS_DYNAMIC == true) { 00261 TensorBase<T, Store>::set_dimension(dimension, ORDER); 00262 } 00263 else { 00264 assert(dimension == N); 00265 } 00266 00267 return; 00268 } 00269 00270 // 00271 // Indexing for constant tensor 00272 // 00273 template<typename T, Index N> 00274 inline 00275 T const & 00276 Tensor<T, N>::operator()(Index const i, Index const j) const 00277 { 00278 Tensor<T, N> const & 00279 self = (*this); 00280 00281 Index const 00282 dimension = self.get_dimension(); 00283 00284 return self[i * dimension + j]; 00285 } 00286 00287 // 00288 //Tensor indexing 00289 // 00290 template<typename T, Index N> 00291 inline 00292 T & 00293 Tensor<T, N>::operator()(Index const i, Index const j) 00294 { 00295 Tensor<T, N> & 00296 self = (*this); 00297 00298 Index const 00299 dimension = self.get_dimension(); 00300 00301 return self[i * dimension + j]; 00302 } 00303 00304 // 00305 // Fill components with value specification 00306 // 00307 template<typename T, Index N> 00308 inline 00309 void 00310 Tensor<T, N>::fill(ComponentValue const value) 00311 { 00312 TensorBase<T, Store>::fill(value); 00313 return; 00314 } 00315 00316 // 00317 // Fill components with value as parameter 00318 // 00319 template<typename T, Index N> 00320 inline 00321 void 00322 Tensor<T, N>::fill(T const & s) 00323 { 00324 TensorBase<T, Store>::fill(s); 00325 return; 00326 } 00327 00328 // 00329 // Fill components from array defined by pointer. 00330 // 00331 template<typename T, Index N> 00332 inline 00333 void 00334 Tensor<T, N>::fill(T const * data_ptr) 00335 { 00336 TensorBase<T, Store>::fill(data_ptr); 00337 return; 00338 } 00339 00340 // 00341 // Fill components from array defined by pointer. 00342 // 00343 template<typename T, Index N> 00344 inline 00345 void 00346 Tensor<T, N>::fill(T const * data_ptr, ComponentOrder const component_order) 00347 { 00348 assert(data_ptr != NULL); 00349 00350 Tensor<T, N> & 00351 self = (*this); 00352 00353 Index const 00354 dimension = self.get_dimension(); 00355 00356 switch (dimension) { 00357 00358 default: 00359 TensorBase<T, Store>::fill(data_ptr); 00360 break; 00361 00362 case 3: 00363 00364 switch (component_order) { 00365 00366 case CANONICAL: 00367 TensorBase<T, Store>::fill(data_ptr); 00368 break; 00369 00370 case SIERRA_FULL: 00371 00372 // 0 1 2 3 4 5 6 7 8 00373 // XX YY ZZ XY YZ ZX YX ZY XZ 00374 // 0 4 8 1 5 6 3 7 2 00375 self[0] = data_ptr[0]; 00376 self[4] = data_ptr[1]; 00377 self[8] = data_ptr[2]; 00378 00379 self[1] = data_ptr[3]; 00380 self[5] = data_ptr[4]; 00381 self[6] = data_ptr[5]; 00382 00383 self[3] = data_ptr[6]; 00384 self[7] = data_ptr[7]; 00385 self[2] = data_ptr[8]; 00386 break; 00387 00388 case SIERRA_SYMMETRIC: 00389 self[0] = data_ptr[0]; 00390 self[4] = data_ptr[1]; 00391 self[8] = data_ptr[2]; 00392 00393 self[1] = data_ptr[3]; 00394 self[5] = data_ptr[4]; 00395 self[6] = data_ptr[5]; 00396 00397 self[3] = data_ptr[3]; 00398 self[7] = data_ptr[4]; 00399 self[2] = data_ptr[5]; 00400 break; 00401 00402 default: 00403 std::cerr << "ERROR: " << __PRETTY_FUNCTION__; 00404 std::cerr << std::endl; 00405 std::cerr << "Unknown component order."; 00406 std::cerr << std::endl; 00407 exit(1); 00408 break; 00409 00410 } 00411 00412 break; 00413 } 00414 00415 return; 00416 } 00417 00418 // 00419 // Tensor addition 00420 // 00421 template<typename S, typename T, Index N> 00422 inline 00423 Tensor<typename Promote<S, T>::type, N> 00424 operator+(Tensor<S, N> const & A, Tensor<T, N> const & B) 00425 { 00426 Tensor<typename Promote<S, T>::type, N> 00427 C(A.get_dimension()); 00428 00429 add(A, B, C); 00430 00431 return C; 00432 } 00433 00434 // 00435 // Tensor subtraction 00436 // 00437 template<typename S, typename T, Index N> 00438 inline 00439 Tensor<typename Promote<S, T>::type, N> 00440 operator-(Tensor<S, N> const & A, Tensor<T, N> const & B) 00441 { 00442 Tensor<typename Promote<S, T>::type, N> 00443 C(A.get_dimension()); 00444 00445 subtract(A, B, C); 00446 00447 return C; 00448 } 00449 00450 // 00451 // Tensor minus 00452 // 00453 template<typename T, Index N> 00454 inline 00455 Tensor<T, N> 00456 operator-(Tensor<T, N> const & A) 00457 { 00458 Tensor<T, N> 00459 B(A.get_dimension()); 00460 00461 minus(A, B); 00462 00463 return B; 00464 } 00465 00466 // 00467 // Tensor equality 00468 // 00469 template<typename T, Index N> 00470 inline 00471 bool 00472 operator==(Tensor<T, N> const & A, Tensor<T, N> const & B) 00473 { 00474 return equal(A, B); 00475 } 00476 00477 // 00478 // Tensor inequality 00479 // 00480 template<typename T, Index N> 00481 inline 00482 bool 00483 operator!=(Tensor<T, N> const & A, Tensor<T, N> const & B) 00484 { 00485 return not_equal(A, B); 00486 } 00487 00488 // 00489 // Scalar tensor product 00490 // 00491 template<typename S, typename T, Index N> 00492 inline 00493 typename lazy_disable_if< order_1234<S>, apply_tensor< Promote<S,T>, N> >::type 00494 operator*(S const & s, Tensor<T, N> const & A) 00495 { 00496 Tensor<typename Promote<S, T>::type, N> 00497 B(A.get_dimension()); 00498 00499 scale(A, s, B); 00500 00501 return B; 00502 } 00503 00504 // 00505 // Tensor scalar product 00506 // 00507 template<typename S, typename T, Index N> 00508 inline 00509 typename lazy_disable_if< order_1234<S>, apply_tensor< Promote<S,T>, N> >::type 00510 operator*(Tensor<T, N> const & A, S const & s) 00511 { 00512 Tensor<typename Promote<S, T>::type, N> 00513 B(A.get_dimension()); 00514 00515 scale(A, s, B); 00516 00517 return B; 00518 } 00519 00520 // 00521 // Tensor scalar division 00522 // 00523 template<typename S, typename T, Index N> 00524 inline 00525 Tensor<typename Promote<S, T>::type, N> 00526 operator/(Tensor<T, N> const & A, S const & s) 00527 { 00528 Tensor<typename Promote<S, T>::type, N> 00529 B(A.get_dimension()); 00530 00531 divide(A, s, B); 00532 00533 return B; 00534 } 00535 00536 // 00537 // Scalar tensor division 00538 // 00539 template<typename S, typename T, Index N> 00540 inline 00541 Tensor<typename Promote<S, T>::type, N> 00542 operator/(S const & s, Tensor<T, N> const & A) 00543 { 00544 Tensor<typename Promote<S, T>::type, N> 00545 B(A.get_dimension()); 00546 00547 split(A, s, B); 00548 00549 return B; 00550 } 00551 00552 // 00553 // Tensor vector product v = A u 00554 // 00555 template<typename S, typename T, Index N> 00556 inline 00557 Vector<typename Promote<S, T>::type, N> 00558 operator*(Tensor<T, N> const & A, Vector<S, N> const & u) 00559 { 00560 return dot(A, u); 00561 } 00562 00563 // 00564 // Vector tensor product v = u A 00565 // 00566 template<typename S, typename T, Index N> 00567 inline 00568 Vector<typename Promote<S, T>::type, N> 00569 operator*(Vector<S, N> const & u, Tensor<T, N> const & A) 00570 { 00571 return dot(u, A); 00572 } 00573 00574 // 00575 // Tensor dot product C = A B 00576 // 00577 template<typename S, typename T, Index N> 00578 inline 00579 Tensor<typename Promote<S, T>::type, N> 00580 operator*(Tensor<S, N> const & A, Tensor<T, N> const & B) 00581 { 00582 return dot(A, B); 00583 } 00584 00585 namespace { 00586 00587 template<typename S> 00588 bool 00589 greater_than(S const & a, S const & b) 00590 { 00591 return a.first > b.first; 00592 } 00593 00594 } // anonymous namespace 00595 00596 // 00597 // Sort and index in descending order. Useful for ordering singular values 00598 // and eigenvalues and corresponding vectors in the respective decompositions. 00599 // 00600 template<typename T, Index N> 00601 std::pair<Vector<T, N>, Tensor<T, N> > 00602 sort_permutation(Vector<T, N> const & u) 00603 { 00604 00605 Index const 00606 dimension = u.get_dimension(); 00607 00608 std::vector<std::pair<T, Index > > 00609 s(dimension); 00610 00611 for (Index i = 0; i < dimension; ++i) { 00612 s[i].first = u(i); 00613 s[i].second = i; 00614 } 00615 00616 std::sort(s.begin(), s.end(), greater_than< std::pair<T, Index > > ); 00617 00618 Vector<T, N> v(dimension); 00619 00620 Tensor<T, N> 00621 P = zero<T, N>(dimension); 00622 00623 for (Index i = 0; i < dimension; ++i) { 00624 v(i) = s[i].first; 00625 P(s[i].second, i) = 1.0; 00626 } 00627 00628 return std::make_pair(v, P); 00629 00630 } 00631 00632 // 00633 // Extract a row as a vector 00634 // 00635 template<typename T, Index N> 00636 Vector<T, N> 00637 row(Tensor<T, N> const & A, Index const i) 00638 { 00639 Index const 00640 dimension = A.get_dimension(); 00641 00642 Vector<T, N> 00643 v(dimension); 00644 00645 switch (dimension) { 00646 default: 00647 for (Index j = 0; j < dimension; ++j) { 00648 v(j) = A(i,j); 00649 } 00650 break; 00651 00652 case 2: 00653 v(0) = A(i,0); 00654 v(1) = A(i,1); 00655 break; 00656 00657 case 3: 00658 v(0) = A(i,0); 00659 v(1) = A(i,1); 00660 v(2) = A(i,2); 00661 break; 00662 } 00663 00664 return v; 00665 } 00666 00667 // 00668 // Extract a column as a vector 00669 // 00670 template<typename T, Index N> 00671 Vector<T, N> 00672 col(Tensor<T, N> const & A, Index const j) 00673 { 00674 Index const 00675 dimension = A.get_dimension(); 00676 00677 Vector<T, N> 00678 v(dimension); 00679 00680 switch (dimension) { 00681 default: 00682 for (Index i = 0; i < dimension; ++i) { 00683 v(i) = A(i,j); 00684 } 00685 break; 00686 00687 case 2: 00688 v(0) = A(0,j); 00689 v(1) = A(1,j); 00690 break; 00691 00692 case 3: 00693 v(0) = A(0,j); 00694 v(1) = A(1,j); 00695 v(2) = A(2,j); 00696 break; 00697 } 00698 00699 return v; 00700 } 00701 00702 // 00703 // R^N tensor vector product v = A u 00704 // \param A tensor 00705 // \param u vector 00706 // \return \f$ A u \f$ 00707 // 00708 template<typename S, typename T, Index N> 00709 inline 00710 Vector<typename Promote<S, T>::type, N> 00711 dot(Tensor<T, N> const & A, Vector<S, N> const & u) 00712 { 00713 Index const 00714 dimension = A.get_dimension(); 00715 00716 assert(u.get_dimension() == dimension); 00717 00718 Vector<typename Promote<S, T>::type, N> 00719 v(dimension); 00720 00721 switch (dimension) { 00722 00723 default: 00724 for (Index i = 0; i < dimension; ++i) { 00725 00726 typename Promote<S, T>::type 00727 s = 0.0; 00728 00729 for (Index p = 0; p < dimension; ++p) { 00730 s += A(i, p) * u(p); 00731 } 00732 v(i) = s; 00733 } 00734 break; 00735 00736 case 3: 00737 v(0) = A(0,0)*u(0) + A(0,1)*u(1) + A(0,2)*u(2); 00738 v(1) = A(1,0)*u(0) + A(1,1)*u(1) + A(1,2)*u(2); 00739 v(2) = A(2,0)*u(0) + A(2,1)*u(1) + A(2,2)*u(2); 00740 break; 00741 00742 case 2: 00743 v(0) = A(0,0)*u(0) + A(0,1)*u(1); 00744 v(1) = A(1,0)*u(0) + A(1,1)*u(1); 00745 break; 00746 00747 } 00748 00749 return v; 00750 } 00751 00752 // 00753 // R^N vector tensor product v = u A 00754 // \param A tensor 00755 // \param u vector 00756 // \return \f$ u A = A^T u \f$ 00757 // 00758 template<typename S, typename T, Index N> 00759 inline 00760 Vector<typename Promote<S, T>::type, N> 00761 dot(Vector<S, N> const & u, Tensor<T, N> const & A) 00762 { 00763 Index const 00764 dimension = A.get_dimension(); 00765 00766 assert(u.get_dimension() == dimension); 00767 00768 Vector<typename Promote<S, T>::type, N> 00769 v(dimension); 00770 00771 switch (dimension) { 00772 00773 default: 00774 for (Index i = 0; i < dimension; ++i) { 00775 00776 typename Promote<S, T>::type 00777 s = 0.0; 00778 00779 for (Index p = 0; p < dimension; ++p) { 00780 s += A(p, i) * u(p); 00781 } 00782 v(i) = s; 00783 } 00784 break; 00785 00786 case 3: 00787 v(0) = A(0,0)*u(0) + A(1,0)*u(1) + A(2,0)*u(2); 00788 v(1) = A(0,1)*u(0) + A(1,1)*u(1) + A(2,1)*u(2); 00789 v(2) = A(0,2)*u(0) + A(1,2)*u(1) + A(2,2)*u(2); 00790 break; 00791 00792 case 2: 00793 v(0) = A(0,0)*u(0) + A(1,0)*u(1); 00794 v(1) = A(0,1)*u(0) + A(1,1)*u(1); 00795 break; 00796 00797 } 00798 00799 return v; 00800 } 00801 00802 // 00803 // R^N tensor tensor product C = A B 00804 // \param A tensor 00805 // \param B tensor 00806 // \return a tensor \f$ A \cdot B \f$ 00807 // 00808 template<typename S, typename T, Index N> 00809 inline 00810 Tensor<typename Promote<S, T>::type, N> 00811 dot(Tensor<S, N> const & A, Tensor<T, N> const & B) 00812 { 00813 Index const 00814 dimension = A.get_dimension(); 00815 00816 assert(B.get_dimension() == dimension); 00817 00818 Tensor<typename Promote<S, T>::type, N> 00819 C(dimension); 00820 00821 switch (dimension) { 00822 00823 default: 00824 for (Index i = 0; i < dimension; ++i) { 00825 for (Index j = 0; j < dimension; ++j) { 00826 00827 typename Promote<S, T>::type 00828 s = 0.0; 00829 00830 for (Index p = 0; p < dimension; ++p) { 00831 s += A(i, p) * B(p, j); 00832 } 00833 C(i, j) = s; 00834 } 00835 } 00836 break; 00837 00838 case 3: 00839 C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(1,0) + A(0,2)*B(2,0); 00840 C(0,1) = A(0,0)*B(0,1) + A(0,1)*B(1,1) + A(0,2)*B(2,1); 00841 C(0,2) = A(0,0)*B(0,2) + A(0,1)*B(1,2) + A(0,2)*B(2,2); 00842 00843 C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(1,0) + A(1,2)*B(2,0); 00844 C(1,1) = A(1,0)*B(0,1) + A(1,1)*B(1,1) + A(1,2)*B(2,1); 00845 C(1,2) = A(1,0)*B(0,2) + A(1,1)*B(1,2) + A(1,2)*B(2,2); 00846 00847 C(2,0) = A(2,0)*B(0,0) + A(2,1)*B(1,0) + A(2,2)*B(2,0); 00848 C(2,1) = A(2,0)*B(0,1) + A(2,1)*B(1,1) + A(2,2)*B(2,1); 00849 C(2,2) = A(2,0)*B(0,2) + A(2,1)*B(1,2) + A(2,2)*B(2,2); 00850 break; 00851 00852 case 2: 00853 C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(1,0); 00854 C(0,1) = A(0,0)*B(0,1) + A(0,1)*B(1,1); 00855 00856 C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(1,0); 00857 C(1,1) = A(1,0)*B(0,1) + A(1,1)*B(1,1); 00858 break; 00859 00860 } 00861 00862 return C; 00863 } 00864 00865 // 00866 // R^N tensor tensor product C = A^T B 00867 // \param A tensor 00868 // \param B tensor 00869 // \return a tensor \f$ A^T \cdot B \f$ 00870 // 00871 template<typename S, typename T, Index N> 00872 inline 00873 Tensor<typename Promote<S, T>::type, N> 00874 t_dot(Tensor<S, N> const & A, Tensor<T, N> const & B) 00875 { 00876 Index const 00877 dimension = A.get_dimension(); 00878 00879 assert(B.get_dimension() == dimension); 00880 00881 Tensor<typename Promote<S, T>::type, N> 00882 C(dimension); 00883 00884 switch (dimension) { 00885 00886 default: 00887 for (Index i = 0; i < dimension; ++i) { 00888 for (Index j = 0; j < dimension; ++j) { 00889 00890 typename Promote<S, T>::type 00891 s = 0.0; 00892 00893 for (Index p = 0; p < dimension; ++p) { 00894 s += A(p, i) * B(p, j); 00895 } 00896 C(i, j) = s; 00897 } 00898 } 00899 break; 00900 00901 case 3: 00902 C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(1,0) + A(2,0)*B(2,0); 00903 C(0,1) = A(0,0)*B(0,1) + A(1,0)*B(1,1) + A(2,0)*B(2,1); 00904 C(0,2) = A(0,0)*B(0,2) + A(1,0)*B(1,2) + A(2,0)*B(2,2); 00905 00906 C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(1,0) + A(2,1)*B(2,0); 00907 C(1,1) = A(0,1)*B(0,1) + A(1,1)*B(1,1) + A(2,1)*B(2,1); 00908 C(1,2) = A(0,1)*B(0,2) + A(1,1)*B(1,2) + A(2,1)*B(2,2); 00909 00910 C(2,0) = A(0,2)*B(0,0) + A(1,2)*B(1,0) + A(2,2)*B(2,0); 00911 C(2,1) = A(0,2)*B(0,1) + A(1,2)*B(1,1) + A(2,2)*B(2,1); 00912 C(2,2) = A(0,2)*B(0,2) + A(1,2)*B(1,2) + A(2,2)*B(2,2); 00913 break; 00914 00915 case 2: 00916 C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(1,0); 00917 C(0,1) = A(0,0)*B(0,1) + A(1,0)*B(1,1); 00918 00919 C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(1,0); 00920 C(1,1) = A(0,1)*B(0,1) + A(1,1)*B(1,1); 00921 break; 00922 00923 } 00924 00925 return C; 00926 } 00927 00928 // 00929 // R^N tensor tensor product C = A B^T 00930 // \param A tensor 00931 // \param B tensor 00932 // \return a tensor \f$ A \cdot B^T \f$ 00933 // 00934 template<typename S, typename T, Index N> 00935 inline 00936 Tensor<typename Promote<S, T>::type, N> 00937 dot_t(Tensor<S, N> const & A, Tensor<T, N> const & B) 00938 { 00939 Index const 00940 dimension = A.get_dimension(); 00941 00942 assert(B.get_dimension() == dimension); 00943 00944 Tensor<typename Promote<S, T>::type, N> 00945 C(dimension); 00946 00947 switch (dimension) { 00948 00949 default: 00950 for (Index i = 0; i < dimension; ++i) { 00951 for (Index j = 0; j < dimension; ++j) { 00952 00953 typename Promote<S, T>::type 00954 s = 0.0; 00955 00956 for (Index p = 0; p < dimension; ++p) { 00957 s += A(i, p) * B(j, p); 00958 } 00959 C(i, j) = s; 00960 } 00961 } 00962 break; 00963 00964 case 3: 00965 C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(0,1) + A(0,2)*B(0,2); 00966 C(0,1) = A(0,0)*B(1,0) + A(0,1)*B(1,1) + A(0,2)*B(1,2); 00967 C(0,2) = A(0,0)*B(2,0) + A(0,1)*B(2,1) + A(0,2)*B(2,2); 00968 00969 C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(0,1) + A(1,2)*B(0,2); 00970 C(1,1) = A(1,0)*B(1,0) + A(1,1)*B(1,1) + A(1,2)*B(1,2); 00971 C(1,2) = A(1,0)*B(2,0) + A(1,1)*B(2,1) + A(1,2)*B(2,2); 00972 00973 C(2,0) = A(2,0)*B(0,0) + A(2,1)*B(0,1) + A(2,2)*B(0,2); 00974 C(2,1) = A(2,0)*B(1,0) + A(2,1)*B(1,1) + A(2,2)*B(1,2); 00975 C(2,2) = A(2,0)*B(2,0) + A(2,1)*B(2,1) + A(2,2)*B(2,2); 00976 break; 00977 00978 case 2: 00979 C(0,0) = A(0,0)*B(0,0) + A(0,1)*B(0,1); 00980 C(0,1) = A(0,0)*B(1,0) + A(0,1)*B(1,1); 00981 00982 C(1,0) = A(1,0)*B(0,0) + A(1,1)*B(0,1); 00983 C(1,1) = A(1,0)*B(1,0) + A(1,1)*B(1,1); 00984 break; 00985 00986 } 00987 00988 return C; 00989 } 00990 00991 // 00992 // R^N tensor tensor product C = A^T B^T 00993 // \param A tensor 00994 // \param B tensor 00995 // \return a tensor \f$ A^T \cdot B^T \f$ 00996 // 00997 template<typename S, typename T, Index N> 00998 inline 00999 Tensor<typename Promote<S, T>::type, N> 01000 t_dot_t(Tensor<S, N> const & A, Tensor<T, N> const & B) 01001 { 01002 Index const 01003 dimension = A.get_dimension(); 01004 01005 assert(B.get_dimension() == dimension); 01006 01007 Tensor<typename Promote<S, T>::type, N> 01008 C(dimension); 01009 01010 switch (dimension) { 01011 01012 default: 01013 for (Index i = 0; i < dimension; ++i) { 01014 for (Index j = 0; j < dimension; ++j) { 01015 01016 typename Promote<S, T>::type 01017 s = 0.0; 01018 01019 for (Index p = 0; p < dimension; ++p) { 01020 s += A(p, i) * B(j, p); 01021 } 01022 C(i, j) = s; 01023 } 01024 } 01025 break; 01026 01027 case 3: 01028 C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(0,1) + A(2,0)*B(0,2); 01029 C(0,1) = A(0,0)*B(1,0) + A(1,0)*B(1,1) + A(2,0)*B(1,2); 01030 C(0,2) = A(0,0)*B(2,0) + A(1,0)*B(2,1) + A(2,0)*B(2,2); 01031 01032 C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(0,1) + A(2,1)*B(0,2); 01033 C(1,1) = A(0,1)*B(1,0) + A(1,1)*B(1,1) + A(2,1)*B(1,2); 01034 C(1,2) = A(0,1)*B(2,0) + A(1,1)*B(2,1) + A(2,1)*B(2,2); 01035 01036 C(2,0) = A(0,2)*B(0,0) + A(1,2)*B(0,1) + A(2,2)*B(0,2); 01037 C(2,1) = A(0,2)*B(1,0) + A(1,2)*B(1,1) + A(2,2)*B(1,2); 01038 C(2,2) = A(0,2)*B(2,0) + A(1,2)*B(2,1) + A(2,2)*B(2,2); 01039 break; 01040 01041 case 2: 01042 C(0,0) = A(0,0)*B(0,0) + A(1,0)*B(0,1); 01043 C(0,1) = A(0,0)*B(1,0) + A(1,0)*B(1,1); 01044 01045 C(1,0) = A(0,1)*B(0,0) + A(1,1)*B(0,1); 01046 C(1,1) = A(0,1)*B(1,0) + A(1,1)*B(1,1); 01047 break; 01048 01049 } 01050 01051 return C; 01052 } 01053 01054 // 01055 // R^N tensor tensor double dot product (contraction) 01056 // \param A tensor 01057 // \param B tensor 01058 // \return a scalar \f$ A : B \f$ 01059 // 01060 template<typename S, typename T, Index N> 01061 inline 01062 typename Promote<S, T>::type 01063 dotdot(Tensor<S, N> const & A, Tensor<T, N> const & B) 01064 { 01065 Index const 01066 dimension = A.get_dimension(); 01067 01068 assert(B.get_dimension() == dimension); 01069 01070 typename Promote<S, T>::type 01071 s = 0.0; 01072 01073 switch (dimension) { 01074 01075 default: 01076 for (Index p = 0; p < dimension; ++p) { 01077 for (Index q = 0; q < dimension; ++q) { 01078 s += A(p, q) * B(p, q); 01079 } 01080 } 01081 break; 01082 01083 case 3: 01084 s+= A(0,0)*B(0,0) + A(0,1)*B(0,1) + A(0,2)*B(0,2); 01085 s+= A(1,0)*B(1,0) + A(1,1)*B(1,1) + A(1,2)*B(1,2); 01086 s+= A(2,0)*B(2,0) + A(2,1)*B(2,1) + A(2,2)*B(2,2); 01087 break; 01088 01089 case 2: 01090 s+= A(0,0)*B(0,0) + A(0,1)*B(0,1); 01091 s+= A(1,0)*B(1,0) + A(1,1)*B(1,1); 01092 break; 01093 01094 } 01095 01096 return s; 01097 } 01098 01099 // 01100 // R^N dyad 01101 // \param u vector 01102 // \param v vector 01103 // \return \f$ u \otimes v \f$ 01104 // 01105 template<typename S, typename T, Index N> 01106 inline 01107 Tensor<typename Promote<S, T>::type, N> 01108 dyad(Vector<S, N> const & u, Vector<T, N> const & v) 01109 { 01110 Index const 01111 dimension = u.get_dimension(); 01112 01113 assert(v.get_dimension() == dimension); 01114 01115 Tensor<typename Promote<S, T>::type, N> 01116 A(dimension); 01117 01118 switch (dimension) { 01119 01120 default: 01121 for (Index i = 0; i < dimension; ++i) { 01122 01123 typename Promote<S, T>::type const 01124 s = u(i); 01125 01126 for (Index j = 0; j < dimension; ++j) { 01127 A(i, j) = s * v(j); 01128 } 01129 } 01130 break; 01131 01132 case 3: 01133 A(0,0) = u(0) * v(0); 01134 A(0,1) = u(0) * v(1); 01135 A(0,2) = u(0) * v(2); 01136 01137 A(1,0) = u(1) * v(0); 01138 A(1,1) = u(1) * v(1); 01139 A(1,2) = u(1) * v(2); 01140 01141 A(2,0) = u(2) * v(0); 01142 A(2,1) = u(2) * v(1); 01143 A(2,2) = u(2) * v(2); 01144 break; 01145 01146 case 2: 01147 A(0,0) = u(0) * v(0); 01148 A(0,1) = u(0) * v(1); 01149 01150 A(1,0) = u(1) * v(0); 01151 A(1,1) = u(1) * v(1); 01152 break; 01153 01154 } 01155 01156 return A; 01157 } 01158 01159 // 01160 // R^N bun operator, just for Jay, and now Reese too. 01161 // \param u vector 01162 // \param v vector 01163 // \return \f$ u \otimes v \f$ 01164 // 01165 template<typename S, typename T, Index N> 01166 inline 01167 Tensor<typename Promote<S, T>::type, N> 01168 bun(Vector<S, N> const & u, Vector<T, N> const & v) 01169 { 01170 return dyad(u, v); 01171 } 01172 01173 // 01174 // R^N tensor product 01175 // \param u vector 01176 // \param v vector 01177 // \return \f$ u \otimes v \f$ 01178 // 01179 template<typename S, typename T, Index N> 01180 inline 01181 Tensor<typename Promote<S, T>::type, N> 01182 tensor(Vector<S, N> const & u, Vector<T, N> const & v) 01183 { 01184 return dyad(u, v); 01185 } 01186 01187 // 01188 // R^N diagonal tensor from vector 01189 // \param v vector 01190 // \return A = diag(v) 01191 // 01192 template<typename T, Index N> 01193 Tensor<T, N> 01194 diag(Vector<T, N> const & v) 01195 { 01196 Index const 01197 dimension = v.get_dimension(); 01198 01199 Tensor<T, N> 01200 A = zero<T, N>(dimension); 01201 01202 switch (dimension) { 01203 01204 default: 01205 for (Index i = 0; i < dimension; ++i) { 01206 A(i, i) = v(i); 01207 } 01208 break; 01209 01210 case 3: 01211 A(0,0) = v(0); 01212 A(1,1) = v(1); 01213 A(2,2) = v(2); 01214 break; 01215 01216 case 2: 01217 A(0,0) = v(0); 01218 A(1,1) = v(1); 01219 break; 01220 01221 } 01222 01223 return A; 01224 } 01225 01226 // 01227 // R^N diagonal of tensor in a vector 01228 // \param A tensor 01229 // \return v = diag(A) 01230 // 01231 template<typename T, Index N> 01232 Vector<T, N> 01233 diag(Tensor<T, N> const & A) 01234 { 01235 Index const 01236 dimension = A.get_dimension(); 01237 01238 Vector<T, N> 01239 v(dimension); 01240 01241 switch (dimension) { 01242 01243 default: 01244 for (Index i = 0; i < dimension; ++i) { 01245 v(i) = A(i, i); 01246 } 01247 break; 01248 01249 case 3: 01250 v(0) = A(0,0); 01251 v(1) = A(1,1); 01252 v(2) = A(2,2); 01253 break; 01254 01255 case 2: 01256 v(0) = A(0,0); 01257 v(1) = A(1,1); 01258 break; 01259 01260 } 01261 01262 return v; 01263 } 01264 01265 // 01266 // Zero 2nd-order tensor 01267 // All components are zero 01268 // 01269 template<typename T, Index N> 01270 inline 01271 Tensor<T, N> const 01272 zero() 01273 { 01274 return Tensor<T, N>(N, ZEROS); 01275 } 01276 01277 template<typename T> 01278 inline 01279 Tensor<T, DYNAMIC> const 01280 zero(Index const dimension) 01281 { 01282 return Tensor<T, DYNAMIC>(dimension, ZEROS); 01283 } 01284 01285 template<typename T, Index N> 01286 inline 01287 Tensor<T, N> const 01288 zero(Index const dimension) 01289 { 01290 if (N != DYNAMIC) assert(dimension == N); 01291 return Tensor<T, N>(dimension, ZEROS); 01292 } 01293 01294 // 01295 // R^N 2nd-order identity tensor 01296 // 01297 namespace { 01298 01299 template< typename T, Index N> 01300 inline 01301 void ones_in_diagonal(Tensor<T, N> & A) 01302 { 01303 Index const 01304 dimension = A.get_dimension(); 01305 01306 switch (dimension) { 01307 01308 default: 01309 for (Index i = 0; i < dimension; ++i) { 01310 A(i, i) = 1.0; 01311 } 01312 break; 01313 01314 case 3: 01315 A(0,0) = 1.0; 01316 A(1,1) = 1.0; 01317 A(2,2) = 1.0; 01318 break; 01319 01320 case 2: 01321 A(0,0) = 1.0; 01322 A(1,1) = 1.0; 01323 break; 01324 01325 } 01326 01327 return; 01328 } 01329 01330 } // anonymous namespace 01331 01332 template<typename T, Index N> 01333 inline 01334 Tensor<T, N> const 01335 identity() 01336 { 01337 Tensor<T, N> A(N, ZEROS); 01338 ones_in_diagonal(A); 01339 return A; 01340 } 01341 01342 template<typename T> 01343 inline 01344 Tensor<T, DYNAMIC> const 01345 identity(Index const dimension) 01346 { 01347 Tensor<T, DYNAMIC> A(dimension, ZEROS); 01348 ones_in_diagonal(A); 01349 return A; 01350 } 01351 01352 template<typename T, Index N> 01353 inline 01354 Tensor<T, N> const 01355 identity(Index const dimension) 01356 { 01357 if (N != DYNAMIC) assert(dimension == N); 01358 01359 Tensor<T, N> A(dimension, ZEROS); 01360 ones_in_diagonal(A); 01361 return A; 01362 } 01363 01364 // 01365 // R^N 2nd-order identity tensor, à la Matlab 01366 // 01367 template<typename T, Index N> 01368 inline 01369 Tensor<T, N> const 01370 eye() 01371 { 01372 return identity<T, N>(); 01373 } 01374 01375 template<typename T> 01376 inline 01377 Tensor<T, DYNAMIC> const 01378 eye(Index const dimension) 01379 { 01380 return identity<T>(dimension); 01381 } 01382 01383 template<typename T, Index N> 01384 inline 01385 Tensor<T, N> const 01386 eye(Index const dimension) 01387 { 01388 return identity<T, N>(dimension); 01389 } 01390 01391 // 01392 // R^N 2nd-order tensor transpose 01393 // 01394 template<typename T, Index N> 01395 inline 01396 Tensor<T, N> 01397 transpose(Tensor<T, N> const & A) 01398 { 01399 Index const 01400 dimension = A.get_dimension(); 01401 01402 Tensor<T, N> 01403 B = A; 01404 01405 switch (dimension) { 01406 01407 default: 01408 for (Index i = 0; i < dimension; ++i) { 01409 for (Index j = i + 1; j < dimension; ++j) { 01410 std::swap(B(i, j), B(j, i)); 01411 } 01412 } 01413 break; 01414 01415 case 3: 01416 std::swap(B(0,1), B(1,0)); 01417 std::swap(B(0,2), B(2,0)); 01418 01419 std::swap(B(1,2), B(2,1)); 01420 01421 break; 01422 01423 case 2: 01424 std::swap(B(0,1), B(1,0)); 01425 01426 break; 01427 01428 } 01429 01430 return B; 01431 } 01432 01433 // 01434 // R^N symmetric part of 2nd-order tensor 01435 // \return \f$ \frac{1}{2}(A + A^T) \f$ 01436 // 01437 template<typename T, Index N> 01438 inline 01439 Tensor<T, N> 01440 sym(Tensor<T, N> const & A) 01441 { 01442 Index const 01443 dimension = A.get_dimension(); 01444 01445 Tensor<T, N> 01446 B(dimension); 01447 01448 switch (dimension) { 01449 01450 default: 01451 B = 0.5 * (A + transpose(A)); 01452 break; 01453 01454 case 3: 01455 { 01456 T const & s00 = A(0,0); 01457 T const & s11 = A(1,1); 01458 T const & s22 = A(2,2); 01459 01460 T const s01 = 0.5 * (A(0,1) + A(1,0)); 01461 T const s02 = 0.5 * (A(0,2) + A(2,0)); 01462 T const s12 = 0.5 * (A(1,2) + A(2,1)); 01463 01464 B(0,0) = s00; 01465 B(0,1) = s01; 01466 B(0,2) = s02; 01467 01468 B(1,0) = s01; 01469 B(1,1) = s11; 01470 B(1,2) = s12; 01471 01472 B(2,0) = s02; 01473 B(2,1) = s12; 01474 B(2,2) = s22; 01475 } 01476 break; 01477 01478 case 2: 01479 { 01480 T const & s00 = A(0,0); 01481 T const & s11 = A(1,1); 01482 01483 T const s01 = 0.5 * (A(0,1) + A(1,0)); 01484 01485 B(0,0) = s00; 01486 B(0,1) = s01; 01487 01488 B(1,0) = s01; 01489 B(1,1) = s11; 01490 } 01491 break; 01492 01493 } 01494 01495 return B; 01496 } 01497 01498 // 01499 // R^N skew symmetric part of 2nd-order tensor 01500 // \return \f$ \frac{1}{2}(A - A^T) \f$ 01501 // 01502 template<typename T, Index N> 01503 inline 01504 Tensor<T, N> 01505 skew(Tensor<T, N> const & A) 01506 { 01507 Index const 01508 dimension = A.get_dimension(); 01509 01510 Tensor<T, N> 01511 B(dimension); 01512 01513 switch (dimension) { 01514 01515 default: 01516 B = 0.5 * (A - transpose(A)); 01517 break; 01518 01519 case 3: 01520 { 01521 T const s01 = 0.5*(A(0,1)-A(1,0)); 01522 T const s02 = 0.5*(A(0,2)-A(2,0)); 01523 T const s12 = 0.5*(A(1,2)-A(2,1)); 01524 01525 B(0,0) = 0.0; 01526 B(0,1) = s01; 01527 B(0,2) = s02; 01528 01529 B(1,0) = -s01; 01530 B(1,1) = 0.0; 01531 B(1,2) = s12; 01532 01533 B(2,0) = -s02; 01534 B(2,1) = -s12; 01535 B(2,2) = 0.0; 01536 } 01537 break; 01538 01539 case 2: 01540 { 01541 T const s01 = 0.5*(A(0,1)-A(1,0)); 01542 01543 B(0,0) = 0.0; 01544 B(0,1) = s01; 01545 01546 B(1,0) = -s01; 01547 B(1,1) = 0.0; 01548 } 01549 break; 01550 01551 } 01552 01553 return B; 01554 } 01555 01556 // 01557 // R^N skew symmetric 2nd-order tensor from vector, undefined 01558 // for N!=3. 01559 // \param u vector 01560 // 01561 template<typename T, Index N> 01562 inline 01563 Tensor<T, N> 01564 skew(Vector<T, N> const & u) 01565 { 01566 Index const 01567 dimension = u.get_dimension(); 01568 01569 Tensor<T, N> 01570 A(dimension); 01571 01572 switch (dimension) { 01573 01574 case 3: 01575 A(0,0) = 0.0; 01576 A(0,1) = -u(2); 01577 A(0,2) = u(1); 01578 01579 A(1,0) = u(2); 01580 A(1,1) = 0.0; 01581 A(1,2) = -u(0); 01582 01583 A(2,0) = -u(1); 01584 A(2,1) = u(0); 01585 A(2,2) = 0.0; 01586 break; 01587 01588 default: 01589 std::cerr << "ERROR: " << __PRETTY_FUNCTION__; 01590 std::cerr << std::endl; 01591 std::cerr << "Skew from vector undefined for R^" << N; 01592 std::cerr << std::endl; 01593 exit(1); 01594 break; 01595 01596 } 01597 01598 return A; 01599 } 01600 01601 } // namespace Intrepid 01602 01603 #endif // Intrepid_MiniTensor_Tensor_i_h
1.7.6.1