// -*- C++ -*- /*************************************************************************** * * The IPPL Framework * * * Visit http://people.web.psi.ch/adelmann/ for more details * ***************************************************************************/ #ifndef TENZOR_H #define TENZOR_H // include files #include "Utility/PAssert.h" #include "Message/Message.h" #include "PETE/IpplExpressions.h" #include "AppTypes/TSVMeta.h" #include // forward declarations template class SymTenzor; template class AntiSymTenzor; ////////////////////////////////////////////////////////////////////// // // Definition of class Tenzor. // ////////////////////////////////////////////////////////////////////// template class Tenzor { public: typedef T Element_t; enum { ElemDim = 2 }; enum { Size = D*D }; // Default Constructor Tenzor() { TSV_MetaAssignScalar,T,OpAssign>::apply(*this,T(0)); } // A noninitializing ctor. class DontInitialize {}; Tenzor(DontInitialize) {} // Copy Constructor Tenzor(const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor ,OpAssign >::apply(*this,rhs); } // constructor from a single T Tenzor(const T& x00) { TSV_MetaAssignScalar< Tenzor , T ,OpAssign >::apply(*this,x00); } // constructors for fixed dimension Tenzor(const T& x00, const T& x10, const T& x01, const T& x11) { PInsist(D==2, "Number of arguments does not match Tenzor dimension!!"); X[0] = x00; X[1] = x10; X[2] = x01; X[3] = x11; } Tenzor(const T& x00, const T& x10, const T& x20, const T& x01, const T& x11, const T& x21, const T& x02, const T& x12, const T& x22) { PInsist(D==3, "Number of arguments does not match Tenzor dimension!!"); X[0] = x00; X[1] = x10; X[2] = x20; X[3] = x01; X[4] = x11; X[5] = x21; X[6] = x02; X[7] = x12; X[8] = x22; } // constructor from SymTenzor Tenzor(const SymTenzor&); // constructor from AntiSymTenzor Tenzor(const AntiSymTenzor&); // destructor ~Tenzor() { }; // assignment operators const Tenzor& operator= (const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor ,OpAssign> :: apply(*this,rhs); return *this; } template const Tenzor& operator= (const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor ,OpAssign> :: apply(*this,rhs); return *this; } const Tenzor& operator= (const T& rhs) { TSV_MetaAssignScalar< Tenzor , T ,OpAssign> :: apply(*this,rhs); return *this; } // accumulation operators template Tenzor& operator+=(const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor , OpAddAssign > :: apply(*this,rhs); return *this; } Tenzor& operator+=(const T& rhs) { TSV_MetaAssignScalar< Tenzor , T , OpAddAssign > :: apply(*this,rhs); return *this; } template Tenzor& operator-=(const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor , OpSubtractAssign > :: apply(*this,rhs); return *this; } Tenzor& operator-=(const T& rhs) { TSV_MetaAssignScalar< Tenzor , T , OpSubtractAssign > :: apply(*this,rhs); return *this; } template Tenzor& operator*=(const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor , OpMultipplyAssign > :: apply(*this,rhs); return *this; } Tenzor& operator*=(const T& rhs) { TSV_MetaAssignScalar< Tenzor , T , OpMultipplyAssign > :: apply(*this,rhs); return *this; } template Tenzor& operator/=(const Tenzor &rhs) { TSV_MetaAssign< Tenzor , Tenzor , OpDivideAssign > :: apply(*this,rhs); return *this; } Tenzor& operator/=(const T& rhs) { TSV_MetaAssignScalar< Tenzor , T , OpDivideAssign > :: apply(*this,rhs); return *this; } // Methods void diagonal(const T& rhs) { for (unsigned int i = 0 ; i < D ; i++ ) (*this)(i,i) = rhs; } int len(void) const { return Size; } int size(void) const { return sizeof(*this); } // Operators Element_t &operator[]( unsigned int i ) { PAssert_LT(i, Size); return X[i]; } Element_t operator[]( unsigned int i ) const { PAssert_LT(i, Size); return X[i]; } //TJW: add these 12/16/97 to help with NegReflectAndZeroFace BC: // These are the same as operator[] but with () instead: Element_t& operator()(unsigned int i) { PAssert (i < Size); return X[i]; } Element_t operator()(unsigned int i) const { PAssert (i < Size); return X[i]; } //TJW. Element_t operator()( unsigned int i, unsigned int j ) const { PAssert ( (i i) const { PAssert ( (i.first>=0) && (i.second>=0) && (i.first i) { PAssert ( (i.first>=0) && (i.second>=0) && (i.first& that) const { return TSV_MetaCompareArrays::apply(X,that.X); } bool operator!=(const Tenzor& that) const { return !(*this == that); } //---------------------------------------------------------------------- // parallel communication Message& putMessage(Message& m) const { m.setCopy(true); const T *p = X; ::putMessage(m, p, p + D*D); return m; } Message& getMessage(Message& m) { T *p = X; ::getMessage(m, p, p + D*D); return m; } private: // The elements themselves. T X[Size]; }; ////////////////////////////////////////////////////////////////////// // // Free functions // ////////////////////////////////////////////////////////////////////// // trace() - sum of diagonal elements. template inline T trace(const Tenzor& rhs) { T result = 0.0; for (unsigned int i = 0 ; i < D ; i++ ) result += rhs(i,i); return result; } // transpose(). transpose(i,j) = input(j,i). template inline Tenzor transpose(const Tenzor& rhs) { Tenzor result = typename Tenzor::DontInitialize(); for (unsigned int j = 0 ; j < D ; j++ ) for (unsigned int i = 0 ; i < D ; i++ ) result(i,j) = rhs(j,i); return result; } // Determinant: only implement for 1D, 2D, 3D: template inline T det(const Tenzor& rhs) { PInsist(D<4, "Tenzor det() function not implemented for D>3!"); return T(-999999.999999); } template inline T det(const Tenzor& rhs) { T result; result = rhs(0,0)*(rhs(1,1)*rhs(2,2) - rhs(1,2)*rhs(2,1)) + rhs(0,1)*(rhs(1,2)*rhs(2,0) - rhs(1,0)*rhs(2,2)) + rhs(0,2)*(rhs(1,0)*rhs(2,1) - rhs(1,1)*rhs(2,0)); return result; } template inline T det(const Tenzor& rhs) { T result; result = rhs(0,0)*rhs(1,1) - rhs(0,1)*rhs(1,0); return result; } template inline T det(const Tenzor& rhs) { T result = rhs(0,0); return result; } // cofactors() - pow(-1, i+j)*M(i,j), where M(i,j) is a minor of the tensor. // See, for example, Arfken, Mathematical Methods for Physicists, 2nd Edition, // p. 157 (the section where the determinant of a matrix is defined). // Only implement for 1D, 2D, 3D: template inline Tenzor cofactors(const Tenzor& rhs) { PInsist(D<4, "Tenzor cofactors() function not implemented for D>3!"); return Tenzor(-999999.999999); } template inline Tenzor cofactors(const Tenzor& rhs) { Tenzor result = typename Tenzor::DontInitialize(); result(0,0) = rhs(1,1)*rhs(2,2) - rhs(1,2)*rhs(2,1); result(1,0) = rhs(0,2)*rhs(2,1) - rhs(0,1)*rhs(2,2); result(2,0) = rhs(0,1)*rhs(1,2) - rhs(1,1)*rhs(0,2); result(0,1) = rhs(2,0)*rhs(1,2) - rhs(1,0)*rhs(2,2); result(1,1) = rhs(0,0)*rhs(2,2) - rhs(0,2)*rhs(2,0); result(2,1) = rhs(1,0)*rhs(0,2) - rhs(0,0)*rhs(1,2); result(0,2) = rhs(1,0)*rhs(2,1) - rhs(2,0)*rhs(1,1); result(1,2) = rhs(0,1)*rhs(2,0) - rhs(0,0)*rhs(2,1); result(2,2) = rhs(0,0)*rhs(1,1) - rhs(1,0)*rhs(0,1); return result; } template inline Tenzor cofactors(const Tenzor& rhs) { Tenzor result = typename Tenzor::DontInitialize(); result(0,0) = rhs(1,1); result(1,0) = -rhs(0,1); result(0,1) = -rhs(1,0); result(1,1) = rhs(0,0); return result; } // For D=1, cofactor is the unit tensor, because det = single tensor element // value: template inline Tenzor cofactors(const Tenzor& rhs) { Tenzor result = Tenzor(1); return result; } ////////////////////////////////////////////////////////////////////// // // Unary Operators // ////////////////////////////////////////////////////////////////////// //---------------------------------------------------------------------- // unary operator- template inline Tenzor operator-(const Tenzor &op) { return TSV_MetaUnary< Tenzor , OpUnaryMinus > :: apply(op); } //---------------------------------------------------------------------- // unary operator+ template inline const Tenzor &operator+(const Tenzor &op) { return op; } ////////////////////////////////////////////////////////////////////// // // Binary Operators // ////////////////////////////////////////////////////////////////////// // // Elementwise operators. // TSV_ELEMENTWISE_OPERATOR(Tenzor,operator+,OpAdd) TSV_ELEMENTWISE_OPERATOR(Tenzor,operator-,OpSubtract) TSV_ELEMENTWISE_OPERATOR(Tenzor,operator*,OpMultipply) TSV_ELEMENTWISE_OPERATOR(Tenzor,operator/,OpDivide) TSV_ELEMENTWISE_OPERATOR(Tenzor,Min,FnMin) TSV_ELEMENTWISE_OPERATOR(Tenzor,Max,FnMax) //---------------------------------------------------------------------- // dot products. //---------------------------------------------------------------------- template < class T1, class T2, unsigned D > inline Tenzor::type,D> dot(const Tenzor &lhs, const Tenzor &rhs) { return TSV_MetaDot< Tenzor , Tenzor > :: apply(lhs,rhs); } template < class T1, class T2, unsigned D > inline Vektor::type,D> dot(const Vektor &lhs, const Tenzor &rhs) { return TSV_MetaDot< Vektor , Tenzor > :: apply(lhs,rhs); } template < class T1, class T2, unsigned D > inline Vektor::type,D> dot(const Tenzor &lhs, const Vektor &rhs) { return TSV_MetaDot< Tenzor , Vektor > :: apply(lhs,rhs); } //---------------------------------------------------------------------- // double dot product. //---------------------------------------------------------------------- template < class T1, class T2, unsigned D > inline typename PETEBinaryReturn::type dotdot(const Tenzor &lhs, const Tenzor &rhs) { return TSV_MetaDotDot< Tenzor , Tenzor > :: apply(lhs,rhs); } //---------------------------------------------------------------------- // Outer product. //---------------------------------------------------------------------- template inline Tenzor::type,D > outerProduct(const Vektor& v1, const Vektor& v2) { typedef typename PETEBinaryReturn::type T0; Tenzor ret = typename Tenzor::DontInitialize(); for (unsigned int i=0; i inline std::ostream& operator<<(std::ostream& out, const Tenzor& rhs) { if (D >= 1) { for (unsigned int i=0; i Tenzor::Tenzor(const SymTenzor& rhs) { for (unsigned int i=0; i Tenzor::Tenzor(const AntiSymTenzor& rhs) { for (unsigned int i=0; i