Skip to content
Snippets Groups Projects
Select Git revision
  • 60bf5dec90d1e21db996283625347d220e2f494a
  • master default protected
  • alphashapes
  • quadMeshingTools
  • cygwin_conv_path
  • macos_arm64
  • add-transfiniteautomatic-to-geo
  • patch_releases_4_10
  • HierarchicalHDiv
  • isuruf-master-patch-63355
  • hyperbolic
  • hexdom
  • hxt_update
  • jf
  • 1618-pythonocc-and-gmsh-api-integration
  • octreeSizeField
  • hexbl
  • alignIrregularVertices
  • getEdges
  • patch_releases_4_8
  • isuruf-master-patch-51992
  • gmsh_4_11_0
  • gmsh_4_10_5
  • gmsh_4_10_4
  • gmsh_4_10_3
  • gmsh_4_10_2
  • gmsh_4_10_1
  • gmsh_4_10_0
  • gmsh_4_9_5
  • gmsh_4_9_4
  • gmsh_4_9_3
  • gmsh_4_9_2
  • gmsh_4_9_1
  • gmsh_4_9_0
  • gmsh_4_8_4
  • gmsh_4_8_3
  • gmsh_4_8_2
  • gmsh_4_8_1
  • gmsh_4_8_0
  • gmsh_4_7_1
  • gmsh_4_7_0
41 results

t21.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    Cal_Value.cpp 81.96 KiB
    // GetDP - Copyright (C) 1997-2018 P. Dular and C. Geuzaine, University of Liege
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to the public mailing list <getdp@onelab.info>.
    //
    // Contributor(s):
    //   Johan Gyselinck
    //
    
    #include <sstream>
    #include <string.h>
    #include <math.h>
    #include "ProData.h"
    #include "ProDefine.h"
    #include "Cal_Value.h"
    #include "Message.h"
    
    extern struct CurrentData Current ;
    
    #define SQU(a)     ((a)*(a))
    
    /* ------------------------------------------------------------------------ */
    /*  O p e r a t o r s   o n   V a l u e s                                   */
    /* ------------------------------------------------------------------------ */
    /* Warning: the pointers V1 and R or V2 and R can be identical. You must    */
    /*          use temporary variables in your computations: you can only      */
    /*          affect to R at the very last time (when you're sure you will    */
    /*          not use V1 or V2 any more).                                     */
    /* ------------------------------------------------------------------------ */
    
    static double  a0;
    static double  a1     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  a2     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  b1     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  b2     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  b3     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  c1     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  c2     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  c3     [NBR_MAX_HARMONIC * MAX_DIM] ;
    static double  tmp[27][NBR_MAX_HARMONIC * MAX_DIM] ;
    
    static int TENSOR_SYM_MAP[]  = {0,1,2,1,3,4,2,4,5};
    static int TENSOR_DIAG_MAP[] = {0,-1,-1,-1,1,-1,-1,-1,2};
    
    void Cal_ComplexProduct(double V1[], double V2[], double P[])
    {
      P[0]       = V1[0] * V2[0]       - V1[MAX_DIM] * V2[MAX_DIM] ;
      P[MAX_DIM] = V1[0] * V2[MAX_DIM] + V1[MAX_DIM] * V2[0] ;
    }
    
    void Cal_ComplexDivision(double V1[], double V2[], double P[])
    {
      double Mod2 ;
    
      Mod2       = SQU(V2[0]) + SQU(V2[MAX_DIM]) ;
      if(!Mod2){ Message::Error("Division by zero in 'Cal_ComplexDivision'"); return; }
      P[0]       = (  V1[0] * V2[0]       + V1[MAX_DIM] * V2[MAX_DIM]) / Mod2 ;
      P[MAX_DIM] = (- V1[0] * V2[MAX_DIM] + V1[MAX_DIM] * V2[0])       / Mod2 ;
    }
    
    void Cal_ComplexInvert(double V1[], double P[])
    {
      double Mod2 ;
    
      Mod2       = SQU(V1[0]) + SQU(V1[MAX_DIM]) ;
      if(!Mod2){ Message::Error("Division by zero in 'Cal_ComplexInvert'"); return; }
      P[0]       =   V1[0]       / Mod2 ;
      P[MAX_DIM] = - V1[MAX_DIM] / Mod2 ;
    }
    
    /* ------------------------------------------------------------------------
       R <- V1
       ------------------------------------------------------------------------ */
    
    void Cal_CopyValue(struct Value * V1, struct Value * R)
    {
      int  k ;
    
      if (V1->Type == SCALAR) {
        R->Type = SCALAR ;
        for (k = 0 ; k < Current.NbrHar ; k++)
          R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] ;
      }
      else if (V1->Type == VECTOR || V1->Type == TENSOR_DIAG){
        R->Type = V1->Type ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] ;
        }
      }
      else if (V1->Type == TENSOR_SYM){
        R->Type = TENSOR_SYM ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] ;
          R->Val[MAX_DIM*k+3] = V1->Val[MAX_DIM*k+3] ;
          R->Val[MAX_DIM*k+4] = V1->Val[MAX_DIM*k+4] ;
          R->Val[MAX_DIM*k+5] = V1->Val[MAX_DIM*k+5] ;
        }
      }
      else if (V1->Type == TENSOR){
        R->Type = TENSOR ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] ;
          R->Val[MAX_DIM*k+3] = V1->Val[MAX_DIM*k+3] ;
          R->Val[MAX_DIM*k+4] = V1->Val[MAX_DIM*k+4] ;
          R->Val[MAX_DIM*k+5] = V1->Val[MAX_DIM*k+5] ;
          R->Val[MAX_DIM*k+6] = V1->Val[MAX_DIM*k+6] ;
          R->Val[MAX_DIM*k+7] = V1->Val[MAX_DIM*k+7] ;
          R->Val[MAX_DIM*k+8] = V1->Val[MAX_DIM*k+8] ;
        }
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- 0
       ------------------------------------------------------------------------ */
    
    //static double VALUE_ZERO [NBR_MAX_HARMONIC * MAX_DIM] =
    // {0.,0.,0., 0.,0.,0.,
    //  0.,0.,0., 0.,0.,0.,
    //  0.,0.,0., 0.,0.,0.} ;
    
    void Cal_ZeroValue(struct Value * R)
    {
      //memcpy(R->Val, VALUE_ZERO, Current.NbrHar*MAX_DIM*sizeof(double));
      for(int i = 0; i < Current.NbrHar*MAX_DIM; i++) R->Val[i] = 0.;
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 + V2
       ------------------------------------------------------------------------ */
    
    #define ADD(i)   R->Val[i] = V1->Val[i] + V2->Val[i]
    #define CADD(i)  R->Val[MAX_DIM*k+i] = V1->Val[MAX_DIM*k+i] + V2->Val[MAX_DIM*k+i]
    
    void Cal_AddValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int           i, k;
      int           i1,i2;
      struct Value  A;
    
      if (V1->Type == SCALAR && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          ADD(0);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CADD(0);
          }
        }
        R->Type = SCALAR ;
      }
    
      else if ((V1->Type == VECTOR      && V2->Type == VECTOR) ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR_DIAG)) {
        if (Current.NbrHar == 1) {
          ADD(0); ADD(1); ADD(2);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CADD(0); CADD(1); CADD(2);
          }
        }
        R->Type = V1->Type;
      }
    
      else if (V1->Type == TENSOR_SYM && V2->Type == TENSOR_SYM) {
        if (Current.NbrHar == 1) {
          ADD(0); ADD(1); ADD(2); ADD(3); ADD(4); ADD(5);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CADD(0); CADD(1); CADD(2); CADD(3); CADD(4); CADD(5);
          }
        }
        R->Type = TENSOR_SYM;
      }
    
      else if (V1->Type == TENSOR && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          ADD(0); ADD(1); ADD(2); ADD(3); ADD(4); ADD(5); ADD(6); ADD(7); ADD(8);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CADD(0); CADD(1); CADD(2); CADD(3); CADD(4); CADD(5); CADD(6); CADD(7); CADD(8);
          }
        }
        R->Type = TENSOR;
      }
    
      else if ((V1->Type == TENSOR     && V2->Type == TENSOR_SYM) ||
    	   (V1->Type == TENSOR     && V2->Type == TENSOR_DIAG)||
    	   (V1->Type == TENSOR_SYM && V2->Type == TENSOR_DIAG)){
        A.Type = V1->Type;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          for(i=0 ; i<9 ; i++){
    	i1 = (V1->Type==TENSOR)?i:TENSOR_SYM_MAP[i];
    	i2 = (V2->Type==TENSOR_SYM)?TENSOR_SYM_MAP[i]:TENSOR_DIAG_MAP[i];
    	A.Val[MAX_DIM*k+i1] =
    	  V1->Val[MAX_DIM*k+i1] + ((i2<0)?0.0:V2->Val[MAX_DIM*k+i2]);
          }
        }
        Cal_CopyValue(&A,R);
      }
    
      else if ((V1->Type == TENSOR_SYM  && V2->Type == TENSOR)      ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR)      ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR_SYM)){
        A.Type = V2->Type;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          for(i=0 ; i<9 ; i++){
    	i1 = (V1->Type==TENSOR_SYM)?TENSOR_SYM_MAP[i]:TENSOR_DIAG_MAP[i];
    	i2 = (V2->Type==TENSOR)?i:TENSOR_SYM_MAP[i];
    	A.Val[MAX_DIM*k+i2] =
    	  ((i1<0)?0.0:V1->Val[MAX_DIM*k+i1]) + V2->Val[MAX_DIM*k+i2];
          }
        }
        Cal_CopyValue(&A,R);
      }
    
      else {
        Message::Error("Addition of different quantities: %s + %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    #undef ADD
    #undef CADD
    
    /* ------------------------------------------------------------------------
       R <- V1 * d ,   where d is a double
       ------------------------------------------------------------------------ */
    
    void Cal_MultValue(struct Value * V1, double d, struct Value * R)
    {
      int k;
    
      R->Type = V1->Type ;
    
      switch(V1->Type){
      case SCALAR :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k] = V1->Val[MAX_DIM*k] * d;
          }
        }
        break;
      case VECTOR :
      case TENSOR_DIAG :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0] * d;
          R->Val[1] = V1->Val[1] * d;
          R->Val[2] = V1->Val[2] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] * d;
    	R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] * d;
    	R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] * d;
          }
        }
        break;
      case TENSOR_SYM :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0] * d;
          R->Val[1] = V1->Val[1] * d;
          R->Val[2] = V1->Val[2] * d;
          R->Val[3] = V1->Val[3] * d;
          R->Val[4] = V1->Val[4] * d;
          R->Val[5] = V1->Val[5] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] * d;
    	R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] * d;
    	R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] * d;
    	R->Val[MAX_DIM*k+3] = V1->Val[MAX_DIM*k+3] * d;
    	R->Val[MAX_DIM*k+4] = V1->Val[MAX_DIM*k+4] * d;
    	R->Val[MAX_DIM*k+5] = V1->Val[MAX_DIM*k+5] * d;
          }
        }
        break;
      case TENSOR :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0] * d;
          R->Val[1] = V1->Val[1] * d;
          R->Val[2] = V1->Val[2] * d;
          R->Val[3] = V1->Val[3] * d;
          R->Val[4] = V1->Val[4] * d;
          R->Val[5] = V1->Val[5] * d;
          R->Val[6] = V1->Val[6] * d;
          R->Val[7] = V1->Val[7] * d;
          R->Val[8] = V1->Val[8] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] * d;
    	R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] * d;
    	R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] * d;
    	R->Val[MAX_DIM*k+3] = V1->Val[MAX_DIM*k+3] * d;
    	R->Val[MAX_DIM*k+4] = V1->Val[MAX_DIM*k+4] * d;
    	R->Val[MAX_DIM*k+5] = V1->Val[MAX_DIM*k+5] * d;
    	R->Val[MAX_DIM*k+6] = V1->Val[MAX_DIM*k+6] * d;
    	R->Val[MAX_DIM*k+7] = V1->Val[MAX_DIM*k+7] * d;
    	R->Val[MAX_DIM*k+8] = V1->Val[MAX_DIM*k+8] * d;
          }
        }
        break;
      default :
        Message::Error("Wrong argument type for 'Cal_MultValue'");
        break;
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 + V2 * d ,   where d is a double
       ------------------------------------------------------------------------ */
    
    void Cal_AddMultValue(struct Value * V1, struct Value * V2, double d, struct Value * R)
    {
      int k;
      struct Value A ;
    
      A.Type = V2->Type ;
    
      switch(V2->Type){
      case SCALAR :
        if (Current.NbrHar == 1) {
          A.Val[0] = V2->Val[0] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	A.Val[MAX_DIM*k] = V2->Val[MAX_DIM*k] * d;
          }
        }
        break;
      case VECTOR :
      case TENSOR_DIAG :
        if (Current.NbrHar == 1) {
          A.Val[0] = V2->Val[0] * d;
          A.Val[1] = V2->Val[1] * d;
          A.Val[2] = V2->Val[2] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	A.Val[MAX_DIM*k  ] = V2->Val[MAX_DIM*k  ] * d;
    	A.Val[MAX_DIM*k+1] = V2->Val[MAX_DIM*k+1] * d;
    	A.Val[MAX_DIM*k+2] = V2->Val[MAX_DIM*k+2] * d;
          }
        }
        break;
      case TENSOR_SYM :
        if (Current.NbrHar == 1) {
          A.Val[0] = V2->Val[0] * d;
          A.Val[1] = V2->Val[1] * d;
          A.Val[2] = V2->Val[2] * d;
          A.Val[3] = V2->Val[3] * d;
          A.Val[4] = V2->Val[4] * d;
          A.Val[5] = V2->Val[5] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	A.Val[MAX_DIM*k  ] = V2->Val[MAX_DIM*k  ] * d;
    	A.Val[MAX_DIM*k+1] = V2->Val[MAX_DIM*k+1] * d;
    	A.Val[MAX_DIM*k+2] = V2->Val[MAX_DIM*k+2] * d;
    	A.Val[MAX_DIM*k+3] = V2->Val[MAX_DIM*k+3] * d;
    	A.Val[MAX_DIM*k+4] = V2->Val[MAX_DIM*k+4] * d;
    	A.Val[MAX_DIM*k+5] = V2->Val[MAX_DIM*k+5] * d;
          }
        }
        break;
      case TENSOR :
        if (Current.NbrHar == 1) {
          A.Val[0] = V2->Val[0] * d;
          A.Val[1] = V2->Val[1] * d;
          A.Val[2] = V2->Val[2] * d;
          A.Val[3] = V2->Val[3] * d;
          A.Val[4] = V2->Val[4] * d;
          A.Val[5] = V2->Val[5] * d;
          A.Val[6] = V2->Val[6] * d;
          A.Val[7] = V2->Val[7] * d;
          A.Val[8] = V2->Val[8] * d;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	A.Val[MAX_DIM*k  ] = V2->Val[MAX_DIM*k  ] * d;
    	A.Val[MAX_DIM*k+1] = V2->Val[MAX_DIM*k+1] * d;
    	A.Val[MAX_DIM*k+2] = V2->Val[MAX_DIM*k+2] * d;
    	A.Val[MAX_DIM*k+3] = V2->Val[MAX_DIM*k+3] * d;
    	A.Val[MAX_DIM*k+4] = V2->Val[MAX_DIM*k+4] * d;
    	A.Val[MAX_DIM*k+5] = V2->Val[MAX_DIM*k+5] * d;
    	A.Val[MAX_DIM*k+6] = V2->Val[MAX_DIM*k+6] * d;
    	A.Val[MAX_DIM*k+7] = V2->Val[MAX_DIM*k+7] * d;
    	A.Val[MAX_DIM*k+8] = V2->Val[MAX_DIM*k+8] * d;
          }
        }
        break;
      default :
        Message::Error("Wrong argument type for 'Cal_AddMultValue'");
        return;
      }
      Cal_AddValue(V1,&A,R);
    }
    
    /* ------------------------------------------------------------------------
       V1 <- V1 * d1 + V2 * d2 ,   where d1, d2 are doubles
       ------------------------------------------------------------------------ */
    
    void Cal_AddMultValue2(struct Value * V1, double d1,
    		       struct Value * V2, double d2)
    {
      int k;
    
      switch(V1->Type){
      case SCALAR :
        if (Current.NbrHar == 1) {
          V1->Val[0] = V1->Val[0] * d1 + V2->Val[0] * d2;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	V1->Val[MAX_DIM*k] = V1->Val[MAX_DIM*k] * d1 + V2->Val[MAX_DIM*k] * d2;
          }
        }
        break;
      case VECTOR :
      case TENSOR_DIAG :
        if (Current.NbrHar == 1) {
          V1->Val[0] = V1->Val[0] * d1 + V2->Val[0] * d2;
          V1->Val[1] = V1->Val[1] * d1 + V2->Val[1] * d2;
          V1->Val[2] = V1->Val[2] * d1 + V2->Val[2] * d2;
        }
        else{
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	V1->Val[MAX_DIM*k  ] = V1->Val[MAX_DIM*k  ] * d1 + V2->Val[MAX_DIM*k  ] * d2;
    	V1->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+1] * d1 + V2->Val[MAX_DIM*k+1] * d2;
    	V1->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+2] * d1 + V2->Val[MAX_DIM*k+2] * d2;
          }
        }
        break;
      default :
        Message::Error("Wrong argument type for 'Cal_AddMultValue2'");
        break;
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 - V2
       ------------------------------------------------------------------------ */
    
    #define SUB(i)   R->Val[i] = V1->Val[i] - V2->Val[i]
    #define CSUB(i)  R->Val[MAX_DIM*k+i] = V1->Val[MAX_DIM*k+i] - V2->Val[MAX_DIM*k+i]
    
    void Cal_SubstractValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int           i, k;
      int           i1, i2;
      struct Value  A;
    
      if (V1->Type == SCALAR && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          SUB(0);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CSUB(0);
          }
        }
        R->Type = SCALAR ;
      }
    
      else if ((V1->Type == VECTOR      && V2->Type == VECTOR) ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR_DIAG)) {
        if (Current.NbrHar == 1) {
          SUB(0); SUB(1); SUB(2);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CSUB(0); CSUB(1); CSUB(2);
          }
        }
        R->Type = V1->Type ;
      }
    
      else if (V1->Type == TENSOR_SYM && V2->Type == TENSOR_SYM) {
        if (Current.NbrHar == 1) {
          SUB(0); SUB(1); SUB(2); SUB(3); SUB(4); SUB(5);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CSUB(0); CSUB(1); CSUB(2); CSUB(3); CSUB(4); CSUB(5);
          }
        }
        R->Type = TENSOR_SYM;
      }
    
      else if (V1->Type == TENSOR && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          SUB(0); SUB(1); SUB(2); SUB(3); SUB(4); SUB(5); SUB(6); SUB(7); SUB(8);
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	CSUB(0); CSUB(1); CSUB(2); CSUB(3); CSUB(4); CSUB(5); CSUB(6); CSUB(7); CSUB(8);
          }
        }
        R->Type = TENSOR;
      }
    
      else if ((V1->Type == TENSOR     && V2->Type == TENSOR_SYM) ||
    	   (V1->Type == TENSOR     && V2->Type == TENSOR_DIAG)||
    	   (V1->Type == TENSOR_SYM && V2->Type == TENSOR_DIAG)){
        A.Type = V1->Type;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          for(i=0 ; i<9 ; i++){
    	i1 = (V1->Type==TENSOR)?i:TENSOR_SYM_MAP[i];
    	i2 = (V2->Type==TENSOR_SYM)?TENSOR_SYM_MAP[i]:TENSOR_DIAG_MAP[i];
    	A.Val[MAX_DIM*k+i1] =
    	  V1->Val[MAX_DIM*k+i1] - ((i2<0)?0.0:V2->Val[MAX_DIM*k+i2]);
          }
        }
        Cal_CopyValue(&A,R);
      }
    
      else if ((V1->Type == TENSOR_SYM  && V2->Type == TENSOR)      ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR)      ||
    	   (V1->Type == TENSOR_DIAG && V2->Type == TENSOR_SYM)){
        A.Type = V2->Type;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          for(i=0 ; i<9 ; i++){
    	i1 = (V1->Type==TENSOR_SYM)?TENSOR_SYM_MAP[i]:TENSOR_DIAG_MAP[i];
    	i2 = (V2->Type==TENSOR)?i:TENSOR_SYM_MAP[i];
    	A.Val[MAX_DIM*k+i2] =
    	  ((i1<0)?0.0:V1->Val[MAX_DIM*k+i1]) - V2->Val[MAX_DIM*k+i2];
          }
        }
        Cal_CopyValue(&A,R);
      }
    
      else {
        Message::Error("Substraction of different quantities: %s - %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    #undef SUB
    #undef CSUB
    
    /* ------------------------------------------------------------------------
       R <- V1 * V2
       ------------------------------------------------------------------------ */
    
    #define CMULT(a,b,c)								\
      Cal_ComplexProduct(&(V1->Val[MAX_DIM*k+a]), &(V2->Val[MAX_DIM*k+b]), tmp[c])
    
    #define CPUT(a)					\
      R->Val[MAX_DIM* k   +a] = tmp[a][0] ;		\
      R->Val[MAX_DIM*(k+1)+a] = tmp[a][MAX_DIM]
    
    #define CPUT3(a,b,c,d)								\
      R->Val[MAX_DIM* k   +d] = tmp[a][0]      +tmp[b][0]      +tmp[c][0] ;		\
      R->Val[MAX_DIM*(k+1)+d] = tmp[a][MAX_DIM]+tmp[b][MAX_DIM]+tmp[c][MAX_DIM]
    
    void Cal_ProductValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int k;
    
      if (V1->Type == SCALAR && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]*V2->Val[0];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0);
    	CPUT(0);
          }
        }
        R->Type = SCALAR ;
      }
    
      else if (V1->Type == SCALAR && (V2->Type == VECTOR || V2->Type == TENSOR_DIAG)) {
        if (Current.NbrHar == 1) {
          a0 = V1->Val[0] ;
          R->Val[0] = a0 * V2->Val[0] ;
          R->Val[1] = a0 * V2->Val[1] ;
          R->Val[2] = a0 * V2->Val[2] ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(0,1,1); CMULT(0,2,2);
    	CPUT(0); CPUT(1); CPUT(2);
          }
        }
        R->Type = V2->Type ;
      }
    
      else if (V1->Type == SCALAR && V2->Type == TENSOR_SYM) {
        if (Current.NbrHar == 1) {
          a0 = V1->Val[0] ;
          R->Val[0] = a0 * V2->Val[0] ;
          R->Val[1] = a0 * V2->Val[1] ;
          R->Val[2] = a0 * V2->Val[2] ;
          R->Val[3] = a0 * V2->Val[3] ;
          R->Val[4] = a0 * V2->Val[4] ;
          R->Val[5] = a0 * V2->Val[5] ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(0,1,1); CMULT(0,2,2); CMULT(0,3,3); CMULT(0,4,4); CMULT(0,5,5);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
          }
        }
        R->Type = TENSOR_SYM ;
      }
    
      else if (V1->Type == SCALAR && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          a0 = V1->Val[0] ;
          R->Val[0] = a0 * V2->Val[0] ;
          R->Val[1] = a0 * V2->Val[1] ;
          R->Val[2] = a0 * V2->Val[2] ;
          R->Val[3] = a0 * V2->Val[3] ;
          R->Val[4] = a0 * V2->Val[4] ;
          R->Val[5] = a0 * V2->Val[5] ;
          R->Val[6] = a0 * V2->Val[6] ;
          R->Val[7] = a0 * V2->Val[7] ;
          R->Val[8] = a0 * V2->Val[8] ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(0,1,1); CMULT(0,2,2); CMULT(0,3,3); CMULT(0,4,4); CMULT(0,5,5);
    	CMULT(0,6,6); CMULT(0,7,7); CMULT(0,8,8);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
    	CPUT(6); CPUT(7); CPUT(8);
          }
        }
        R->Type = TENSOR ;
      }
    
      else if ((V1->Type == VECTOR || V1->Type == TENSOR_DIAG) && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] * a0 ;
          R->Val[1] = V1->Val[1] * a0 ;
          R->Val[2] = V1->Val[2] * a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,0,1); CMULT(2,0,2);
    	CPUT(0); CPUT(1); CPUT(2);
          }
        }
        R->Type = V1->Type ;
      }
    
      else if (V1->Type == TENSOR_SYM && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] * a0 ;
          R->Val[1] = V1->Val[1] * a0 ;
          R->Val[2] = V1->Val[2] * a0 ;
          R->Val[3] = V1->Val[3] * a0 ;
          R->Val[4] = V1->Val[4] * a0 ;
          R->Val[5] = V1->Val[5] * a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,0,1); CMULT(2,0,2); CMULT(3,0,3); CMULT(4,0,4); CMULT(5,0,5);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
          }
        }
        R->Type = TENSOR_SYM ;
      }
    
      else if (V1->Type == TENSOR && V2->Type == SCALAR) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] * a0 ;
          R->Val[1] = V1->Val[1] * a0 ;
          R->Val[2] = V1->Val[2] * a0 ;
          R->Val[3] = V1->Val[3] * a0 ;
          R->Val[4] = V1->Val[4] * a0 ;
          R->Val[5] = V1->Val[5] * a0 ;
          R->Val[6] = V1->Val[6] * a0 ;
          R->Val[7] = V1->Val[7] * a0 ;
          R->Val[8] = V1->Val[8] * a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,0,1); CMULT(2,0,2); CMULT(3,0,3); CMULT(4,0,4); CMULT(5,0,5);
    	CMULT(6,0,6); CMULT(7,0,7); CMULT(8,0,8);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
    	CPUT(6); CPUT(7); CPUT(8);
          }
        }
        R->Type = TENSOR ;
      }
    
      /* Scalar Product. See 'Cal_CrossProductValue' for the Vector Product */
    
      else if (V1->Type == VECTOR && V2->Type == VECTOR) {
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0] * V2->Val[0] +
                      V1->Val[1] * V2->Val[1] +
    	          V1->Val[2] * V2->Val[2] ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,1,1); CMULT(2,2,2);
    	CPUT3(0,1,2,0);
          }
        }
        R->Type = SCALAR ;
      }
    
      else if ( (V1->Type == TENSOR_DIAG && V2->Type == VECTOR) ||
    	    (V2->Type == TENSOR_DIAG && V1->Type == VECTOR) ) { /* WARNING WARNING! */
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]*V2->Val[0];
          R->Val[1] = V1->Val[1]*V2->Val[1];
          R->Val[2] = V1->Val[2]*V2->Val[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,1,1); CMULT(2,2,2);
    	CPUT(0); CPUT(1); CPUT(2);
          }
        }
        R->Type = VECTOR ;
      }
    
      else if (V1->Type == TENSOR_SYM && V2->Type == VECTOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[1] + V1->Val[2]*V2->Val[2];
          a1[1] = V1->Val[1]*V2->Val[0] + V1->Val[3]*V2->Val[1] + V1->Val[4]*V2->Val[2];
          a1[2] = V1->Val[2]*V2->Val[0] + V1->Val[4]*V2->Val[1] + V1->Val[5]*V2->Val[2];
          R->Val[0] = a1[0];
          R->Val[1] = a1[1];
          R->Val[2] = a1[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,1,1); CMULT(2,2,2);
    	CMULT(1,0,3); CMULT(3,1,4); CMULT(4,2,5);
    	CMULT(2,0,6); CMULT(4,1,7); CMULT(5,2,8);
    	CPUT3(0,1,2,0);
    	CPUT3(3,4,5,1);
    	CPUT3(6,7,8,2);
          }
        }
        R->Type = VECTOR ;
      }
    
      else if (V1->Type == TENSOR && V2->Type == VECTOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[1] + V1->Val[2]*V2->Val[2];
          a1[1] = V1->Val[3]*V2->Val[0] + V1->Val[4]*V2->Val[1] + V1->Val[5]*V2->Val[2];
          a1[2] = V1->Val[6]*V2->Val[0] + V1->Val[7]*V2->Val[1] + V1->Val[8]*V2->Val[2];
          R->Val[0] = a1[0];
          R->Val[1] = a1[1];
          R->Val[2] = a1[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,1,1); CMULT(2,2,2);
    	CMULT(3,0,3); CMULT(4,1,4); CMULT(5,2,5);
    	CMULT(6,0,6); CMULT(7,1,7); CMULT(8,2,8);
    	CPUT3(0,1,2,0);
    	CPUT3(3,4,5,1);
    	CPUT3(6,7,8,2);
          }
        }
        R->Type = VECTOR ;
      }
      
      else if (V1->Type == VECTOR && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[3] + V1->Val[2]*V2->Val[6];
          a1[1] = V1->Val[0]*V2->Val[1] + V1->Val[1]*V2->Val[4] + V1->Val[2]*V2->Val[7];
          a1[2] = V1->Val[0]*V2->Val[2] + V1->Val[1]*V2->Val[5] + V1->Val[2]*V2->Val[8];
          R->Val[0] = a1[0];
          R->Val[1] = a1[1];
          R->Val[2] = a1[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
            CMULT(0,0,0); CMULT(0,1,1); CMULT(0,2,2);
            CMULT(1,3,3); CMULT(1,4,4); CMULT(1,5,5);
            CMULT(2,6,6); CMULT(2,7,7); CMULT(2,8,8);
            CPUT3(0,3,6,0);
            CPUT3(1,4,7,1);
            CPUT3(2,5,8,2);
          }
        }
        R->Type = VECTOR ;
      }
    
      else if (V1->Type == TENSOR && V2->Type == TENSOR_DIAG) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0];
          a1[1] = V1->Val[1]*V2->Val[1];
          a1[2] = V1->Val[2]*V2->Val[2];
          a1[3] = V1->Val[3]*V2->Val[0];
          a1[4] = V1->Val[4]*V2->Val[1];
          a1[5] = V1->Val[5]*V2->Val[2];
          a1[6] = V1->Val[6]*V2->Val[0];
          a1[7] = V1->Val[7]*V2->Val[1];
          a1[8] = V1->Val[8]*V2->Val[2];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
    
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0);
    	CMULT(1,1,1);
    	CMULT(2,2,2);
    	CMULT(3,0,3);
    	CMULT(4,1,4);
    	CMULT(5,2,5);
    	CMULT(6,0,6);
    	CMULT(7,1,7);
    	CMULT(8,2,8);
    	CPUT(0); CPUT(1); CPUT(2);
    	CPUT(3); CPUT(4); CPUT(5);
    	CPUT(6); CPUT(7); CPUT(8);
          }
        }
        R->Type = TENSOR;
      }
    
      else if (V1->Type == TENSOR_DIAG && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0];
          a1[1] = V1->Val[0]*V2->Val[1];
          a1[2] = V1->Val[0]*V2->Val[2];
          a1[3] = V1->Val[1]*V2->Val[3];
          a1[4] = V1->Val[1]*V2->Val[4];
          a1[5] = V1->Val[1]*V2->Val[5];
          a1[6] = V1->Val[2]*V2->Val[6];
          a1[7] = V1->Val[2]*V2->Val[7];
          a1[8] = V1->Val[2]*V2->Val[8];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
    
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0);
    	CMULT(0,1,1);
    	CMULT(0,2,2);
    	CMULT(1,3,3);
    	CMULT(1,4,4);
    	CMULT(1,5,5);
    	CMULT(2,6,6);
    	CMULT(2,7,7);
    	CMULT(2,8,8);
    	CPUT(0); CPUT(1); CPUT(2);
    	CPUT(3); CPUT(4); CPUT(5);
    	CPUT(6); CPUT(7); CPUT(8);
          }
        }
        R->Type = TENSOR;
      }
    
      else if (V1->Type == TENSOR_DIAG && V2->Type == TENSOR_DIAG) {
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]*V2->Val[0];
          R->Val[1] = V1->Val[1]*V2->Val[1];
          R->Val[2] = V1->Val[2]*V2->Val[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0); CMULT(1,1,1); CMULT(2,2,2);
    	CPUT(0); CPUT(1); CPUT(2);
          }
        }
        R->Type = TENSOR_DIAG;
      }
    
      else if (V1->Type == TENSOR_SYM && V2->Type == TENSOR_SYM) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[1] + V1->Val[2]*V2->Val[2];
          a1[1] = V1->Val[0]*V2->Val[1] + V1->Val[1]*V2->Val[3] + V1->Val[2]*V2->Val[4];
          a1[2] = V1->Val[0]*V2->Val[2] + V1->Val[1]*V2->Val[4] + V1->Val[2]*V2->Val[5];
          a1[3] = V1->Val[1]*V2->Val[0] + V1->Val[3]*V2->Val[1] + V1->Val[4]*V2->Val[2];
          a1[4] = V1->Val[1]*V2->Val[1] + V1->Val[3]*V2->Val[3] + V1->Val[4]*V2->Val[4];
          a1[5] = V1->Val[1]*V2->Val[2] + V1->Val[3]*V2->Val[4] + V1->Val[4]*V2->Val[5];
          a1[6] = V1->Val[2]*V2->Val[0] + V1->Val[4]*V2->Val[1] + V1->Val[5]*V2->Val[2];
          a1[7] = V1->Val[2]*V2->Val[1] + V1->Val[4]*V2->Val[3] + V1->Val[5]*V2->Val[4];
          a1[8] = V1->Val[2]*V2->Val[2] + V1->Val[4]*V2->Val[4] + V1->Val[5]*V2->Val[5];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0);  CMULT(1,1,1);  CMULT(2,2,2);
    	CMULT(0,1,3);  CMULT(1,3,4);  CMULT(2,4,5);
    	CMULT(0,2,6);  CMULT(1,4,7);  CMULT(2,5,8);
    	CMULT(1,0,9);  CMULT(3,1,10); CMULT(4,2,11);
    	CMULT(1,1,12); CMULT(3,3,13); CMULT(4,4,14);
    	CMULT(1,2,15); CMULT(3,4,16); CMULT(4,5,17);
    	CMULT(2,0,18); CMULT(4,1,19); CMULT(5,2,20);
    	CMULT(2,1,21); CMULT(4,3,22); CMULT(5,4,23);
    	CMULT(2,2,24); CMULT(4,4,25); CMULT(5,5,26);
    	CPUT3(0,1,2,0);    CPUT3(3,4,5,1);    CPUT3(6,7,8,2);
    	CPUT3(9,10,11,3);  CPUT3(12,13,14,4); CPUT3(15,16,17,5);
    	CPUT3(18,19,20,6); CPUT3(21,22,23,7); CPUT3(24,25,26,8);
          }
        }
        R->Type = TENSOR;
      }
      else if (V1->Type == TENSOR && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[3] + V1->Val[2]*V2->Val[6];
          a1[1] = V1->Val[0]*V2->Val[1] + V1->Val[1]*V2->Val[4] + V1->Val[2]*V2->Val[7];
          a1[2] = V1->Val[0]*V2->Val[2] + V1->Val[1]*V2->Val[5] + V1->Val[2]*V2->Val[8];
          a1[3] = V1->Val[3]*V2->Val[0] + V1->Val[4]*V2->Val[3] + V1->Val[5]*V2->Val[6];
          a1[4] = V1->Val[3]*V2->Val[1] + V1->Val[4]*V2->Val[4] + V1->Val[5]*V2->Val[7];
          a1[5] = V1->Val[3]*V2->Val[2] + V1->Val[4]*V2->Val[5] + V1->Val[5]*V2->Val[8];
          a1[6] = V1->Val[6]*V2->Val[0] + V1->Val[7]*V2->Val[3] + V1->Val[8]*V2->Val[6];
          a1[7] = V1->Val[6]*V2->Val[1] + V1->Val[7]*V2->Val[4] + V1->Val[8]*V2->Val[7];
          a1[8] = V1->Val[6]*V2->Val[2] + V1->Val[7]*V2->Val[5] + V1->Val[8]*V2->Val[8];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CMULT(0,0,0);  CMULT(1,3,1);  CMULT(2,6,2);
    	CMULT(0,1,3);  CMULT(1,4,4);  CMULT(2,7,5);
    	CMULT(0,2,6);  CMULT(1,5,7);  CMULT(2,8,8);
    	CMULT(3,0,9);  CMULT(4,3,10); CMULT(5,6,11);
    	CMULT(3,1,12); CMULT(4,4,13); CMULT(5,7,14);
    	CMULT(3,2,15); CMULT(4,5,16); CMULT(5,8,17);
    	CMULT(6,0,18); CMULT(7,3,19); CMULT(8,6,20);
    	CMULT(6,1,21); CMULT(7,4,22); CMULT(8,7,23);
    	CMULT(6,2,24); CMULT(7,5,25); CMULT(8,8,26);
    	CPUT3(0,1,2,0);    CPUT3(3,4,5,1);    CPUT3(6,7,8,2);
    	CPUT3(9,10,11,3);  CPUT3(12,13,14,4); CPUT3(15,16,17,5);
    	CPUT3(18,19,20,6); CPUT3(21,22,23,7); CPUT3(24,25,26,8);
          }
        }
        R->Type = TENSOR;
      }
      else if (V1->Type == TENSOR_SYM && V2->Type == TENSOR) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[3] + V1->Val[2]*V2->Val[6];
          a1[1] = V1->Val[0]*V2->Val[1] + V1->Val[1]*V2->Val[4] + V1->Val[2]*V2->Val[7];
          a1[2] = V1->Val[0]*V2->Val[2] + V1->Val[1]*V2->Val[5] + V1->Val[2]*V2->Val[8];
          a1[3] = V1->Val[1]*V2->Val[0] + V1->Val[3]*V2->Val[3] + V1->Val[4]*V2->Val[6];
          a1[4] = V1->Val[1]*V2->Val[1] + V1->Val[3]*V2->Val[4] + V1->Val[4]*V2->Val[7];
          a1[5] = V1->Val[1]*V2->Val[2] + V1->Val[3]*V2->Val[5] + V1->Val[4]*V2->Val[8];
          a1[6] = V1->Val[2]*V2->Val[0] + V1->Val[4]*V2->Val[3] + V1->Val[5]*V2->Val[6];
          a1[7] = V1->Val[2]*V2->Val[1] + V1->Val[4]*V2->Val[4] + V1->Val[5]*V2->Val[7];
          a1[8] = V1->Val[2]*V2->Val[2] + V1->Val[4]*V2->Val[5] + V1->Val[5]*V2->Val[8];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
            CMULT(0,0,0);  CMULT(1,3,1);  CMULT(2,6,2);
            CMULT(0,1,3);  CMULT(1,4,4);  CMULT(2,7,5);
            CMULT(0,2,6);  CMULT(1,5,7);  CMULT(2,8,8);
            CMULT(1,0,9);  CMULT(2,3,10); CMULT(4,6,11);
            CMULT(1,1,12); CMULT(2,4,13); CMULT(4,7,14);
            CMULT(1,2,15); CMULT(2,5,16); CMULT(4,8,17);
            CMULT(3,0,18); CMULT(4,3,19); CMULT(5,6,20);
            CMULT(3,1,21); CMULT(4,4,22); CMULT(5,7,23);
            CMULT(3,2,24); CMULT(4,5,25); CMULT(5,8,26);
            CPUT3(0,1,2,0);    CPUT3(3,4,5,1);    CPUT3(6,7,8,2);
            CPUT3(9,10,11,3);  CPUT3(12,13,14,4); CPUT3(15,16,17,5);
            CPUT3(18,19,20,6); CPUT3(21,22,23,7); CPUT3(24,25,26,8);
            }
        }
        R->Type = TENSOR;
      }
      else if (V1->Type == TENSOR && V2->Type == TENSOR_SYM) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[0]*V2->Val[0] + V1->Val[1]*V2->Val[1] + V1->Val[2]*V2->Val[2];
          a1[1] = V1->Val[0]*V2->Val[1] + V1->Val[1]*V2->Val[3] + V1->Val[2]*V2->Val[4];
          a1[2] = V1->Val[0]*V2->Val[2] + V1->Val[1]*V2->Val[4] + V1->Val[2]*V2->Val[5];
          a1[3] = V1->Val[3]*V2->Val[0] + V1->Val[4]*V2->Val[1] + V1->Val[5]*V2->Val[2];
          a1[4] = V1->Val[3]*V2->Val[1] + V1->Val[4]*V2->Val[3] + V1->Val[5]*V2->Val[4];
          a1[5] = V1->Val[3]*V2->Val[2] + V1->Val[4]*V2->Val[4] + V1->Val[5]*V2->Val[5];
          a1[6] = V1->Val[6]*V2->Val[0] + V1->Val[7]*V2->Val[1] + V1->Val[8]*V2->Val[2];
          a1[7] = V1->Val[6]*V2->Val[1] + V1->Val[7]*V2->Val[3] + V1->Val[8]*V2->Val[4];
          a1[8] = V1->Val[6]*V2->Val[2] + V1->Val[7]*V2->Val[4] + V1->Val[8]*V2->Val[5];
          R->Val[0] = a1[0];  R->Val[1] = a1[1];  R->Val[2] = a1[2];
          R->Val[3] = a1[3];  R->Val[4] = a1[4];  R->Val[5] = a1[5];
          R->Val[6] = a1[6];  R->Val[7] = a1[7];  R->Val[8] = a1[8];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
            CMULT(0,0,0);  CMULT(1,1,1);  CMULT(2,2,2);
            CMULT(0,1,3);  CMULT(1,3,4);  CMULT(2,4,5);
            CMULT(0,2,6);  CMULT(1,4,7);  CMULT(2,5,8);
            CMULT(3,0,9);  CMULT(4,1,10); CMULT(5,2,11);
            CMULT(3,1,12); CMULT(4,3,13); CMULT(5,4,14);
            CMULT(3,2,15); CMULT(4,4,16); CMULT(5,5,17);
            CMULT(6,0,18); CMULT(7,1,19); CMULT(8,2,20);
            CMULT(6,1,21); CMULT(7,3,22); CMULT(8,4,23);
            CMULT(6,2,24); CMULT(7,4,25); CMULT(8,5,26);
            CPUT3(0,1,2,0);    CPUT3(3,4,5,1);    CPUT3(6,7,8,2);
            CPUT3(9,10,11,3);  CPUT3(12,13,14,4); CPUT3(15,16,17,5);
            CPUT3(18,19,20,6); CPUT3(21,22,23,7); CPUT3(24,25,26,8);
         }
        }
        R->Type = TENSOR;
      }
    
      /* a faire: differents tenseurs entre eux */
    
      else {
        Message::Error("Product of non adapted quantities: %s * %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    
    }
    
    #undef CMULT
    #undef CPUT
    #undef CPUT3
    
    /* ------------------------------------------------------------------------
       R <- V1 / V2
       ------------------------------------------------------------------------ */
    
    #define CDIVI(a,b,c) 								\
      Cal_ComplexDivision(&(V1->Val[MAX_DIM*k+a]), &(V2->Val[MAX_DIM*k+b]), tmp[c])
    
    #define CPUT(a) 				\
      R->Val[MAX_DIM* k   +a] = tmp[a][0] ; 	\
      R->Val[MAX_DIM*(k+1)+a] = tmp[a][MAX_DIM]
    
    void Cal_DivideValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int  k ;
      struct Value V3 ;
    
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]/V2->Val[0];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {  /* meaning in multi-harmonics ??? */
    	CDIVI(0,0,0);
    	CPUT(0);
          }
        }
        R->Type = SCALAR ;
      }
    
      else if ( (V1->Type == VECTOR || V1->Type == TENSOR_DIAG) && (V2->Type == SCALAR) ) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] / a0 ;
          R->Val[1] = V1->Val[1] / a0 ;
          R->Val[2] = V1->Val[2] / a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CDIVI(0,0,0); CDIVI(1,0,1); CDIVI(2,0,2);
    	CPUT(0); CPUT(1); CPUT(2);
          }
        }
        R->Type = V1->Type ;
      }
    
      else if ( (V1->Type == TENSOR_SYM) && (V2->Type == SCALAR) ) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] / a0 ;
          R->Val[1] = V1->Val[1] / a0 ;
          R->Val[2] = V1->Val[2] / a0 ;
          R->Val[3] = V1->Val[3] / a0 ;
          R->Val[4] = V1->Val[4] / a0 ;
          R->Val[5] = V1->Val[5] / a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CDIVI(0,0,0); CDIVI(1,0,1); CDIVI(2,0,2); CDIVI(3,0,3); CDIVI(4,0,4); CDIVI(5,0,5);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
          }
        }
        R->Type = TENSOR_SYM ;
      }
    
      else if ( (V1->Type == TENSOR) && (V2->Type == SCALAR) ) {
        if (Current.NbrHar == 1) {
          a0 = V2->Val[0] ;
          R->Val[0] = V1->Val[0] / a0 ;
          R->Val[1] = V1->Val[1] / a0 ;
          R->Val[2] = V1->Val[2] / a0 ;
          R->Val[3] = V1->Val[3] / a0 ;
          R->Val[4] = V1->Val[4] / a0 ;
          R->Val[5] = V1->Val[5] / a0 ;
          R->Val[6] = V1->Val[6] / a0 ;
          R->Val[7] = V1->Val[7] / a0 ;
          R->Val[8] = V1->Val[8] / a0 ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	CDIVI(0,0,0); CDIVI(1,0,1); CDIVI(2,0,2); CDIVI(3,0,3); CDIVI(4,0,4); CDIVI(5,0,5);
    	CDIVI(6,0,6); CDIVI(7,0,7); CDIVI(8,0,8);
    	CPUT(0); CPUT(1); CPUT(2); CPUT(3); CPUT(4); CPUT(5);
    	CPUT(6); CPUT(7); CPUT(8);
          }
        }
        R->Type = TENSOR ;
      }
    
      else if ( (V1->Type == SCALAR) &&
    	    (V2->Type == TENSOR || V2->Type == TENSOR_SYM || V2->Type == TENSOR_DIAG) ) {
        Cal_InvertValue(V2,&V3);
        Cal_ProductValue(V1,&V3,R);
      }
    
      else {
        Message::Error("Division of non adapted quantities: %s / %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    
    }
    
    #undef CDIVI
    #undef CPUT
    
    /* ------------------------------------------------------------------------
       R <- V1 % V2
       ------------------------------------------------------------------------ */
    
    void Cal_ModuloValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int k ;
    
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        for (k = 0 ; k < Current.NbrHar ; k += 2) {
          R->Val[MAX_DIM* k   ] = (int)V1->Val[MAX_DIM*k] % (int)V2->Val[MAX_DIM*k] ;
          R->Val[MAX_DIM*(k+1)] = 0. ;
        }
        R->Type = SCALAR ;
      }
    
      else if ( (V1->Type == VECTOR) && (V2->Type == SCALAR) ) {
        for (k = 0 ; k < Current.NbrHar ; k += 2) {
          R->Val[MAX_DIM* k   ]   = (int)V1->Val[MAX_DIM*k  ] % (int)V2->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM* k   +1] = (int)V1->Val[MAX_DIM*k+1] % (int)V2->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM* k   +2] = (int)V1->Val[MAX_DIM*k+2] % (int)V2->Val[MAX_DIM*k+2] ;
          R->Val[MAX_DIM*(k+1)]   = 0. ;
          R->Val[MAX_DIM*(k+1)+1] = 0. ;
          R->Val[MAX_DIM*(k+1)+2] = 0. ;
        }
        R->Type = VECTOR ;
      }
    
      else {
        Message::Error("Modulo of non adapted quantities: %s %% %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 X V2
       ------------------------------------------------------------------------ */
    
    void  Cal_CrossProductValue (struct Value * V1, struct Value * V2, struct Value * R)
    {
      int k ;
    
      if ( (V1->Type == VECTOR) && (V2->Type == VECTOR) ) {
        if (Current.NbrHar == 1) {
          a1[0] = V1->Val[1] * V2->Val[2] - V1->Val[2] * V2->Val[1] ;
          a1[1] = V1->Val[2] * V2->Val[0] - V1->Val[0] * V2->Val[2] ;
          a1[2] = V1->Val[0] * V2->Val[1] - V1->Val[1] * V2->Val[0] ;
          R->Val[0] = a1[0] ;  R->Val[1] = a1[1] ;  R->Val[2] = a1[2] ;
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k += 2) {
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k+1]), &(V2->Val[MAX_DIM*k+2]), a1) ;
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k+2]), &(V2->Val[MAX_DIM*k+1]), a2) ;
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k+2]), &(V2->Val[MAX_DIM*k  ]), a1) ;
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k  ]), &(V2->Val[MAX_DIM*k+2]), a2) ;
    	b2[0] = a1[0] - a2[0] ;  b2[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k  ]), &(V2->Val[MAX_DIM*k+1]), a1) ;
    	Cal_ComplexProduct(&(V1->Val[MAX_DIM*k+1]), &(V2->Val[MAX_DIM*k  ]), a2) ;
    	b3[0] = a1[0] - a2[0] ;  b3[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    
    	R->Val[MAX_DIM*k  ] = b1[0] ;  R->Val[MAX_DIM*(k+1)  ] = b1[MAX_DIM] ;
    	R->Val[MAX_DIM*k+1] = b2[0] ;  R->Val[MAX_DIM*(k+1)+1] = b2[MAX_DIM] ;
    	R->Val[MAX_DIM*k+2] = b3[0] ;  R->Val[MAX_DIM*(k+1)+2] = b3[MAX_DIM] ;
          }
        }
        R->Type = VECTOR ;
      }
    
      else {
        Message::Error("Cross product of non vector quantities: %s /\\ %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    
    }
    
    /* ------------------------------------------------------------------------
       R <- SQRT(V1)
       ------------------------------------------------------------------------ */
    
    void Cal_SqrtValue(struct Value *V1, struct Value *R)
    {
      if( V1->Type == SCALAR ){
        struct Value P;
        P.Type = SCALAR;
        P.Val[0] = 0.5;
        Cal_PowerValue(V1, &P, R);
      }
      else {
        Message::Error("Square root of non scalar quantity: %s",
                       Get_StringForDefine(Field_Type, V1->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 ^ V2
       ------------------------------------------------------------------------ */
    
    void Cal_PowerValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int    k;
      double arg, abs ;
    
      if ( V1->Type == SCALAR && V2->Type == SCALAR ){
    
        if(V2->Val[0] == 1.){
          Cal_CopyValue(V1,R) ;
        }
        if(V2->Val[0] == 2.){
          if (Current.NbrHar == 1) {
    	R->Val[0] = SQU(V1->Val[0]) ;
          }
          else{
    	for (k = 0 ; k < Current.NbrHar ; k+=2) {
    	  Cal_ComplexProduct(&(V1->Val[MAX_DIM*k]), &(V1->Val[MAX_DIM*k]), a1) ;
    	  R->Val[MAX_DIM* k   ] = a1[0];
    	  R->Val[MAX_DIM*(k+1)] = a1[MAX_DIM];
    	}
          }
        }
        else{
          if (Current.NbrHar == 1) {
    	R->Val[0] = pow(V1->Val[0],V2->Val[0]) ;
          }
          else{
    	for (k = 0 ; k < Current.NbrHar ; k+=2) {
    	  abs = pow(sqrt(SQU(V1->Val[MAX_DIM*k])+SQU(V1->Val[MAX_DIM*(k+1)])),
    		    V2->Val[0]) ;
    	  arg = atan2(V1->Val[MAX_DIM*(k+1)], V1->Val[MAX_DIM*k]) ;
    	  R->Val[MAX_DIM* k   ] = abs * cos(V2->Val[0] * arg) ;
    	  R->Val[MAX_DIM*(k+1)] = abs * sin(V2->Val[0] * arg) ;
    	}
          }
        }
        R->Type = SCALAR ;
      }
    
      else {
        Message::Error("Power of non scalar quantities: %s ^ %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 < V2
       ------------------------------------------------------------------------ */
    
    void Cal_LessValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] < V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of non scalar quantities: %s < %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 <= V2
       ------------------------------------------------------------------------ */
    
    void Cal_LessOrEqualValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] <= V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of non scalar quantities: %s <= %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 > V2
       ------------------------------------------------------------------------ */
    
    void Cal_GreaterValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] > V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of non scalar quantities: %s > %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 >= V2
       ------------------------------------------------------------------------ */
    
    void Cal_GreaterOrEqualValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] >= V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of non scalar quantities: %s >= %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 == V2
       ------------------------------------------------------------------------ */
    
    void Cal_EqualValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int    k;
    
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] == V2->Val[0]) ;
        for (k = 1 ; k < Current.NbrHar ; k++){
          if(!R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k] == V2->Val[MAX_DIM*k]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( ( (V1->Type == VECTOR) && (V2->Type == VECTOR) ) ||
    	    ( (V1->Type == TENSOR_DIAG) && (V2->Type == TENSOR_DIAG) ) ) {
        R->Val[0] = (V1->Val[0] == V2->Val[0] &&
    		 V1->Val[1] == V2->Val[1] &&
    		 V1->Val[2] == V2->Val[2]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(!R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] == V2->Val[MAX_DIM*k  ] &&
    		   V1->Val[MAX_DIM*k+1] == V2->Val[MAX_DIM*k+1] &&
    		   V1->Val[MAX_DIM*k+2] == V2->Val[MAX_DIM*k+2]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( (V1->Type == TENSOR_SYM) && (V2->Type == TENSOR_SYM) ) {
        R->Val[0] = (V1->Val[0] == V2->Val[0] &&
    		 V1->Val[1] == V2->Val[1] &&
    		 V1->Val[2] == V2->Val[2] &&
    		 V1->Val[3] == V2->Val[3] &&
    		 V1->Val[4] == V2->Val[4] &&
    		 V1->Val[5] == V2->Val[5]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(!R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] == V2->Val[MAX_DIM*k  ] &&
    		   V1->Val[MAX_DIM*k+1] == V2->Val[MAX_DIM*k+1] &&
    		   V1->Val[MAX_DIM*k+2] == V2->Val[MAX_DIM*k+2] &&
    		   V1->Val[MAX_DIM*k+3] == V2->Val[MAX_DIM*k+3] &&
    		   V1->Val[MAX_DIM*k+4] == V2->Val[MAX_DIM*k+4] &&
    		   V1->Val[MAX_DIM*k+5] == V2->Val[MAX_DIM*k+5]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( (V1->Type == TENSOR) && (V2->Type == TENSOR) ) {
        R->Val[0] = (V1->Val[0] == V2->Val[0] &&
    		 V1->Val[1] == V2->Val[1] &&
    		 V1->Val[2] == V2->Val[2] &&
    		 V1->Val[3] == V2->Val[3] &&
    		 V1->Val[4] == V2->Val[4] &&
    		 V1->Val[5] == V2->Val[5] &&
    		 V1->Val[6] == V2->Val[6] &&
    		 V1->Val[7] == V2->Val[7] &&
    		 V1->Val[8] == V2->Val[8]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(!R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] == V2->Val[MAX_DIM*k  ] &&
    		   V1->Val[MAX_DIM*k+1] == V2->Val[MAX_DIM*k+1] &&
    		   V1->Val[MAX_DIM*k+2] == V2->Val[MAX_DIM*k+2] &&
    		   V1->Val[MAX_DIM*k+3] == V2->Val[MAX_DIM*k+3] &&
    		   V1->Val[MAX_DIM*k+4] == V2->Val[MAX_DIM*k+4] &&
    		   V1->Val[MAX_DIM*k+5] == V2->Val[MAX_DIM*k+5] &&
    		   V1->Val[MAX_DIM*k+6] == V2->Val[MAX_DIM*k+6] &&
    		   V1->Val[MAX_DIM*k+7] == V2->Val[MAX_DIM*k+7] &&
    		   V1->Val[MAX_DIM*k+8] == V2->Val[MAX_DIM*k+8]) ;
        }
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of different quantities: %s == %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 != V2
       ------------------------------------------------------------------------ */
    
    void Cal_NotEqualValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      int    k;
    
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] != V2->Val[0]) ;
        for (k = 1 ; k < Current.NbrHar ; k++){
          if(R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k] != V2->Val[MAX_DIM*k]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( ( (V1->Type == VECTOR) && (V2->Type == VECTOR) ) ||
    	    ( (V1->Type == TENSOR_DIAG) && (V2->Type == TENSOR_DIAG) ) ) {
        R->Val[0] = (V1->Val[0] != V2->Val[0] ||
    		 V1->Val[1] != V2->Val[1] ||
    		 V1->Val[2] != V2->Val[2]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] != V2->Val[MAX_DIM*k  ] ||
    		   V1->Val[MAX_DIM*k+1] != V2->Val[MAX_DIM*k+1] ||
    		   V1->Val[MAX_DIM*k+2] != V2->Val[MAX_DIM*k+2]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( (V1->Type == TENSOR_SYM) && (V2->Type == TENSOR_SYM) ) {
        R->Val[0] = (V1->Val[0] != V2->Val[0] ||
    		 V1->Val[1] != V2->Val[1] ||
    		 V1->Val[2] != V2->Val[2] ||
    		 V1->Val[3] != V2->Val[3] ||
    		 V1->Val[4] != V2->Val[4] ||
    		 V1->Val[5] != V2->Val[5]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] != V2->Val[MAX_DIM*k  ] ||
    		   V1->Val[MAX_DIM*k+1] != V2->Val[MAX_DIM*k+1] ||
    		   V1->Val[MAX_DIM*k+2] != V2->Val[MAX_DIM*k+2] ||
    		   V1->Val[MAX_DIM*k+3] != V2->Val[MAX_DIM*k+3] ||
    		   V1->Val[MAX_DIM*k+4] != V2->Val[MAX_DIM*k+4] ||
    		   V1->Val[MAX_DIM*k+5] != V2->Val[MAX_DIM*k+5]) ;
        }
        R->Type = SCALAR ;
      }
      else if ( (V1->Type == TENSOR) && (V2->Type == TENSOR) ) {
        R->Val[0] = (V1->Val[0] != V2->Val[0] ||
    		 V1->Val[1] != V2->Val[1] ||
    		 V1->Val[2] != V2->Val[2] ||
    		 V1->Val[3] != V2->Val[3] ||
    		 V1->Val[4] != V2->Val[4] ||
    		 V1->Val[5] != V2->Val[5] ||
    		 V1->Val[6] != V2->Val[6] ||
    		 V1->Val[7] != V2->Val[7] ||
    		 V1->Val[8] != V2->Val[8]) ;
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(R->Val[0]) break;
          R->Val[0] = (V1->Val[MAX_DIM*k  ] != V2->Val[MAX_DIM*k  ] ||
    		   V1->Val[MAX_DIM*k+1] != V2->Val[MAX_DIM*k+1] ||
    		   V1->Val[MAX_DIM*k+2] != V2->Val[MAX_DIM*k+2] ||
    		   V1->Val[MAX_DIM*k+3] != V2->Val[MAX_DIM*k+3] ||
    		   V1->Val[MAX_DIM*k+4] != V2->Val[MAX_DIM*k+4] ||
    		   V1->Val[MAX_DIM*k+5] != V2->Val[MAX_DIM*k+5] ||
    		   V1->Val[MAX_DIM*k+6] != V2->Val[MAX_DIM*k+6] ||
    		   V1->Val[MAX_DIM*k+7] != V2->Val[MAX_DIM*k+7] ||
    		   V1->Val[MAX_DIM*k+8] != V2->Val[MAX_DIM*k+8]) ;
        }
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of different quantities: %s != %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 ~= V2
       ------------------------------------------------------------------------ */
    
    void Cal_ApproxEqualValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (fabs(V1->Val[0] - V2->Val[0]) < 1.e-10) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Comparison of non scalar quantities: %s ~= %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 && V2
       ------------------------------------------------------------------------ */
    
    void Cal_AndValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] && V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("And of non scalar quantities: %s && %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1 || V2
       ------------------------------------------------------------------------ */
    
    void Cal_OrValue(struct Value * V1, struct Value * V2, struct Value * R)
    {
      if ( (V1->Type == SCALAR) && (V2->Type == SCALAR) ) {
        R->Val[0] = (V1->Val[0] || V2->Val[0]) ;
        R->Type = SCALAR ;
      }
      else {
        Message::Error("Or of non scalar quantities: %s || %s",
                       Get_StringForDefine(Field_Type, V1->Type),
                       Get_StringForDefine(Field_Type, V2->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- -R
       ------------------------------------------------------------------------ */
    
    void Cal_NegValue(struct Value * R)
    {
      int k ;
    
      switch(R->Type) {
      case SCALAR :
        for (k = 0 ; k < Current.NbrHar ; k++){
          R->Val[MAX_DIM*k] = -R->Val[MAX_DIM*k] ;
        }
        break;
      case VECTOR :
      case TENSOR_DIAG :
        for (k = 0 ; k < Current.NbrHar ; k++){
          R->Val[MAX_DIM*k  ] = -R->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = -R->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = -R->Val[MAX_DIM*k+2] ;
        }
        break;
      case TENSOR_SYM :
        for (k = 0 ; k < Current.NbrHar ; k++){
          R->Val[MAX_DIM*k  ] = -R->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = -R->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = -R->Val[MAX_DIM*k+2] ;
          R->Val[MAX_DIM*k+3] = -R->Val[MAX_DIM*k+3] ;
          R->Val[MAX_DIM*k+4] = -R->Val[MAX_DIM*k+4] ;
          R->Val[MAX_DIM*k+5] = -R->Val[MAX_DIM*k+5] ;
        }
        break;
      case TENSOR :
        for (k = 0 ; k < Current.NbrHar ; k++){
          R->Val[MAX_DIM*k  ] = -R->Val[MAX_DIM*k  ] ;
          R->Val[MAX_DIM*k+1] = -R->Val[MAX_DIM*k+1] ;
          R->Val[MAX_DIM*k+2] = -R->Val[MAX_DIM*k+2] ;
          R->Val[MAX_DIM*k+3] = -R->Val[MAX_DIM*k+3] ;
          R->Val[MAX_DIM*k+4] = -R->Val[MAX_DIM*k+4] ;
          R->Val[MAX_DIM*k+5] = -R->Val[MAX_DIM*k+5] ;
          R->Val[MAX_DIM*k+6] = -R->Val[MAX_DIM*k+6] ;
          R->Val[MAX_DIM*k+7] = -R->Val[MAX_DIM*k+7] ;
          R->Val[MAX_DIM*k+8] = -R->Val[MAX_DIM*k+8] ;
        }
        break;
      default :
        Message::Error("Wrong argument type for Operator (-)");
        break;
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- !R
       ------------------------------------------------------------------------ */
    
    void Cal_NotValue(struct Value * R)
    {
      if (R->Type == SCALAR){
        R->Val[0] = !R->Val[0] ;
      }
      else {
        Message::Error("Negation of non scalar quantity: ! %s",
                       Get_StringForDefine(Field_Type, R->Type));
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1^T
       ------------------------------------------------------------------------ */
    
    void Cal_TransposeValue(struct Value *V1, struct Value *R)
    {
      int     k;
    
      switch(V1->Type){
    
      case TENSOR_DIAG :
      case TENSOR_SYM :
        Cal_CopyValue(V1,R);
        break;
    
      case TENSOR :
        R->Type = TENSOR;
        if(Current.NbrHar==1){
          R->Val[0] = V1->Val[0];
          R->Val[4] = V1->Val[4];
          R->Val[8] = V1->Val[8];
          a1[0] = V1->Val[1];
          a1[1] = V1->Val[2];
          a1[2] = V1->Val[5];
          R->Val[1] = V1->Val[3];
          R->Val[2] = V1->Val[6];
          R->Val[5] = V1->Val[7];
          R->Val[3] = a1[0];
          R->Val[6] = a1[1];
          R->Val[7] = a1[2];
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=1){
    	R->Val[MAX_DIM*k+0] = V1->Val[MAX_DIM*k+0];
    	R->Val[MAX_DIM*k+4] = V1->Val[MAX_DIM*k+4];
    	R->Val[MAX_DIM*k+8] = V1->Val[MAX_DIM*k+8];
    	a1[0] = V1->Val[MAX_DIM*k+1];
    	a1[1] = V1->Val[MAX_DIM*k+2];
    	a1[2] = V1->Val[MAX_DIM*k+5];
    	R->Val[MAX_DIM*k+1] = V1->Val[MAX_DIM*k+3];
    	R->Val[MAX_DIM*k+2] = V1->Val[MAX_DIM*k+6];
    	R->Val[MAX_DIM*k+5] = V1->Val[MAX_DIM*k+7];
    	R->Val[MAX_DIM*k+3] = a1[0];
    	R->Val[MAX_DIM*k+6] = a1[1];
    	R->Val[MAX_DIM*k+7] = a1[2];
          }
        }
        break;
    
      default:
        Message::Error("Wrong argument in 'Cal_TransposeValue'");
        break;
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- Trace(V1)
       ------------------------------------------------------------------------ */
    
    void Cal_TraceValue(struct Value *V1, struct Value *R)
    {
      int     k;
    
      switch(V1->Type){
    
      case TENSOR_DIAG :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]+V1->Val[1]+V1->Val[2];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k] = V1->Val[MAX_DIM*k  ]+
    	                    V1->Val[MAX_DIM*k+1]+
    	                    V1->Val[MAX_DIM*k+2];
          }
        }
        R->Type = SCALAR ;
        break;
    
      case TENSOR_SYM :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]+V1->Val[3]+V1->Val[5];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k] = V1->Val[MAX_DIM*k  ]+
    	                    V1->Val[MAX_DIM*k+3]+
    	                    V1->Val[MAX_DIM*k+5];
          }
        }
        R->Type = SCALAR ;
        break;
    
      case TENSOR :
        if (Current.NbrHar == 1) {
          R->Val[0] = V1->Val[0]+V1->Val[4]+V1->Val[8];
        }
        else {
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	R->Val[MAX_DIM*k] = V1->Val[MAX_DIM*k  ]+
    	                    V1->Val[MAX_DIM*k+4]+
    	                    V1->Val[MAX_DIM*k+8];
          }
        }
        R->Type = SCALAR ;
        break;
    
      default:
        Message::Error("Wrong argument type in 'Cal_TraceValue'");
        break;
      }
    }
    
    /* ------------------------------------------------------------------------
       R <- V1^T * V2 * V1  ,  V1 real
       ------------------------------------------------------------------------ */
    
    #define A0  V1->Val[0]
    #define A1  V1->Val[1]
    #define A2  V1->Val[2]
    #define A3  V1->Val[3]
    #define A4  V1->Val[4]
    #define A5  V1->Val[5]
    #define A6  V1->Val[6]
    #define A7  V1->Val[7]
    #define A8  V1->Val[8]
    
    void Cal_RotateValue(struct Value *V1, struct Value *V2, struct Value *R)
    {
      int           k;
      double        t0,t1,t2,t3,t4,t5,t6,t7,t8;
      struct Value  A;
    
      switch(V2->Type){
    
      case VECTOR :
        if(Current.NbrHar == 1){
    #define B0  V2->Val[0]
    #define B1  V2->Val[1]
    #define B2  V2->Val[2]
          A.Val[0]= A0*B0+A1*B1+A2*B2;
          A.Val[1]= A3*B0+A4*B1+A5*B2;
          A.Val[2]= A6*B0+A7*B1+A8*B2;
          A.Type = VECTOR;
          Cal_CopyValue(&A,R);
    #undef B0
    #undef B1
    #undef B2
        }
        else{ /* Attention: a modifier */
    #define B0  V2->Val[0]
    #define B1  V2->Val[1]
    #define B2  V2->Val[2]
          A.Val[0]= A0*B0+A1*B1+A2*B2;
          A.Val[1]= A3*B0+A4*B1+A5*B2;
          A.Val[2]= A6*B0+A7*B1+A8*B2;
          A.Type = VECTOR;
          Cal_CopyValue(&A,R);
    #undef B0
    #undef B1
    #undef B2
        }
        break ;
    
      case TENSOR_DIAG :
        if(Current.NbrHar == 1){
    #define B0  V2->Val[0]
    #define B1  V2->Val[1]
    #define B2  V2->Val[2]
          A.Val[0]= A0*A0*B0+A3*A3*B1+A6*A6*B2;
          A.Val[1]= A1*A0*B0+A3*A4*B1+A6*A7*B2;
          A.Val[2]= A2*A0*B0+A3*A5*B1+A6*A8*B2;
          A.Val[3]= A1*A0*B0+A3*A4*B1+A6*A7*B2;
          A.Val[4]= A1*A1*B0+A4*A4*B1+A7*A7*B2;
          A.Val[5]= A2*A1*B0+A4*A5*B1+A7*A8*B2;
          A.Val[6]= A2*A0*B0+A3*A5*B1+A6*A8*B2;
          A.Val[7]= A2*A1*B0+A4*A5*B1+A7*A8*B2;
          A.Val[8]= A2*A2*B0+A5*A5*B1+A8*A8*B2;
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0
    #undef B1
    #undef B2
        }
        else{
    #define B0r  V2->Val[MAX_DIM* k   +0]
    #define B1r  V2->Val[MAX_DIM* k   +1]
    #define B2r  V2->Val[MAX_DIM* k   +2]
    #define B0i  V2->Val[MAX_DIM*(k+1)+0]
    #define B1i  V2->Val[MAX_DIM*(k+1)+1]
    #define B2i  V2->Val[MAX_DIM*(k+1)+2]
    #define AFFECT(i)				\
      A.Val[MAX_DIM* k   +i] = t0*B0r+t1*B1r+t2*B2r;	\
      A.Val[MAX_DIM*(k+1)+i] = t0*B0i+t1*B1i+t2*B2i
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	t0=A0*A0; t1=A3*A3; t2=A6*A6; AFFECT(0);
    	t0=A1*A0; t1=A3*A4; t2=A6*A7; AFFECT(1);
    	t0=A2*A0; t1=A3*A5; t2=A6*A8; AFFECT(2);
    	t0=A1*A0; t1=A3*A4; t2=A6*A7; AFFECT(3);
    	t0=A1*A1; t1=A4*A4; t2=A7*A7; AFFECT(4);
    	t0=A2*A1; t1=A4*A5; t2=A7*A8; AFFECT(5);
    	t0=A2*A0; t1=A3*A5; t2=A6*A8; AFFECT(6);
    	t0=A2*A1; t1=A4*A5; t2=A7*A8; AFFECT(7);
    	t0=A2*A2; t1=A5*A5; t2=A8*A8; AFFECT(8);
          }
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0r
    #undef B1r
    #undef B2r
    #undef B0i
    #undef B1i
    #undef B2i
    #undef AFFECT
        }
        break;
    
    #define COMPUTE_A                                                                               \
      A.Val[0]= A0*A0*B0+A0*A3*B3+A0*A6*B6+A3*A0*B1+A3*A3*B4+A3*A6*B7+A6*A0*B2+A6*A3*B5+A6*A6*B8;	\
      A.Val[1]= A1*A0*B0+A1*A3*B3+A1*A6*B6+A4*A0*B1+A4*A3*B4+A4*A6*B7+A7*A0*B2+A7*A3*B5+A7*A6*B8;	\
      A.Val[2]= A2*A0*B0+A2*A3*B3+A2*A6*B6+A5*A0*B1+A5*A3*B4+A5*A6*B7+A8*A0*B2+A8*A3*B5+A8*A6*B8;	\
      A.Val[3]= A1*A0*B0+A0*A4*B3+A0*A7*B6+A3*A1*B1+A4*A3*B4+A3*A7*B7+A6*A1*B2+A6*A4*B5+A7*A6*B8;	\
      A.Val[4]= A1*A1*B0+A1*A4*B3+A1*A7*B6+A4*A1*B1+A4*A4*B4+A4*A7*B7+A7*A1*B2+A7*A4*B5+A7*A7*B8;	\
      A.Val[5]= A2*A1*B0+A2*A4*B3+A2*A7*B6+A5*A1*B1+A5*A4*B4+A5*A7*B7+A8*A1*B2+A8*A4*B5+A8*A7*B8;	\
      A.Val[6]= A2*A0*B0+A0*A5*B3+A0*A8*B6+A3*A2*B1+A5*A3*B4+A3*A8*B7+A6*A2*B2+A6*A5*B5+A8*A6*B8;	\
      A.Val[7]= A2*A1*B0+A1*A5*B3+A1*A8*B6+A4*A2*B1+A5*A4*B4+A4*A8*B7+A7*A2*B2+A7*A5*B5+A8*A7*B8;	\
      A.Val[8]= A2*A2*B0+A2*A5*B3+A2*A8*B6+A5*A2*B1+A5*A5*B4+A5*A8*B7+A8*A2*B2+A8*A5*B5+A8*A8*B8
    
    #define COMPLEX_COMPUTE_A									\
      t0=A0*A0; t1=A0*A3; t2=A0*A6; t3=A3*A0; t4=A3*A3; t5=A3*A6; t6=A6*A0; t7=A6*A3; t8=A6*A6; 	\
      AFFECT(0);											\
      t0=A1*A0; t1=A1*A3; t2=A1*A6; t3=A4*A0; t4=A4*A3; t5=A4*A6; t6=A7*A0; t7=A7*A3; t8=A7*A6; 	\
      AFFECT(1);											\
      t0=A2*A0; t1=A2*A3; t2=A2*A6; t3=A5*A0; t4=A5*A3; t5=A5*A6; t6=A8*A0; t7=A8*A3; t8=A8*A6; 	\
      AFFECT(2);											\
      t0=A1*A0; t1=A0*A4; t2=A0*A7; t3=A3*A1; t4=A4*A3; t5=A3*A7; t6=A6*A1; t7=A6*A4; t8=A7*A6; 	\
      AFFECT(3);											\
      t0=A1*A1; t1=A1*A4; t2=A1*A7; t3=A4*A1; t4=A4*A4; t5=A4*A7; t6=A7*A1; t7=A7*A4; t8=A7*A7; 	\
      AFFECT(4);											\
      t0=A2*A1; t1=A2*A4; t2=A2*A7; t3=A5*A1; t4=A5*A4; t5=A5*A7; t6=A8*A1; t7=A8*A4; t8=A8*A7; 	\
      AFFECT(5);											\
      t0=A2*A0; t1=A0*A5; t2=A0*A8; t3=A3*A2; t4=A5*A3; t5=A3*A8; t6=A6*A2; t7=A6*A5; t8=A8*A6; 	\
      AFFECT(6);											\
      t0=A2*A1; t1=A1*A5; t2=A1*A8; t3=A4*A2; t4=A5*A4; t5=A4*A8; t6=A7*A2; t7=A7*A5; t8=A8*A7; 	\
      AFFECT(7);											\
      t0=A2*A2; t1=A2*A5; t2=A2*A8; t3=A5*A2; t4=A5*A5; t5=A5*A8; t6=A8*A2; t7=A8*A5; t8=A8*A8; 	\
      AFFECT(8)
    
      case TENSOR_SYM :
        if(Current.NbrHar == 1){
    #define B0  V2->Val[0]
    #define B1  V2->Val[1]
    #define B2  V2->Val[2]
    #define B3  V2->Val[1]
    #define B4  V2->Val[3]
    #define B5  V2->Val[4]
    #define B6  V2->Val[2]
    #define B7  V2->Val[4]
    #define B8  V2->Val[5]
          COMPUTE_A;
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0
    #undef B1
    #undef B2
    #undef B3
    #undef B4
    #undef B5
    #undef B6
    #undef B7
    #undef B8
        }
        else{
    #define B0r  V2->Val[MAX_DIM* k   +0]
    #define B1r  V2->Val[MAX_DIM* k   +1]
    #define B2r  V2->Val[MAX_DIM* k   +2]
    #define B3r  V2->Val[MAX_DIM* k   +1]
    #define B4r  V2->Val[MAX_DIM* k   +3]
    #define B5r  V2->Val[MAX_DIM* k   +4]
    #define B6r  V2->Val[MAX_DIM* k   +2]
    #define B7r  V2->Val[MAX_DIM* k   +4]
    #define B8r  V2->Val[MAX_DIM* k   +5]
    #define B0i  V2->Val[MAX_DIM*(k+1)+0]
    #define B1i  V2->Val[MAX_DIM*(k+1)+1]
    #define B2i  V2->Val[MAX_DIM*(k+1)+2]
    #define B3i  V2->Val[MAX_DIM*(k+1)+1]
    #define B4i  V2->Val[MAX_DIM*(k+1)+3]
    #define B5i  V2->Val[MAX_DIM*(k+1)+4]
    #define B6i  V2->Val[MAX_DIM*(k+1)+2]
    #define B7i  V2->Val[MAX_DIM*(k+1)+4]
    #define B8i  V2->Val[MAX_DIM*(k+1)+5]
    #define AFFECT(i) 										\
      A.Val[MAX_DIM* k   +i] = t0*B0r+t1*B3r+t2*B6r+t3*B1r+t4*B4r+t5*B7r+t6*B2r+t7*B5r+t8*B8r; 	\
      A.Val[MAX_DIM*(k+1)+i] = t0*B0i+t1*B3i+t2*B6i+t3*B1i+t4*B4i+t5*B7i+t6*B2i+t7*B5i+t8*B8i
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	COMPLEX_COMPUTE_A;
          }
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0r
    #undef B1r
    #undef B2r
    #undef B3r
    #undef B4r
    #undef B5r
    #undef B6r
    #undef B7r
    #undef B8r
    #undef B0i
    #undef B1i
    #undef B2i
    #undef B3i
    #undef B4i
    #undef B5i
    #undef B6i
    #undef B7i
    #undef B8i
    #undef AFFECT
        }
        break;
    
      case TENSOR :
        if(Current.NbrHar == 1){
    #define B0  V2->Val[0]
    #define B1  V2->Val[1]
    #define B2  V2->Val[2]
    #define B3  V2->Val[3]
    #define B4  V2->Val[4]
    #define B5  V2->Val[5]
    #define B6  V2->Val[6]
    #define B7  V2->Val[7]
    #define B8  V2->Val[8]
          COMPUTE_A;
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0
    #undef B1
    #undef B2
    #undef B3
    #undef B4
    #undef B5
    #undef B6
    #undef B7
    #undef B8
        }
        else{
    #define B0r  V2->Val[MAX_DIM* k   +0]
    #define B1r  V2->Val[MAX_DIM* k   +1]
    #define B2r  V2->Val[MAX_DIM* k   +2]
    #define B3r  V2->Val[MAX_DIM* k   +3]
    #define B4r  V2->Val[MAX_DIM* k   +4]
    #define B5r  V2->Val[MAX_DIM* k   +5]
    #define B6r  V2->Val[MAX_DIM* k   +6]
    #define B7r  V2->Val[MAX_DIM* k   +7]
    #define B8r  V2->Val[MAX_DIM* k   +8]
    #define B0i  V2->Val[MAX_DIM*(k+1)+0]
    #define B1i  V2->Val[MAX_DIM*(k+1)+1]
    #define B2i  V2->Val[MAX_DIM*(k+1)+2]
    #define B3i  V2->Val[MAX_DIM*(k+1)+3]
    #define B4i  V2->Val[MAX_DIM*(k+1)+4]
    #define B5i  V2->Val[MAX_DIM*(k+1)+5]
    #define B6i  V2->Val[MAX_DIM*(k+1)+6]
    #define B7i  V2->Val[MAX_DIM*(k+1)+7]
    #define B8i  V2->Val[MAX_DIM*(k+1)+8]
    #define AFFECT(i) 										\
      A.Val[MAX_DIM* k   +i] = t0*B0r+t1*B3r+t2*B6r+t3*B1r+t4*B4r+t5*B7r+t6*B2r+t7*B5r+t8*B8r; 	\
      A.Val[MAX_DIM*(k+1)+i] = t0*B0i+t1*B3i+t2*B6i+t3*B1i+t4*B4i+t5*B7i+t6*B2i+t7*B5i+t8*B8i
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	COMPLEX_COMPUTE_A;
          }
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
    #undef B0r
    #undef B1r
    #undef B2r
    #undef B3r
    #undef B4r
    #undef B5r
    #undef B6r
    #undef B7r
    #undef B8r
    #undef B0i
    #undef B1i
    #undef B2i
    #undef B3i
    #undef B4i
    #undef B5i
    #undef B6i
    #undef B7i
    #undef B8i
    #undef AFFECT
        }
        break;
    
    #undef COMPUTE_A
    #undef COMPLEX_COMPUTE_A
    
      default :
        Message::Error("Wrong argument type in 'Cal_RotateValue'");
        break;
      }
    }
    
    #undef A0
    #undef A1
    #undef A2
    #undef A3
    #undef A4
    #undef A5
    #undef A6
    #undef A7
    #undef A8
    
    /* ------------------------------------------------------------------------
       R <- Det(V1)
       ------------------------------------------------------------------------ */
    
    void Cal_DetValue(struct Value *V1, struct Value *R)
    {
      int     k;
      int     V1Type;
    
      V1Type = V1->Type;
      R->Type = SCALAR;
    
      switch(V1Type){
    
      case TENSOR_DIAG :
        if(Current.NbrHar==1){
          R->Val[0] = V1->Val[0]*V1->Val[1]*V1->Val[2];
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+0], &V1->Val[MAX_DIM*k+1], a1);
          	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+2], a1, a2);
    	R->Val[MAX_DIM* k   ] = a2[0];
    	R->Val[MAX_DIM*(k+1)] = a2[MAX_DIM];
          }
        }
        break;
    
      case TENSOR_SYM :
        if(Current.NbrHar==1){
          R->Val[0] = V1->Val[0]*(V1->Val[3]*V1->Val[5]-V1->Val[4]*V1->Val[4])
    	        - V1->Val[1]*(V1->Val[1]*V1->Val[5]-V1->Val[2]*V1->Val[4])
    	        + V1->Val[2]*(V1->Val[1]*V1->Val[4]-V1->Val[2]*V1->Val[3]);
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+3], &V1->Val[MAX_DIM*k+5], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+4], &V1->Val[MAX_DIM*k+4], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+0], b1, c1);
    
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+1], &V1->Val[MAX_DIM*k+5], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+2], &V1->Val[MAX_DIM*k+4], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+1], b1, c2);
    
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+1], &V1->Val[MAX_DIM*k+4], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+2], &V1->Val[MAX_DIM*k+3], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+2], b1, c3);
    
    	R->Val[MAX_DIM* k   ] = c1[0]      -c2[0]      +c3[0];
    	R->Val[MAX_DIM*(k+1)] = c1[MAX_DIM]-c2[MAX_DIM]+c3[MAX_DIM];
          }
        }
        break;
    
      case TENSOR :
        if(Current.NbrHar==1){
          R->Val[0] = V1->Val[0]*(V1->Val[4]*V1->Val[8]-V1->Val[7]*V1->Val[5])
    	        - V1->Val[1]*(V1->Val[3]*V1->Val[8]-V1->Val[6]*V1->Val[5])
    	        + V1->Val[2]*(V1->Val[3]*V1->Val[7]-V1->Val[6]*V1->Val[4]);
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+4], &V1->Val[MAX_DIM*k+8], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+7], &V1->Val[MAX_DIM*k+5], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+0], b1, c1);
    
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+3], &V1->Val[MAX_DIM*k+8], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+6], &V1->Val[MAX_DIM*k+5], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+1], b1, c2);
    
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+3], &V1->Val[MAX_DIM*k+7], a1);
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+6], &V1->Val[MAX_DIM*k+4], a2);
    	b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM] ;
    	Cal_ComplexProduct(&V1->Val[MAX_DIM*k+2], b1, c3);
    
    	R->Val[MAX_DIM* k   ] = c1[0]      -c2[0]      +c3[0];
    	R->Val[MAX_DIM*(k+1)] = c1[MAX_DIM]-c2[MAX_DIM]+c3[MAX_DIM];
          }
        }
        break;
    
      default:
        Message::Error("Wrong argument type in 'Cal_DetValue'");
        break;
      }
    
    }
    
    /* ------------------------------------------------------------------------
       R <- 1/V1
       ------------------------------------------------------------------------ */
    
    void Cal_InvertValue(struct Value *V1, struct Value *R)
    {
      int            k;
      struct Value   Det,A;
    
      switch(V1->Type){
    
      case SCALAR :
        R->Type = SCALAR;
    
        if(Current.NbrHar==1){
          if(!V1->Val[0]){
    	Message::Error("Division by zero in 'Cal_InvertValue'");
            return;
          }
          R->Val[0] = 1./V1->Val[0];
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	Cal_ComplexInvert(&V1->Val[MAX_DIM*k], &R->Val[MAX_DIM*k]);
          }
        }
        break;
    
      case TENSOR_DIAG :
        R->Type = TENSOR_DIAG;
    
        if(Current.NbrHar==1){
          if(V1->Val[0] && V1->Val[1] && V1->Val[2]){
    	R->Val[0] = 1./V1->Val[0];
    	R->Val[1] = 1./V1->Val[1];
    	R->Val[2] = 1./V1->Val[2];
          }
          else{
    	Message::Error("Null determinant in 'Cal_InvertValue'");
            return;
          }
        }
        else{
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	Cal_ComplexInvert(&V1->Val[MAX_DIM*k  ], &R->Val[MAX_DIM*k  ]);
    	Cal_ComplexInvert(&V1->Val[MAX_DIM*k+1], &R->Val[MAX_DIM*k+1]);
    	Cal_ComplexInvert(&V1->Val[MAX_DIM*k+2], &R->Val[MAX_DIM*k+2]);
          }
        }
        break;
    
      case TENSOR_SYM :
        Cal_DetValue(V1,&Det);
    
        if(!Det.Val[0]){
          Message::Error("Null determinant in 'Cal_InvertValue'");
          return;
        }
    
        if(Current.NbrHar==1){
          A.Val[0] =  (V1->Val[3]*V1->Val[5]-V1->Val[4]*V1->Val[4])/Det.Val[0];
          A.Val[1] = -(V1->Val[1]*V1->Val[5]-V1->Val[4]*V1->Val[2])/Det.Val[0];
          A.Val[2] =  (V1->Val[1]*V1->Val[4]-V1->Val[3]*V1->Val[2])/Det.Val[0];
          A.Val[3] = -(V1->Val[1]*V1->Val[5]-V1->Val[2]*V1->Val[4])/Det.Val[0];
          A.Val[4] =  (V1->Val[0]*V1->Val[5]-V1->Val[2]*V1->Val[2])/Det.Val[0];
          A.Val[5] = -(V1->Val[0]*V1->Val[4]-V1->Val[2]*V1->Val[1])/Det.Val[0];
          A.Val[6] =  (V1->Val[1]*V1->Val[4]-V1->Val[2]*V1->Val[3])/Det.Val[0];
          A.Val[7] = -(V1->Val[0]*V1->Val[4]-V1->Val[1]*V1->Val[2])/Det.Val[0];
          A.Val[8] =  (V1->Val[0]*V1->Val[3]-V1->Val[1]*V1->Val[1])/Det.Val[0];
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
        }
        else{
    #define PRODSUBDIV(a,b,c,d,e) 						\
      Cal_ComplexProduct(&V1->Val[MAX_DIM*k+a], &V1->Val[MAX_DIM*k+b], a1);	\
      Cal_ComplexProduct(&V1->Val[MAX_DIM*k+c], &V1->Val[MAX_DIM*k+d], a2);	\
      b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM];     \
      Cal_ComplexDivision(b1, &Det.Val[MAX_DIM*k], &A.Val[e])
    
    #define ASSIGN1(i)				      \
      R->Val[MAX_DIM* k   +i] = A.Val[MAX_DIM* k   +i];   \
      R->Val[MAX_DIM*(k+1)+i] = A.Val[MAX_DIM*(k+1)+i]
    
    #define ASSIGN2(i)				      \
      R->Val[MAX_DIM* k   +i] = -A.Val[MAX_DIM* k   +i];  \
      R->Val[MAX_DIM*(k+1)+i] = -A.Val[MAX_DIM*(k+1)+i]
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	PRODSUBDIV(3,5,4,4,0); PRODSUBDIV(1,5,4,2,1); PRODSUBDIV(1,4,3,2,2);
    	PRODSUBDIV(1,5,2,4,3); PRODSUBDIV(0,5,2,2,4); PRODSUBDIV(0,4,2,1,5);
    	PRODSUBDIV(1,4,2,3,6); PRODSUBDIV(0,4,1,2,7); PRODSUBDIV(0,3,1,1,8);
    	ASSIGN1(0); ASSIGN2(1);	ASSIGN1(2);
    	ASSIGN2(3); ASSIGN1(4);	ASSIGN2(5);
    	ASSIGN1(6); ASSIGN2(7);	ASSIGN1(8);
          }
          R->Type = TENSOR;
    #undef PRODSUBDIV
    #undef ASSIGN1
    #undef ASSIGN2
        }
        break;
    
      case TENSOR :
        Cal_DetValue(V1,&Det);
    
        if(!Det.Val[0]){
          Message::Error("Null determinant in 'Cal_InvertValue'");
          return;
        }
    
        if(Current.NbrHar==1){
          A.Val[0] =  (V1->Val[4]*V1->Val[8]-V1->Val[5]*V1->Val[7])/Det.Val[0];
          A.Val[1] = -(V1->Val[1]*V1->Val[8]-V1->Val[7]*V1->Val[2])/Det.Val[0];
          A.Val[2] =  (V1->Val[1]*V1->Val[5]-V1->Val[4]*V1->Val[2])/Det.Val[0];
          A.Val[3] = -(V1->Val[3]*V1->Val[8]-V1->Val[6]*V1->Val[5])/Det.Val[0];
          A.Val[4] =  (V1->Val[0]*V1->Val[8]-V1->Val[2]*V1->Val[6])/Det.Val[0];
          A.Val[5] = -(V1->Val[0]*V1->Val[5]-V1->Val[2]*V1->Val[3])/Det.Val[0];
          A.Val[6] =  (V1->Val[3]*V1->Val[7]-V1->Val[6]*V1->Val[4])/Det.Val[0];
          A.Val[7] = -(V1->Val[0]*V1->Val[7]-V1->Val[1]*V1->Val[6])/Det.Val[0];
          A.Val[8] =  (V1->Val[0]*V1->Val[4]-V1->Val[1]*V1->Val[3])/Det.Val[0];
          A.Type = TENSOR;
          Cal_CopyValue(&A,R);
        }
        else{
    #define PRODSUBDIV(a,b,c,d,e) 						\
      Cal_ComplexProduct(&V1->Val[MAX_DIM*k+a], &V1->Val[MAX_DIM*k+b], a1);	\
      Cal_ComplexProduct(&V1->Val[MAX_DIM*k+c], &V1->Val[MAX_DIM*k+d], a2);	\
      b1[0] = a1[0] - a2[0] ;  b1[MAX_DIM] = a1[MAX_DIM] - a2[MAX_DIM];     \
      Cal_ComplexDivision(b1, &Det.Val[MAX_DIM*k], &A.Val[e])
    
    #define ASSIGN1(i)				 \
      R->Val[MAX_DIM* k   +i] = A.Val[MAX_DIM* k   +i];	 \
      R->Val[MAX_DIM*(k+1)+i] = A.Val[MAX_DIM*(k+1)+i]
    
    #define ASSIGN2(i)				\
      R->Val[MAX_DIM* k   +i] = -A.Val[MAX_DIM* k   +i];	\
      R->Val[MAX_DIM*(k+1)+i] = -A.Val[MAX_DIM*(k+1)+i]
          for(k=0 ; k<Current.NbrHar ; k+=2){
    	PRODSUBDIV(4,8,5,7,0); PRODSUBDIV(1,8,7,2,1); PRODSUBDIV(1,5,4,2,2);
    	PRODSUBDIV(3,8,6,5,3); PRODSUBDIV(0,8,2,6,4); PRODSUBDIV(0,5,2,3,5);
    	PRODSUBDIV(3,7,6,4,6); PRODSUBDIV(0,7,1,6,7); PRODSUBDIV(0,4,1,3,8);
    	ASSIGN1(0); ASSIGN2(1);	ASSIGN1(2);
    	ASSIGN2(3); ASSIGN1(4);	ASSIGN2(5);
    	ASSIGN1(6); ASSIGN2(7);	ASSIGN1(8);
          }
          R->Type = TENSOR;
    #undef PRODSUBDIV
    #undef ASSIGN1
    #undef ASSIGN2
        }
        break;
    
      default :
        Message::Error("Wrong type of argument in 'Cal_InvertValue'");
        break;
      }
    
    }
    
    /* ------------------------------------------------------- */
    /*  -->  P r i n t _ V a l u e                             */
    /* ------------------------------------------------------- */
    
    std::string Print_Value_ToString(struct Value *A)
    {
      int i, j, k, index = 0;
      std::ostringstream sstream;
    
      sstream.precision(16);
    
      switch(A->Type){
    
      case SCALAR :
        if(Current.NbrHar>1) sstream << "(";
        for (k = 0 ; k < Current.NbrHar ; k++) {
          if(k) sstream << ",";
          sstream << A->Val[MAX_DIM*k];
        }
        if(Current.NbrHar>1) sstream << ")";
        break;
    
      case VECTOR :
        sstream << "[";
        for (i = 0 ; i < 3 ; i++) {
          if(i) sstream << " ";
          if(Current.NbrHar>1) sstream << "(";
          for (k = 0 ; k < Current.NbrHar ; k++) {
    	if(k) sstream << ",";
    	sstream << A->Val[MAX_DIM*k+i];
          }
          if(Current.NbrHar>1) sstream << ")";
        }
        sstream << "]";
        break;
    
      case TENSOR_DIAG :
      case TENSOR_SYM :
      case TENSOR :
        sstream << "[[";
        for (i = 0 ; i < 3 ; i++) {
          if(i) sstream << "][";
          for (j = 0 ; j < 3 ; j++) {
    	if(j) sstream << " ";
    	if(Current.NbrHar>1) sstream << "(";
    	switch(A->Type){
    	case TENSOR_DIAG : index = TENSOR_DIAG_MAP[3*i+j]; break;
    	case TENSOR_SYM  : index = TENSOR_SYM_MAP[3*i+j]; break;
    	case TENSOR      : index = 3*i+j; break;
    	}
    	for (k = 0 ; k < Current.NbrHar ; k++) {
    	  if(k) sstream << ",";
    	  if(index<0)
    	    sstream << "0";
    	  else
    	    sstream << A->Val[MAX_DIM*k+index];
    	}
    	if(Current.NbrHar>1) sstream << ")";
          }
        }
        sstream << "]]";
        break;
    
      default :
        Message::Error("Unknown type of argument in function 'Printf'");
        break;
      }
    
      std::string ret(sstream.str());
      return ret;
    }
    
    void Print_Value(struct Value *A, FILE *fp)
    {
      std::string s = Print_Value_ToString(A);
      if(fp && fp != stdout && fp != stderr)
        fprintf(fp, "%s\n", s.c_str());
      else
        Message::Direct("%s", s.c_str());
    }
    
    /* ------------------------------------------------------------------------
       Complete harmonics
       ------------------------------------------------------------------------ */
    
    void Cal_SetHarmonicValue(struct Value *R)
    {
      int k ;
    
      switch(R->Type){
    
      case SCALAR :
        R->Val[MAX_DIM] = 0. ;
        for (k = 2 ; k < std::min(NBR_MAX_HARMONIC, Current.NbrHar) ; k += 2) {
          R->Val[MAX_DIM*k    ] = R->Val[0] ;
          R->Val[MAX_DIM*(k+1)] = 0. ;
        }
        break;
    
      case VECTOR :
        R->Val[MAX_DIM] = R->Val[MAX_DIM+1] = R->Val[MAX_DIM+2] = 0. ;
        for (k = 2 ; k < std::min(NBR_MAX_HARMONIC, Current.NbrHar) ; k += 2) {
          R->Val[MAX_DIM*k  ] = R->Val[0] ;
          R->Val[MAX_DIM*k+1] = R->Val[1] ;
          R->Val[MAX_DIM*k+2] = R->Val[2] ;
          R->Val[MAX_DIM*(k+1)  ] = 0. ;
          R->Val[MAX_DIM*(k+1)+1] = 0. ;
          R->Val[MAX_DIM*(k+1)+2] = 0. ;
        }
        break;
    
      default :
        Message::Error("Unknown type of argument in function 'Cal_SetHarmonicValue'");
      }
    
    }
    
    /* ------------------------------------------------------------------------
       Set superfluous harmonics to zero (in case of CASTing)
       ------------------------------------------------------------------------ */
    
    void Cal_SetZeroHarmonicValue(struct Value *R, int Save_NbrHar)
    {
      int k ;
    
      switch(R->Type) {
      case SCALAR :
        for (k = Current.NbrHar ; k < Save_NbrHar ; k++) {
         R->Val[k*MAX_DIM  ] =  0. ;
        }
        break ;
      case VECTOR :
      case TENSOR_DIAG :
        for (k = Current.NbrHar ; k < Save_NbrHar ; k++) {
         R->Val[k*MAX_DIM  ] =  0. ;
         R->Val[k*MAX_DIM+1] =  0. ;
         R->Val[k*MAX_DIM+2] =  0. ;
        }
        break ;
      case TENSOR_SYM :
        for (k = Current.NbrHar ; k < Save_NbrHar ; k++) {
         R->Val[k*MAX_DIM  ] =  0. ;
         R->Val[k*MAX_DIM+1] =  0. ;
         R->Val[k*MAX_DIM+2] =  0. ;
         R->Val[k*MAX_DIM+3] =  0. ;
         R->Val[k*MAX_DIM+4] =  0. ;
         R->Val[k*MAX_DIM+5] =  0. ;
        }
        break ;
      case TENSOR :
        for (k = Current.NbrHar ; k < Save_NbrHar ; k++) {
         R->Val[k*MAX_DIM  ] =  0. ;
         R->Val[k*MAX_DIM+1] =  0. ;
         R->Val[k*MAX_DIM+2] =  0. ;
         R->Val[k*MAX_DIM+3] =  0. ;
         R->Val[k*MAX_DIM+4] =  0. ;
         R->Val[k*MAX_DIM+5] =  0. ;
         R->Val[k*MAX_DIM+6] =  0. ;
         R->Val[k*MAX_DIM+7] =  0. ;
         R->Val[k*MAX_DIM+8] =  0. ;
        }
        break ;
      default :
        Message::Error("Unknown type of argument in function 'Cal_SetZeroHarmonicValue'");
      }
    
    }
    
    /* ------------------------------------------------------- */
    /*  -->  S h o w _ V a l u e                               */
    /* ------------------------------------------------------- */
    
    #define W(i,j)   A->Val[MAX_DIM*(i)+j]
    
    int NonZeroHar(int NbrComp, double Val[])
    {
      int iComp, nz, nh;
    
      nh=Current.NbrHar-1;
      while( nh >= 0 ){
        nz=0;
        for (iComp=0 ; iComp<NbrComp ; iComp++)
          if(Val[MAX_DIM*nh+iComp])nz++;
        if(nz)break;
        nh--;
      }
      return nh+1;
    }
    
    void Show_Value(struct Value *A)
    {
      int k, nzh;
    
      switch(A->Type){
    
      case SCALAR :
        if((nzh=NonZeroHar(1,A->Val)) == 0){
          fprintf(stderr, "zero scalar \n") ;
        }
        else if(nzh == 1){
          fprintf(stderr, "real scalar %e \n", W(0,0) ) ;
        }
        else if (nzh == 2){
          fprintf(stderr, "complex scalar %e +j %e \n", W(0,0), W(1,0) ) ;
        }
        else {
          fprintf(stderr, "multi-freq scalar ");
          for (k = 0 ; k < Current.NbrHar ; k += 2)
    	fprintf(stderr, " Freq %d : %e + j %e",k/2+1, W(k,0), W(k+1,0) ) ;
          fprintf(stderr, "\n");
        }
        break;
    
      case VECTOR :
        if((nzh=NonZeroHar(3,A->Val)) == 0){
          fprintf(stderr, "zero vector \n") ;
        }
        else if (nzh == 1){
          fprintf(stderr, "real vector x %e  y %e  z %e \n", W(0,0), W(0,1), W(0,2));
        }
        else if (nzh == 2){
          fprintf(stderr, "complex vector x %e +j %e  y %e +j %e  z %e +j %e \n",
    	      W(0,0), W(1,0), W(0,1), W(1,1), W(0,2), W(1,2) );
        }
        else{
          fprintf(stderr, "multi-freq vector ");
          for (k = 0 ; k < Current.NbrHar ; k += 2)
    	fprintf(stderr, " Freq %d :  x %e +j %e  y %e +j %e  z %e +j %e", k/2+1,
    		W(k,0), W(k+1,0), W(k,1), W(k+1,1), W(k,2), W(k+1,2) );
          fprintf(stderr, "\n");
        }
        break;
    
      case TENSOR :
        if((nzh=NonZeroHar(9,A->Val)) == 0){
          fprintf(stderr, "zero tensor \n") ;
        }
        else if (nzh == 1){
          fprintf(stderr, "real tensor "
    	      " xx %e  xy %e  xz %e "
    	      " yx %e  yy %e  yz %e "
    	      " zx %e  zy %e  zz %e \n",
    	      W(0,0), W(0,1), W(0,2), W(0,3), W(0,4), W(0,5), W(0,6), W(0,7), W(0,8));
        }
        else if (nzh == 2){
          fprintf(stderr, "complex tensor "
    	      " xx %e +j %e  xy %e +j %e  xz %e +j %e "
    	      " yx %e +j %e  yy %e +j %e  yz %e +j %e "
    	      " zx %e +j %e  zy %e +j %e  zz %e +j %e\n",
    	      W(0,0), W(1,0), W(0,1), W(1,1), W(0,2), W(1,2),
    	      W(0,3), W(1,3), W(0,4), W(1,4), W(0,5), W(1,5),
    	      W(0,6), W(1,6), W(0,7), W(1,7), W(0,8), W(1,8));
        }
        else {
          fprintf(stderr, "multi-freq tensor ");
          for (k = 0 ; k < Current.NbrHar ; k += 2)
    	fprintf(stderr, " Freq %d : "
    		" xx %e +j %e  xy %e +j %e  xz %e +j %e "
    	        " yx %e +j %e  yy %e +j %e  yz %e +j %e "
    		" zx %e +j %e  zy %e +j %e  zz %e +j %e", k/2+1,
    		W(k,0), W(k+1,0), W(k,1), W(k+1,1), W(k,2), W(k+1,2),
    		W(k,3), W(k+1,3), W(k,4), W(k+1,4), W(k,5), W(k+1,5),
    		W(k,6), W(k+1,6), W(k,7), W(k+1,7), W(k,8), W(k+1,8));
          fprintf(stderr, "\n");
        }
        break;
    
      case TENSOR_SYM :
        if((nzh=NonZeroHar(6,A->Val)) == 0){
          fprintf(stderr, "zero sym tensor \n") ;
        }
        else if (nzh == 1){
          fprintf(stderr, "real sym tensor "
    	      " xx %e  xy %e  xz %e "
    	      " yy %e  yz %e  zz %e \n",
    	      W(0,0), W(0,1), W(0,2), W(0,3), W(0,4), W(0,5));
        }
        else if (nzh == 2){
          fprintf(stderr, "complex sym tensor "
    	      " xx %e +j %e  xy %e +j %e  xz %e +j %e "
    	      " yy %e +j %e  yz %e +j %e  zz %e +j %e\n",
    	      W(0,0), W(1,0), W(0,1), W(1,1), W(0,2), W(1,2),
    	      W(0,3), W(1,3), W(0,4), W(1,4), W(0,5), W(1,5));
        }
        else {
          fprintf(stderr, "multi-freq sym tensor ");
          for (k = 0 ; k < Current.NbrHar ; k += 2)
    	fprintf(stderr, " Freq %d : "
    		" xx %e +j %e  xy %e +j %e  xz %e +j %e "
    		" yy %e +j %e  yz %e +j %e  zz %e +j %e", k/2+1,
    		W(k,0), W(k+1,0), W(k,1), W(k+1,1), W(k,2), W(k+1,2),
    		W(k,3), W(k+1,3), W(k,4), W(k+1,4), W(k,5), W(k+1,5));
          fprintf(stderr, "\n");
        }
        break;
    
      case TENSOR_DIAG :
        if((nzh=NonZeroHar(3,A->Val)) == 0){
          fprintf(stderr, "zero sym tensor \n") ;
        }
        else if (nzh == 1){
          fprintf(stderr, "real diag tensor xx %e  yy %e  zz %e \n",
    	      W(0,0), W(0,1), W(0,2));
        }
        else if (nzh == 2){
          fprintf(stderr, "complex diag tensor  xx %e +j %e  yy %e +j %e  zz %e +j %e",
    	      W(0,0), W(1,0), W(0,1), W(1,1), W(0,2), W(1,2));
        }
        else {
          fprintf(stderr, "multi-freq diag tensor ");
          for (k = 0 ; k < Current.NbrHar ; k += 2)
    	fprintf(stderr, " Freq %d :  xx %e +j %e  yy %e +j %e  zz %e +j %e", k/2+1,
    		W(k,0), W(k+1,0), W(k,1), W(k+1,1), W(k,2), W(k+1,2));
          fprintf(stderr, "\n");
        }
        break;
    
      default :
        Message::Error("Unknown value type in Show_Value");
      }
    }
    
    void Export_Value(struct Value *A, std::vector<double> &out, List_T *harmonics,
                      bool append)
    {
      std::vector<int> har;
      if(harmonics){
        for(int i = 0; i < List_Nbr(harmonics); i++)
          har.push_back((int)*(double*)List_Pointer(harmonics, i));
      }
      else{
        for(int i = 0; i < Current.NbrHar; i++)
          har.push_back(i);
      }
    
      if(!append) out.clear();
    
      switch(A->Type){
    
      case SCALAR :
        for(unsigned int k = 0; k < har.size(); k++)
          out.push_back(W(har[k], 0));
        break;
    
      case VECTOR :
      case TENSOR_DIAG :
        for(unsigned int k = 0; k < har.size(); k++)
          for(int i = 0; i < 3; i++)
            out.push_back(W(har[k], i));
        break;
    
      case TENSOR :
        for(unsigned int k = 0; k < har.size(); k++)
          for(int i = 0; i < 9; i++)
            out.push_back(W(har[k], i));
        break;
    
      case TENSOR_SYM :
        for(unsigned int k = 0; k < har.size(); k++)
          for(int i = 0; i < 6; i++)
            out.push_back(W(har[k], i));
        break;
    
      default :
        Message::Error("Unknown value type in Export_Value");
      }
    }
    
    #undef W