Main Page | Namespace List | Class Hierarchy | Class List | File List | Class Members | File Members

src/AppTypes/AntiSymTenzor.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /***************************************************************************
00003  *
00004  * The IPPL Framework
00005  * 
00006  *
00007  * Visit http://people.web.psi.ch/adelmann/ for more details
00008  *
00009  ***************************************************************************/
00010 
00011 #ifndef ANTI_SYM_TENZOR_H
00012 #define ANTI_SYM_TENZOR_H
00013 
00014 // include files
00015 #include "Utility/PAssert.h"
00016 #include "Message/Message.h"
00017 #include "PETE/IpplExpressions.h"
00018 #include "AppTypes/TSVMeta.h"
00019 #include "AppTypes/Tenzor.h"
00020 
00021 #ifdef IPPL_USE_STANDARD_HEADERS
00022 #include <iostream>
00023 using namespace std;
00024 #else
00025 #include <iostream.h>
00026 #endif
00027 
00028 
00030 //
00031 // Definition of class AntiSymTenzor.
00032 //
00034 
00035 //
00036 //              |  O -x10  -x20 |
00037 //              | x10   0  -x21 |
00038 //              | x20  x21   0  |
00039 //
00040 
00041 template<class T, unsigned D>
00042 class AntiSymTenzor
00043 {
00044 public:
00045 
00046   typedef T Element_t;
00047   enum { ElemDim = 2 };
00048   enum { Size = D*(D-1)/2 };
00049 
00050   // Default Constructor 
00051   AntiSymTenzor() {
00052     TSV_MetaAssignScalar< AntiSymTenzor<T,D>,T,OpAssign>::apply(*this,T(0));
00053   } 
00054 
00055   // A noninitializing ctor.
00056   class DontInitialize {};
00057   AntiSymTenzor(DontInitialize) {}
00058 
00059   // Construct an AntiSymTenzor from a single T.
00060   // This doubles as the 2D AntiSymTenzor initializer.
00061   AntiSymTenzor(const T& x00) {
00062     TSV_MetaAssignScalar< AntiSymTenzor<T,D>,T,OpAssign>::apply(*this,x00);
00063   }
00064   // construct a 3D AntiSymTenzor
00065   AntiSymTenzor(const T& x10, const T& x20, const T& x21) { 
00066     PInsist(D==3,
00067             "Number of arguments does not match AntiSymTenzor dimension!!");
00068     X[0]= x10; X[1]= x20; X[2]= x21;
00069   }
00070 
00071   // Copy Constructor
00072   AntiSymTenzor(const AntiSymTenzor<T,D> &rhs) {
00073     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T,D> ,OpAssign > :: 
00074       apply(*this,rhs);
00075   }
00076 
00077   // Construct from a Tenzor.
00078   // Extract the antisymmetric part.
00079   AntiSymTenzor( const Tenzor<T,D>& t ) {
00080     for (int i=1; i<D; ++i) {
00081       for (int j=0; j<i; ++j)
00082         (*this)[((i-1)*i/2)+j] = (t(i,j)-t(j,i))*0.5;
00083     }
00084   }
00085 
00086   ~AntiSymTenzor() { };
00087 
00088   // assignment operators
00089   const AntiSymTenzor<T,D>& operator= (const AntiSymTenzor<T,D> &rhs) {
00090     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T,D> ,OpAssign > :: 
00091       apply(*this,rhs);
00092     return *this;
00093   }
00094   template<class T1>
00095   const AntiSymTenzor<T,D>& operator= (const AntiSymTenzor<T1,D> &rhs) {
00096     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T1,D> ,OpAssign > :: 
00097       apply(*this,rhs);
00098     return *this;
00099   }
00100   const AntiSymTenzor<T,D>& operator= (const T& rhs) {
00101     TSV_MetaAssignScalar< AntiSymTenzor<T,D> , T ,OpAssign > :: 
00102       apply(*this,rhs);
00103     return *this;
00104   }
00105 
00106   // accumulation operators
00107   template<class T1>
00108   AntiSymTenzor<T,D>& operator+=(const AntiSymTenzor<T1,D> &rhs)
00109   {
00110     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T1,D> , OpAddAssign > 
00111       :: apply(*this,rhs);
00112     return *this;
00113   }
00114 
00115   template<class T1>
00116   AntiSymTenzor<T,D>& operator-=(const AntiSymTenzor<T1,D> &rhs)
00117   {
00118     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T1,D> , 
00119       OpSubtractAssign > :: apply(*this,rhs);
00120     return *this;
00121   }
00122 
00123   template<class T1>
00124   AntiSymTenzor<T,D>& operator*=(const AntiSymTenzor<T1,D> &rhs)
00125   {
00126     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T1,D> , 
00127       OpMultipplyAssign > :: apply(*this,rhs);
00128     return *this;
00129   }
00130   AntiSymTenzor<T,D>& operator*=(const T& rhs)
00131   {
00132     TSV_MetaAssignScalar< AntiSymTenzor<T,D> , T , OpMultipplyAssign > :: 
00133       apply(*this,rhs);
00134     return *this;
00135   }
00136 
00137   template<class T1>
00138   AntiSymTenzor<T,D>& operator/=(const AntiSymTenzor<T1,D> &rhs)
00139   {
00140     TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T1,D> , 
00141       OpDivideAssign > :: apply(*this,rhs);
00142     return *this;
00143   }
00144   AntiSymTenzor<T,D>& operator/=(const T& rhs)
00145   {
00146     TSV_MetaAssignScalar< AntiSymTenzor<T,D> , T , OpDivideAssign > :: 
00147       apply(*this,rhs);
00148     return *this;
00149   }
00150 
00151   // Methods
00152 
00153   int len(void)  const { return Size; }
00154   int size(void) const { return sizeof(*this); }
00155   int get_Size(void) const { return Size; }
00156 
00157   class AssignProxy {
00158   public:
00159     AssignProxy(Element_t &elem, int where)
00160       : elem_m(elem), where_m(where) { }
00161     AssignProxy(const AssignProxy &model)
00162       : elem_m(model.elem_m), where_m(where_m) { }
00163     const AssignProxy &operator=(const AssignProxy &a)
00164       {
00165         PAssert(where_m != 0 || a.elem_m == -a.elem_m);
00166         elem_m = where_m < 0 ? -a.elem_m : a.elem_m;
00167         return *this;
00168       }
00169     const AssignProxy &operator=(const Element_t &e)
00170       {
00171         PAssert(where_m != 0 || e == -e);
00172         elem_m = where_m < 0 ? -e : e;
00173         return *this;
00174       }
00175 
00176     operator Element_t() const
00177       {
00178         return (where_m < 0 ? -elem_m : elem_m);
00179       }
00180 
00181   private:
00182 
00183     mutable Element_t &elem_m;
00184     mutable int where_m;
00185   };
00186 
00187   // Operators
00188   
00189   Element_t operator()(unsigned int i, unsigned int j) const {
00190     if (i == j)
00191       return T(0.0);
00192     else if (i < j)
00193       return -X[((j-1)*j/2) + i];
00194     else
00195       return X[((i-1)*i/2) + j];
00196   }
00197 
00198   Element_t operator()( pair<int,int> a) const {
00199     int i = a.first;
00200     int j = a.second;
00201     return (*this)(i, j);
00202   }
00203 
00204   AssignProxy operator()(unsigned int i, unsigned int j) {
00205     if (i == j)
00206       return AssignProxy(AntiSymTenzor<T,D>::Zero, 0);
00207     else
00208       {
00209         int lo = i < j ? i : j;
00210         int hi = i > j ? i : j;
00211         return AssignProxy(X[((hi-1)*hi/2) + lo], i - j);
00212       }
00213   }
00214 
00215   AssignProxy operator()(pair<int,int> a) {
00216     int i = a.first;
00217     int j = a.second;
00218     return (*this)(i, j);
00219   }
00220 
00221   Element_t& operator[](unsigned int i) { 
00222     PAssert (i < Size);
00223     return X[i];
00224   }
00225 
00226   Element_t operator[](unsigned int i) const { 
00227     PAssert (i < Size);
00228     return X[i];
00229   }
00230 
00231   // These are the same as operator[] but with () instead:
00232 
00233   Element_t& operator()(unsigned int i) { 
00234     PAssert (i < Size);
00235     return X[i];
00236   }
00237 
00238   Element_t operator()(unsigned int i) const { 
00239     PAssert (i < Size);
00240     return X[i];
00241   }
00242 
00243   //----------------------------------------------------------------------
00244   // Comparison operators.
00245   bool operator==(const AntiSymTenzor<T,D>& that) const {
00246     return TSV_MetaCompareArrays<T,T,D*(D-1)/2>::apply(X,that.X);
00247   }
00248   bool operator!=(const AntiSymTenzor<T,D>& that) const {
00249     return !(*this == that);
00250   }
00251 
00252   //----------------------------------------------------------------------
00253   // parallel communication
00254   Message& putMessage(Message& m) const {
00255     m.setCopy(true);
00256     ::putMessage(m, X, X + Size);
00257     return m;
00258   }
00259 
00260   Message& getMessage(Message& m) {
00261     ::getMessage(m, X, X + Size);
00262     return m;
00263   }
00264 
00265 private:
00266 
00267   friend class AssignProxy;
00268 
00269   // The elements themselves.
00270   T X[Size];
00271 
00272   // A place to store a zero element.
00273   // We need to return a reference to this
00274   // for the diagonal element.
00275   static T Zero;
00276 };
00277 
00278 
00279 // Assign the static zero element value:
00280 template<class T, unsigned int D>
00281 T AntiSymTenzor<T,D>::Zero = 0;
00282 
00283 
00284 
00286 // Specialization for 1D  -- this is basically just the zero tensor
00288 
00289 template <class T>
00290 class AntiSymTenzor<T,1>
00291 {
00292 public:
00293 
00294   typedef T Element_t;
00295   enum { ElemDim = 2 };
00296 
00297   // Default Constructor 
00298   AntiSymTenzor() {} 
00299 
00300   // Copy Constructor 
00301   AntiSymTenzor(const AntiSymTenzor<T,1>&) {}
00302 
00303   // A noninitializing ctor.
00304   class DontInitialize {};
00305   AntiSymTenzor(DontInitialize) {}
00306 
00307   // Construct from a Tenzor: still a no-op here:
00308   AntiSymTenzor( const Tenzor<T,1>& t ) { }
00309 
00310   ~AntiSymTenzor() {}
00311 
00312   // assignment operators
00313   const AntiSymTenzor<T,1>& operator=(const AntiSymTenzor<T,1>&) {
00314     return *this;
00315   }
00316   template <class T1>
00317   const AntiSymTenzor<T,1>& operator=(const AntiSymTenzor<T1,1>&) {
00318     return *this;
00319   }
00320   const AntiSymTenzor<T,1>& operator=(const T& rhs) {
00321     PInsist(rhs==0, "Cannot assign non-zero value to a 1D AntiSymTenzor!");
00322     return *this;
00323   }
00324 
00325   // accumulation operators
00326   template <class T1>
00327   AntiSymTenzor<T,1>& operator+=(const AntiSymTenzor<T1,1>&) {
00328     return *this;
00329   }
00330 
00331   template <class T1>
00332   AntiSymTenzor<T,1>& operator-=(const AntiSymTenzor<T1,1>&) {
00333     return *this;
00334   }
00335 
00336   template <class T1>
00337   AntiSymTenzor<T,1>& operator*=(const AntiSymTenzor<T1,1>&) {
00338     return *this;
00339   }
00340   AntiSymTenzor<T,1>& operator*=(const T&) {
00341     return *this;
00342   }
00343 
00344   template <class T1>
00345   AntiSymTenzor<T,1>& operator/=(const AntiSymTenzor<T1,1>&) {
00346     return *this;
00347   }
00348   AntiSymTenzor<T,1>& operator/=(const T&) {
00349     return *this;
00350   }
00351 
00352   // Methods
00353 
00354   int len(void)  const { return Size; }
00355   int size(void) const { return sizeof(*this); }
00356   int get_Size(void) const { return Size; }
00357 
00358   class AssignProxy {
00359   public:
00360     AssignProxy(Element_t &elem, int where)
00361       : elem_m(elem), where_m(where) {}
00362     AssignProxy(const AssignProxy& model)
00363       : elem_m(model.elem_m), where_m(where_m) {}
00364     const AssignProxy& operator=(const AssignProxy& a)
00365       {
00366         PAssert(where_m != 0 || a.elem_m == -a.elem_m);
00367         elem_m = where_m < 0 ? -a.elem_m : a.elem_m;
00368         return *this;
00369       }
00370     const AssignProxy& operator=(const Element_t& e)
00371       {
00372         PAssert(where_m != 0 || e == -e);
00373         elem_m = where_m < 0 ? -e : e;
00374         return *this;
00375       }
00376 
00377     operator Element_t() const
00378       {
00379         return (where_m < 0 ? -elem_m : elem_m);
00380       }
00381 
00382   private:
00383 
00384     mutable Element_t &elem_m;
00385     mutable int where_m;
00386   };
00387 
00388   // Operators
00389   
00390   Element_t operator()(unsigned int i, unsigned int j) const {
00391     PAssert(i==j);
00392     return T(0.0);
00393   }
00394 
00395   Element_t operator()( pair<int,int> a) const {
00396     int i = a.first;
00397     int j = a.second;
00398     return (*this)(i, j);
00399   }
00400 
00401   AssignProxy operator()(unsigned int i, unsigned int j) {
00402     PAssert(i==j);
00403     return AssignProxy(AntiSymTenzor<T,1>::Zero, 0);
00404   }
00405 
00406   AssignProxy operator()(pair<int,int> a) {
00407     int i = a.first;
00408     int j = a.second;
00409     return (*this)(i, j);
00410   }
00411 
00412   Element_t operator[](unsigned int i) const { 
00413     PAssert (i == 0);
00414     return AntiSymTenzor<T,1>::Zero;
00415   }
00416 
00417   // These are the same as operator[] but with () instead:
00418 
00419   Element_t operator()(unsigned int i) const { 
00420     PAssert (i == 0);
00421     return AntiSymTenzor<T,1>::Zero;
00422   }
00423 
00424   //----------------------------------------------------------------------
00425   // Comparison operators.
00426   bool operator==(const AntiSymTenzor<T,1>& that) const {
00427     return true;
00428   }
00429   bool operator!=(const AntiSymTenzor<T,1>& that) const {
00430     return !(*this == that);
00431   }
00432 
00433   //----------------------------------------------------------------------
00434   // parallel communication
00435   Message& putMessage(Message& m) const {
00436     m.setCopy(true);
00437     m.put(AntiSymTenzor<T,1>::Zero);
00438     return m;
00439   }
00440 
00441   Message& getMessage(Message& m) {
00442     T zero;
00443     m.get(zero);
00444     return m;
00445   }
00446 
00447 private:
00448 
00449   friend class AssignProxy;
00450 
00451   // The number of elements.
00452   enum { Size = 0 };
00453 
00454   // A place to store a zero element.
00455   // We need to return a reference to this
00456   // for the diagonal element.
00457   static T Zero;
00458 };
00459 
00460 
00461 // Assign the static zero element value:
00462 template<class T>
00463 T AntiSymTenzor<T,1U>::Zero = 0;
00464 
00465 
00466 
00468 //
00469 // Free functions
00470 //
00472 
00473 template <class T, unsigned D>
00474 T trace(const AntiSymTenzor<T,D>&) {
00475   return T(0.0);
00476 }
00477 
00478 template <class T, unsigned D>
00479 AntiSymTenzor<T,D> transpose(const AntiSymTenzor<T,D>& rhs) {
00480   return -rhs;
00481 }
00482 
00483 // Determinant: only implement for 1D, 2D, 3D:
00484 
00485 // For D=3, det is zero, because diagonal elements are zero:
00486 template<class T>
00487 inline T
00488 det(const AntiSymTenzor<T,3>& t)
00489 {
00490   return T(0.0);
00491 }
00492 // For D=2, det is nonzero; use linear indexing of only stored element:
00493 template<class T>
00494 inline T
00495 det(const AntiSymTenzor<T,2>& t)
00496 {
00497   T result;
00498   result = t(0)*t(0);
00499   return result;
00500 }
00501 // For D=1, det is zero, because diagonal elements are zero:
00502 template<class T>
00503 inline T
00504 det(const AntiSymTenzor<T,1>& t)
00505 {
00506   return T(0.0);
00507 }
00508 
00509 // cofactors() - pow(-1, i+j)*M(i,j), where M(i,j) is a minor of the tensor.
00510 // See, for example, Arfken, Mathematical Methods for Physicists, 2nd Edition,
00511 // p. 157 (the section where the determinant of a matrix is defined).
00512 
00513 // Only implement for 1D, 2D, 3D:
00514 
00515 template <class T, unsigned D>
00516 Tenzor<T,D> cofactors(const AntiSymTenzor<T,D>& rhs) {
00517   PInsist(D<4, "AntiSymTenzor cofactors() function not implemented for D>3!");
00518   return Tenzor<T,D>(-999999.999999);
00519 }
00520 
00521 template <class T>
00522 Tenzor<T,3> cofactors(const AntiSymTenzor<T,3>& rhs) {
00523 // check for typename keyword bug
00524 #if (defined(IPPL_SGI_CC_721_TYPENAME_BUG) || defined(__MWERKS__))
00525   Tenzor<T,3> result = Tenzor<T,3>::DontInitialize();
00526 #else
00527   Tenzor<T,3> result = typename Tenzor<T,3>::DontInitialize();
00528 #endif
00529   result(0,0) = rhs(1,1)*rhs(2,2) - rhs(1,2)*rhs(2,1);
00530   result(1,0) = rhs(0,2)*rhs(2,1) - rhs(0,1)*rhs(2,2);
00531   result(2,0) = rhs(0,1)*rhs(1,2) - rhs(1,1)*rhs(0,2);
00532   result(0,1) = rhs(2,0)*rhs(1,2) - rhs(1,0)*rhs(2,2);
00533   result(1,1) = rhs(0,0)*rhs(2,2) - rhs(0,2)*rhs(2,0);
00534   result(2,1) = rhs(1,0)*rhs(0,2) - rhs(0,0)*rhs(1,2);
00535   result(0,2) = rhs(1,0)*rhs(2,1) - rhs(2,0)*rhs(1,1);
00536   result(1,2) = rhs(0,1)*rhs(2,0) - rhs(0,0)*rhs(2,1);
00537   result(2,2) = rhs(0,0)*rhs(1,1) - rhs(1,0)*rhs(0,1);
00538   return result;
00539 }
00540 
00541 template <class T>
00542 Tenzor<T,2> cofactors(const AntiSymTenzor<T,2>& rhs) {
00543 // check for typename keyword bug
00544 #if (defined(IPPL_SGI_CC_721_TYPENAME_BUG) || defined(__MWERKS__))
00545   Tenzor<T,2> result = Tenzor<T,2>::DontInitialize();
00546 #else
00547   Tenzor<T,2> result = typename Tenzor<T,2>::DontInitialize();
00548 #endif
00549   result(0,0) =  rhs(1,1);
00550   result(1,0) = -rhs(0,1);
00551   result(0,1) = -rhs(1,0);
00552   result(1,1) =  rhs(0,0);
00553   return result;
00554 }
00555 
00556 // For D=1, cofactor is the unit tensor, because det = single tensor element
00557 // value:
00558 template <class T>
00559 Tenzor<T,1> cofactors(const AntiSymTenzor<T,1>& rhs) {
00560   Tenzor<T,1> result = Tenzor<T,1>(1);
00561   return result;
00562 }
00563 
00564 
00566 //
00567 // Unary Operators
00568 //
00570 
00571 //----------------------------------------------------------------------
00572 // unary operator-
00573 template<class T, unsigned D>
00574 inline AntiSymTenzor<T,D> operator-(const AntiSymTenzor<T,D> &op)
00575 {
00576   return TSV_MetaUnary< AntiSymTenzor<T,D> , OpUnaryMinus > :: apply(op);
00577 }
00578 
00579 //----------------------------------------------------------------------
00580 // unary operator+
00581 template<class T, unsigned D>
00582 inline const AntiSymTenzor<T,D> &operator+(const AntiSymTenzor<T,D> &op)
00583 {
00584   return op;
00585 }
00586 
00588 //
00589 // Binary Operators
00590 //
00592 
00593 //
00594 // Elementwise operators.
00595 //
00596 
00597 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,operator+,OpAdd)
00598 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,operator-,OpSubtract)
00599 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,operator*,OpMultipply)
00600 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,operator/,OpDivide)
00601 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,Min,FnMin)
00602 TSV_ELEMENTWISE_OPERATOR(AntiSymTenzor,Max,FnMax)
00603 
00604 //----------------------------------------------------------------------
00605 // dot products.
00606 //----------------------------------------------------------------------
00607 
00608 template < class T1, class T2, unsigned D >
00609 inline Tenzor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00610 dot(const AntiSymTenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00611 {
00612   return TSV_MetaDot< AntiSymTenzor<T1,D> , AntiSymTenzor<T2,D> > :: 
00613     apply(lhs,rhs);
00614 }
00615 
00616 template < class T1, class T2, unsigned D >
00617 inline Tenzor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00618 dot(const AntiSymTenzor<T1,D> &lhs, const Tenzor<T2,D> &rhs) 
00619 {
00620   return TSV_MetaDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00621     apply(Tenzor<T1,D>(lhs),rhs);
00622 }
00623 
00624 template < class T1, class T2, unsigned D >
00625 inline Tenzor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00626 dot(const Tenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00627 {
00628   return TSV_MetaDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00629     apply(lhs,Tenzor<T2,D>(rhs));
00630 }
00631 
00632 template < class T1, class T2, unsigned D >
00633 inline Tenzor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00634 dot(const AntiSymTenzor<T1,D> &lhs, const SymTenzor<T2,D> &rhs) 
00635 {
00636   return TSV_MetaDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00637     apply(Tenzor<T1,D>(lhs),Tenzor<T2,D>(rhs));
00638 }
00639 
00640 template < class T1, class T2, unsigned D >
00641 inline Tenzor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00642 dot(const SymTenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00643 {
00644   return TSV_MetaDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00645     apply(Tenzor<T1,D>(lhs),Tenzor<T2,D>(rhs));
00646 }
00647 
00648 template < class T1, class T2, unsigned D >
00649 inline Vektor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00650 dot(const Vektor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00651 {
00652   return TSV_MetaDot< Vektor<T1,D> , AntiSymTenzor<T2,D> > :: apply(lhs,rhs);
00653 }
00654 
00655 template < class T1, class T2, unsigned D >
00656 inline Vektor<typename PETEBinaryReturn<T1,T2,OpMultipply>::type,D>
00657 dot(const AntiSymTenzor<T1,D> &lhs, const Vektor<T2,D> &rhs) 
00658 {
00659   return TSV_MetaDot< AntiSymTenzor<T1,D> , Vektor<T2,D> > :: apply(lhs,rhs);
00660 }
00661 
00662 //----------------------------------------------------------------------
00663 // double dot products.
00664 //----------------------------------------------------------------------
00665 
00666 template < class T1, class T2, unsigned D >
00667 inline typename PETEBinaryReturn<T1,T2,OpMultipply>::type
00668 dotdot(const AntiSymTenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00669 {
00670   return TSV_MetaDotDot< AntiSymTenzor<T1,D> , AntiSymTenzor<T2,D> > :: 
00671     apply(lhs,rhs);
00672 }
00673 
00674 template < class T1, class T2, unsigned D >
00675 inline typename PETEBinaryReturn<T1,T2,OpMultipply>::type
00676 dotdot(const AntiSymTenzor<T1,D> &lhs, const Tenzor<T2,D> &rhs) 
00677 {
00678   return TSV_MetaDotDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00679     apply(Tenzor<T1,D>(lhs),rhs);
00680 }
00681 
00682 template < class T1, class T2, unsigned D >
00683 inline typename PETEBinaryReturn<T1,T2,OpMultipply>::type
00684 dotdot(const Tenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00685 {
00686   return TSV_MetaDotDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00687     apply(lhs,Tenzor<T2,D>(rhs));
00688 }
00689 
00690 template < class T1, class T2, unsigned D >
00691 inline typename PETEBinaryReturn<T1,T2,OpMultipply>::type
00692 dotdot(const AntiSymTenzor<T1,D> &lhs, const SymTenzor<T2,D> &rhs) 
00693 {
00694   return TSV_MetaDotDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00695     apply(Tenzor<T1,D>(lhs),Tenzor<T2,D>(rhs));
00696 }
00697 
00698 template < class T1, class T2, unsigned D >
00699 inline typename PETEBinaryReturn<T1,T2,OpMultipply>::type
00700 dotdot(const SymTenzor<T1,D> &lhs, const AntiSymTenzor<T2,D> &rhs) 
00701 {
00702   return TSV_MetaDotDot< Tenzor<T1,D> , Tenzor<T2,D> > :: 
00703     apply(Tenzor<T1,D>(lhs),Tenzor<T2,D>(rhs));
00704 }
00705 
00706 //----------------------------------------------------------------------
00707 // I/O
00708 template<class T, unsigned D>
00709 ostream& operator<<(ostream& out, const AntiSymTenzor<T,D>& rhs) {
00710   if (D >= 1) {
00711     for (int i=0; i<D; i++) {
00712       out << "(";
00713       for (int j=0; j<D-1; j++) {
00714         out << rhs(i,j) << " , ";
00715       }
00716       out << rhs(i,D-1) << ")";
00717       // I removed this. --TJW: if (i < D - 1) out << endl;
00718     }
00719   } else {
00720     out << "( " << rhs(0,0) << " )";
00721   }
00722   return out;
00723 }
00724 
00726 
00727 #endif // ANTI_SYM_TENZOR_H
00728 
00729 /***************************************************************************
00730  * $RCSfile: AntiSymTenzor.h,v $
00731  * $Revision: 1.1.1.1 $
00732  * IPPL_VERSION_ID: $Id: AntiSymTenzor.h,v 1.1.1.1 2003/01/23 07:40:24 adelmann Exp $
00733  ***************************************************************************/
00734 

Generated on Fri Nov 2 01:25:54 2007 for IPPL by doxygen 1.3.5