00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef ANTI_SYM_TENZOR_H
00012 #define ANTI_SYM_TENZOR_H
00013
00014
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
00032
00034
00035
00036
00037
00038
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
00051 AntiSymTenzor() {
00052 TSV_MetaAssignScalar< AntiSymTenzor<T,D>,T,OpAssign>::apply(*this,T(0));
00053 }
00054
00055
00056 class DontInitialize {};
00057 AntiSymTenzor(DontInitialize) {}
00058
00059
00060
00061 AntiSymTenzor(const T& x00) {
00062 TSV_MetaAssignScalar< AntiSymTenzor<T,D>,T,OpAssign>::apply(*this,x00);
00063 }
00064
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
00072 AntiSymTenzor(const AntiSymTenzor<T,D> &rhs) {
00073 TSV_MetaAssign< AntiSymTenzor<T,D> , AntiSymTenzor<T,D> ,OpAssign > ::
00074 apply(*this,rhs);
00075 }
00076
00077
00078
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
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
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
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
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
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
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
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
00270 T X[Size];
00271
00272
00273
00274
00275 static T Zero;
00276 };
00277
00278
00279
00280 template<class T, unsigned int D>
00281 T AntiSymTenzor<T,D>::Zero = 0;
00282
00283
00284
00286
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
00298 AntiSymTenzor() {}
00299
00300
00301 AntiSymTenzor(const AntiSymTenzor<T,1>&) {}
00302
00303
00304 class DontInitialize {};
00305 AntiSymTenzor(DontInitialize) {}
00306
00307
00308 AntiSymTenzor( const Tenzor<T,1>& t ) { }
00309
00310 ~AntiSymTenzor() {}
00311
00312
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
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
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
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
00418
00419 Element_t operator()(unsigned int i) const {
00420 PAssert (i == 0);
00421 return AntiSymTenzor<T,1>::Zero;
00422 }
00423
00424
00425
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
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
00452 enum { Size = 0 };
00453
00454
00455
00456
00457 static T Zero;
00458 };
00459
00460
00461
00462 template<class T>
00463 T AntiSymTenzor<T,1U>::Zero = 0;
00464
00465
00466
00468
00469
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
00484
00485
00486 template<class T>
00487 inline T
00488 det(const AntiSymTenzor<T,3>& t)
00489 {
00490 return T(0.0);
00491 }
00492
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
00502 template<class T>
00503 inline T
00504 det(const AntiSymTenzor<T,1>& t)
00505 {
00506 return T(0.0);
00507 }
00508
00509
00510
00511
00512
00513
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