

// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2021 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.


/************************************************************************
*     DATE:        23/01/97                                            *
*                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
*                                                                $     *
*     PROJET:      Herezh++                                            *
*                                                                $     *
************************************************************************
*     BUT:   Definition des classes derivees de dimension 3.           *
*                                                                $     *
*     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
************************************************************************/


#ifndef Tenseur3_H
#define Tenseur3_H

#include <iostream> 
#include "Tenseur.h"  
#include "PtTabRel.h"
#include "Tableau2_T.h"


/** @defgroup Les_classes_tenseurs_dim3_ordre2
*
*     BUT:   Definir les tenseurs d'ordre 2 de differentes composantes,
*     spécifiquement à la dimension 3.
*     L'objectif principal est de surcharger les differentes operations
*     classiques.
*
*   concernant le produit contracte un fois, en particulier pour les tenseurs mixtes
*   il y a contraction du 2ieme indice du premier tenseur avec le premier indice du second
*   tenseur : Aij * Bjk = C ik <-> A * B = C
*   le tenseur inverse par rapport au produit contracte est defini de la maniere suivante
*   Inverse(A) * A = Id, ainsi l'inverse d'un tenseur BH est un BH idem pour les HB
*   mais l'inverse d'un BB est un HH, et l'inverse d'un HH est un BB
*
*   NB: lorsque les tenseurs mixtes sont issues de tenseurs HH ou BB symetrique, l'ordre
*   de contraction des indices n'a pas d'importance sur le resultat !!
*
*   le produit contracte de deux tenseurs symetriques quelconques ne donne pas un tenseur
*   symetrique !!, donc par exemple la contraction d'un tenseur HB avec HH n'est pas forcement
*   symetrique. Le resultat est symetrique SEULEMENT lorsque ces operations sont effectues
*   avec le tenseur metrique.
*
* \author    Gérard Rio
* \version   1.0
* \date       23/01/97
* \brief       Définition des classes de dimension 3 de type Tenseur d'ordre 2, en coordonnées avec différentes variances.
*
*/


class Tenseur_ns3HH;class Tenseur2HH;
/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes deux fois contravariantes
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97

class Tenseur3HH : public TenseurHH
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur3HH &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur3HH &);
  friend class Tenseur2HH; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  friend class Tenseur3BB;

  public :
    // Constructeur
    Tenseur3HH() ; // par défaut
    // initialisation de toutes les composantes a une meme valeur val 
    Tenseur3HH(const double val);  
    // initialisation avec 6 valeurs différentes correspondantes a
    // (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3) 
    Tenseur3HH
      (const double val1,const  double val2,const  double val3,const  double val4,
      const  double val5,const  double val6) ; 
    // DESTRUCTEUR :
    ~Tenseur3HH() ;
    // constructeur a partir d'une instance non differenciee  
    Tenseur3HH (const  TenseurHH &); 
    // constructeur de copie  
    Tenseur3HH (const  Tenseur3HH &); 
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurHH & operator + (const TenseurHH &) const ;
    void operator += ( const TenseurHH &);
    TenseurHH & operator - () const ;  // oppose du tenseur
    TenseurHH & operator - ( const TenseurHH &) const ;
    void  operator -= ( const TenseurHH &);
    TenseurHH & operator = ( const TenseurHH &);
    TenseurHH & operator = ( const Tenseur3HH & B)
       { return this->operator=((TenseurHH &) B); };
    TenseurHH & operator = ( const Tenseur_ns3HH & B)
       { return this->operator=((TenseurHH &) B); };
    TenseurHH & operator * ( const double &) const ;
    void  operator *= ( const double &);
    TenseurHH & operator / ( const double &) const ;
    void  operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur2HH & B,bool plusZero);  
 
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurHH & B,bool plusZero);
 
    // produit contracte avec un vecteur
    CoordonneeH operator * ( const CoordonneeB & ) const ;
      
    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    TenseurHH & operator * ( const TenseurBH &) const ;
    TenseurHB & operator * ( const TenseurBB &) const ;
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    double  operator && ( const TenseurBB &) const ;
    
    // test
    int operator == ( const TenseurHH &) const ;
    int operator != ( const TenseurHH &) const ;
    
    double  Det() const ;     // determinant de la matrice des coordonnees
         
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurBB & Inverse() const ;
         
    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    TenseurHH & Transpose() const ; 
    
    // ---- manipulation d'indice ---- -> création de nouveaux tenseurs
    virtual TenseurBB& Baisse2Indices() const;
    virtual TenseurBH& BaissePremierIndice() const;
    virtual TenseurHB& BaisseDernierIndice() const;
         
    // calcul du maximum en valeur absolu des composantes du tenseur
    double MaxiComposante() const;
            
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
         
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
   
    //fonctions static définissant le produit tensoriel de deux vecteurs
    // si les vecteurs sont égaux le tenseur est symétrique sinon il est non symétrique
    static TenseurHH & Prod_tensoriel(const CoordonneeH & aH, const CoordonneeH & bH);
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
    
    // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
    // dans l'ordre: (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3)
    static int OdVect(const int i, const int j)  {return Tenseur3HH::cdex.odVect(i,j);};
    // transformation 1 indice -> 2 indices
    // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
    // dans l'ordre: (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3)
    static int idx_i(const int k)  {return Tenseur3HH::cdex.idx_i(k);};
    static int idx_j(const int k)  {return Tenseur3HH::cdex.idx_j(k);};
	
	 protected :
	   // allocator dans la liste de data
    listdouble6Iter ipointe;
    // --- gestion   d'index ----
    class ChangementIndex
     { public:
       ChangementIndex(); 
       // passage pour les index de la forme vecteur à la forme i,j
       Tableau <int> idx_i,idx_j; 
       // passage pour les index de la forme i,j à la forme vecteur
       Tableau2 <int> odVect;  
      };
    static const ChangementIndex  cdex;
 };
/// @}  // end of group

class Tenseur_ns2HH;

/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes deux fois contravariantes non symetriques
///          pour les differencier la dimension = -3
//-----------------------------------------------------------------------  
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97
class Tenseur_ns3HH : public TenseurHH
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur_ns3HH &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur_ns3HH &);
  friend class Tenseur_ns2HH; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  friend class Tenseur_ns3BB;
  public :
    // constructeur
    Tenseur_ns3HH() ; // par défaut
    // initialisation de toutes les composantes a une meme valeur val 
    Tenseur_ns3HH (double val) ;  
    // initialisation avec 9 valeurs différentes correspodantes aux trois
    // lignes : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    //  car le tableau n'est pas symetrique !!!!
    //  le premier indice = ligne, le second = colonne
    Tenseur_ns3HH
      ( const double val1,  const double val2, const  double val3,   // 1ere  ligne
        const double val4,  const double val5, const double val6,   // 2ieme ligne
        const double val7, const  double val8, const  double val9) ; // 3ieme ligne
  
    // DESTRUCTEUR :
    ~Tenseur_ns3HH();
    // constructeur a partir d'une instance non differenciee  
    Tenseur_ns3HH ( const  TenseurHH &); 
    // constructeur de copie  
    Tenseur_ns3HH ( const Tenseur_ns3HH &); 
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurHH & operator + ( const TenseurHH &) const ;
    void operator += ( const TenseurHH &);
    TenseurHH & operator - () const ;  // oppose du tenseur
    TenseurHH & operator - ( const TenseurHH &) const ;
    void  operator -= ( const TenseurHH &);
    TenseurHH & operator = ( const TenseurHH &);
    TenseurHH & operator = ( const Tenseur3HH & B)
       { return this->operator=((TenseurHH &) B); };
    TenseurHH & operator = ( const Tenseur_ns3HH & B)
       { return this->operator=((TenseurHH &) B); };
    TenseurHH & operator * ( const double &) const ;
    void  operator *= ( const double &);
    TenseurHH & operator / ( const double &) const ;
    void  operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur_ns2HH & B,bool plusZero);  
            
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurHH & B,bool plusZero);
 
    // produit contracte avec un vecteur
    CoordonneeH operator * ( const CoordonneeB & ) const ;
 
    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    TenseurHH & operator * ( const TenseurBH &) const ;
    TenseurHB & operator * ( const TenseurBB &) const ;
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    double  operator && ( const TenseurBB &) const ;
    
    // test
    int operator == ( const TenseurHH &) const ;
    int operator != ( const TenseurHH &) const ;
    
    double  Det() const ;     // determinant de la matrice des coordonnees
         
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurBB & Inverse() const ;
         
    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    TenseurHH & Transpose() const ; 
    
    // ---- manipulation d'indice ---- -> création de nouveaux tenseurs
    virtual TenseurBB& Baisse2Indices() const;
    virtual TenseurBH& BaissePremierIndice() const;
    virtual TenseurHB& BaisseDernierIndice() const;
        
    // calcul du maximum en valeur absolu des composantes du tenseur
    double MaxiComposante() const;
             
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
          
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
	 	 
     
    // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
    // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    static int OdVect(const int i, const int j)  {return Tenseur_ns3HH::cdex.odVect(i,j);};
    // transformation 1 indice -> 2 indices
    // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
    // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    static int idx_i(const int k)  {return Tenseur_ns3HH::cdex.idx_i(k);};
    static int idx_j(const int k)  {return Tenseur_ns3HH::cdex.idx_j(k);};
	 	 	 
	  protected :
	   // allocator dans la liste de data
	   //  static list <Reels4> listdouble4;
    listdouble9Iter ipointe;
    // --- gestion   d'index ----
    class ChangementIndex
     { public:
       ChangementIndex(); 
       // passage pour les index de la forme vecteur à la forme i,j
       Tableau <int> idx_i,idx_j; 
       // passage pour les index de la forme i,j à la forme vecteur
       Tableau2 <int> odVect;  
      };
    static const ChangementIndex  cdex;
 };
/// @}  // end of group
 
class Tenseur_ns3BB;class Tenseur2BB;

/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes deux fois covariantes
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97
class Tenseur3BB : public TenseurBB
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur3BB &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur3BB &);
  friend class Tenseur2BB; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  friend class Tenseur3HH;
  public :
     // constructeur
    Tenseur3BB() ; // par défaut
        // initialisation de toutes les composantes a une meme valeur val 
    Tenseur3BB( const double val);  
    // initialisation avec 6 valeurs différentes correspondantes a
    // (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3) 
    Tenseur3BB
      ( const double val1, const double val2, const  double val3,
       const  double val4,  const double val5, const  double val6) ; 
    // DESTRUCTEUR :
    ~Tenseur3BB() ;
    // constructeur a partir d'une instance non differenciee  
    Tenseur3BB (  const TenseurBB &); 
    // constructeur de copie  
    Tenseur3BB (  const Tenseur3BB &); 
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurBB & operator + ( const TenseurBB &) const ;
    void operator += ( const TenseurBB &);
    TenseurBB & operator - () const ;  // oppose du tenseur
    TenseurBB & operator - ( const TenseurBB &) const ;
    void operator -= ( const TenseurBB &);
    TenseurBB & operator = ( const TenseurBB &) ;
	   TenseurBB & operator = ( const Tenseur3BB & B)
        { return this->operator=((TenseurBB &) B); };
	   TenseurBB & operator = ( const Tenseur_ns3BB & B)
        { return this->operator=((TenseurBB &) B); };
    TenseurBB & operator * ( const double &) const ;
    void operator *= ( const double &);
    TenseurBB & operator / ( const double &) const ;
    void operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur2BB & B,bool plusZero);  
             
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurBB & B,bool plusZero);
 
    // produit contracte avec un vecteur
    CoordonneeB operator * ( const CoordonneeH & ) const ;
    
    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    TenseurBB & operator * ( const TenseurHB &) const ;
    TenseurBH & operator * ( const TenseurHH &) const ;
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    double  operator && ( const TenseurHH &) const ;
         
    // test
    int operator == ( const TenseurBB &) const ;
    int operator != ( const TenseurBB &) const ;
    
    double  Det() const ;     // determinant de la matrice des coordonnees
         
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurHH & Inverse() const ;
         
    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    TenseurBB & Transpose() const ; 
    
    // ---- manipulation d'indice ---- -> création de nouveaux tenseurs
    virtual TenseurHH& Monte2Indices() const ;
    virtual TenseurHB& MontePremierIndice() const ;
    virtual TenseurBH& MonteDernierIndice() const ;

    // calcul du maximum en valeur absolu des composantes du tenseur
	   double MaxiComposante() const;
             
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
          
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
   
    //fonctions static définissant le produit tensoriel de deux vecteurs
    // si les vecteurs sont égaux le tenseur est symétrique sinon il est non symétrique
    static TenseurBB & Prod_tensoriel(const CoordonneeB & aB, const CoordonneeB & bB);
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
	 	 
     
    // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
    // dans l'ordre: (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3) 
    static int OdVect(const int i, const int j)  {return Tenseur3BB::cdex.odVect(i,j);};
    // transformation 1 indice -> 2 indices
    // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
    // dans l'ordre: (1,1) (2,2) (3,3) (2,1)=(1,2) (3,2)=(2,3) (3,1)=(1,3) 
    static int idx_i(const int k)  {return Tenseur3BB::cdex.idx_i(k);};
    static int idx_j(const int k)  {return Tenseur3BB::cdex.idx_j(k);};
	 	 	 
	  protected :
	   // allocator dans la liste de data
    listdouble6Iter ipointe;
    // --- gestion   d'index ----
    class ChangementIndex
     { public:
       ChangementIndex(); 
       // passage pour les index de la forme vecteur à la forme i,j
       Tableau <int> idx_i,idx_j; 
       // passage pour les index de la forme i,j à la forme vecteur
       Tableau2 <int> odVect;  
      };
    static const ChangementIndex  cdex;
};
/// @}  // end of group

class Tenseur_ns2BB;

/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes deux fois covariantes non symetriques
///          pour les differencier la dimension = -3
//--------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97
class Tenseur_ns3BB : public TenseurBB
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur_ns3BB &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur_ns3BB &);
  friend class Tenseur_ns2BB; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  friend class Tenseur_ns3HH;
  public :
      // Constructeur
    Tenseur_ns3BB() ; // par défaut
    // initialisation de toutes les composantes a une meme valeur val 
    Tenseur_ns3BB ( const double val) ;  
    // initialisation avec 9 valeurs différentes correspodantes aux trois
    // lignes : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    //  car le tableau n'est pas symetrique !!!!
    //  le premier indice = ligne, le second = colonne
    Tenseur_ns3BB
      ( const double val1,  const double val2,  const double val3,   // 1ere  ligne
        const double val4,  const double val5,  const double val6,   // 2ieme ligne
        const double val7,  const double val8,  const double val9) ; // 3ieme ligne
    // constructeur a partir d'une instance non differenciee  
    Tenseur_ns3BB (  const TenseurBB &); 
    // constructeur de copie  
    Tenseur_ns3BB (  const Tenseur_ns3BB &); 

    // DESTRUCTEUR :
    ~Tenseur_ns3BB();
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurBB & operator + ( const TenseurBB &) const ;
    void operator += ( const TenseurBB &);
    TenseurBB & operator - () const ;  // oppose du tenseur
    TenseurBB & operator - ( const TenseurBB &) const ;
    void operator -= ( const TenseurBB &);
    TenseurBB & operator = ( const TenseurBB &);
    TenseurBB & operator = ( const Tenseur3BB & B)
       { return this->operator=((TenseurBB &) B); };
    TenseurBB & operator = ( const Tenseur_ns3BB & B)
       { return this->operator=((TenseurBB &) B); };
    TenseurBB & operator * ( const double &) const ;
    void operator *= ( const double &);
    TenseurBB & operator / ( const double &) const ;
    void operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur_ns2BB & B,bool plusZero);  
             
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurBB & B,bool plusZero);
 
    // produit contracte avec un vecteur
    CoordonneeB operator * ( const CoordonneeH & ) const ;
    
    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    TenseurBB & operator * ( const TenseurHB &) const ;
    TenseurBH & operator * ( const TenseurHH &) const ;
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    double  operator && ( const TenseurHH &) const ;
         
    // test
    int operator == ( const TenseurBB &) const ;
    int operator != ( const TenseurBB &) const ;
    
    double  Det() const ;     // determinant de la matrice des coordonnees
         
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurHH & Inverse() const ;
         
    // ATTENTION creation d'un tenseur transpose qui est supprime par Libere
    TenseurBB & Transpose() const ; 
    
    // ---- manipulation d'indice ---- -> création de nouveaux tenseurs
    virtual TenseurHH& Monte2Indices() const ;
    virtual TenseurHB& MontePremierIndice() const ;
    virtual TenseurBH& MonteDernierIndice() const ;

    // calcul du maximum en valeur absolu des composantes du tenseur
    double MaxiComposante() const;
             
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
          
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
	 	 
     
     // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
     // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
     static int OdVect(const int i, const int j)  {return Tenseur_ns3BB::cdex.odVect(i,j);};
     // transformation 1 indice -> 2 indices
     // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
     // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
     static int idx_i(const int k)  {return Tenseur_ns3BB::cdex.idx_i(k);};
     static int idx_j(const int k)  {return Tenseur_ns3BB::cdex.idx_j(k);};
	 	 	 
	  protected :
	    // allocator dans la liste de data
     listdouble9Iter ipointe;
     // --- gestion   d'index ----
     class ChangementIndex
      { public:
        ChangementIndex(); 
        // passage pour les index de la forme vecteur à la forme i,j
        Tableau <int> idx_i,idx_j; 
        // passage pour les index de la forme i,j à la forme vecteur
        Tableau2 <int> odVect;  
       };
     static const ChangementIndex  cdex;
};
/// @}  // end of group

class Tenseur2BH;

/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes mixtes BH
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97
class Tenseur3BH : public TenseurBH
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur3BH &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur3BH &);
  friend class Tenseur2BH; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  public :
    // constructeur
    Tenseur3BH() ; // par défaut
    // initialisation de toutes les composantes a une meme valeur val 
    Tenseur3BH ( const double val) ;  
    // initialisation avec 9 valeurs différentes correspodantes aux trois
    // lignes : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    //  car le tableau n'est pas symetrique !!!!
    //  le premier indice = ligne, le second = colonne
    Tenseur3BH
      ( const double val1,  const double val2,  const double val3,   // 1ere  ligne
        const double val4,  const double val5,  const double val6,   // 2ieme ligne
        const double val7, const double val8, const double val9) ; // 3ieme ligne
  
    // DESTRUCTEUR :
    ~Tenseur3BH();
    // constructeur a partir d'une instance non differenciee  
    Tenseur3BH ( const  TenseurBH &); 
    // constructeur de copie  
    Tenseur3BH (  const Tenseur3BH &); 
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurBH & operator + ( const TenseurBH &) const ;
    void operator += ( const TenseurBH &);
    TenseurBH & operator - () const ;  // oppose du tenseur
    TenseurBH & operator - ( const TenseurBH &) const ;
    void operator -= ( const TenseurBH &);
    TenseurBH & operator = ( const TenseurBH &);
    TenseurBH & operator = ( const Tenseur3BH & B)
        { return this->operator=((TenseurBH &) B); };
    TenseurBH & operator * ( const double &) const ;
    void operator *= ( const double &);
    TenseurBH & operator / ( const double &) const ;
    void operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur2BH & B,bool plusZero);  
 
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurBH & B,bool plusZero);

    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    CoordonneeB operator * ( const CoordonneeB & ) const ;
    TenseurBB & operator * ( const TenseurBB &) const ; // produit une fois contracte
    TenseurBH & operator * ( const TenseurBH &) const ; // produit une fois contracte
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B c-c-d : A_i^{.k} * B_k^{.i}
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    // cela permet d'utiliser les mêmes variances pour les deux tenseurs

    double  operator && ( const TenseurBH &) const ; // produit deux fois contracte
         
    // test
    int operator == ( const TenseurBH &) const ;
    int operator != ( const TenseurBH &) const ;
        
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurBH & Inverse() const ;
    
    double  Trace() const ;   // trace du tenseur ou premier invariant
    double  II() const ;      // second invariant = trace (A*A)
    double  III() const ;     // troisieme invariant = trace ((A*A)*A)
    double  Det() const ;     // determinant de la matrice des coordonnees

    // valeurs propre  dans le vecteur  de retour, classée par ordres "décroissants"
    // cas indique le cas de valeur propre: 
    // cas = -1, si l'extraction des valeurs propres n'a pas pu se faire
    //           dans ce cas les valeurs propres de retour sont nulles par défaut
    // dim = 3 , cas = 1 si 3 val propres différentes, cas = 0 si les 3 sont identiques,
    //           cas = 2 si val(1)=val(2), cas = 3 si val(2)=val(3)
    virtual Coordonnee ValPropre(int& cas) const ;
    // idem met en retour la matrice mat contiend par colonne les vecteurs propre
    // elle doit avoir la dimension du tenseur
    // les vecteurs propre sont exprime dans le repere dual (contrairement au HB)  
    virtual Coordonnee ValPropre(int& cas, Mat_pleine& mat) const ;  

    // ici il s'agit uniquement de calculer les vecteurs propres, les valeurs propres
    // étant déjà connues
    // en retour VP les vecteurs propre: doivent avoir la dimension du tenseur
    // les vecteurs propre sont exprime dans le repere naturel (pour les tenseurs dim 3
    // pour dim=2:le premier vecteur propre est exprime dans le repere naturel 
    //            le second vecteur propre est exprimé dans le repère dual
    // pour dim=1 le vecteur est dans la base naturelle (mais ça importe pas)
    //   en sortie cas = -1 s'il y a eu un problème, dans ce cas, V_P est quelconque
    //             sinon si tout est ok, cas est identique en sortie avec l'entrée
    virtual void VecteursPropres(const Coordonnee& Val_P,int& cas, Tableau <Coordonnee>& V_P) const;
 
    // tenseur transpose
    TenseurHB & Transpose() const ; 
    // permute Bas Haut, mais reste dans le même tenseur
    void PermuteHautBas();
     
    // calcul du maximum en valeur absolu des composantes du tenseur
     double MaxiComposante() const;
             
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
          
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
   
    //fonctions static définissant le produit tensoriel de deux vecteurs
    static TenseurBH & Prod_tensoriel(const CoordonneeB & aB, const CoordonneeH & bH);
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
	 	 
     
     // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
     // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
     static int OdVect(const int i, const int j)  {return Tenseur3BH::cdex.odVect(i,j);};
     // transformation 1 indice -> 2 indices
     // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
     // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
     static int idx_i(const int k)  {return Tenseur3BH::cdex.idx_i(k);};
     static int idx_j(const int k)  {return Tenseur3BH::cdex.idx_j(k);};
	 	 	 
     protected :
	    // allocator dans la liste de data
	    listdouble9Iter ipointe;
	    // --- gestion   d'index ----
     class ChangementIndex
      { public:
        ChangementIndex(); 
        // passage pour les index de la forme vecteur à la forme i,j
        Tableau <int> idx_i,idx_j; 
        // passage pour les index de la forme i,j à la forme vecteur
        Tableau2 <int> odVect;  
       };
     static const ChangementIndex  cdex;
};
class Tenseur2HB;
/// @}  // end of group

/// @addtogroup Les_classes_tenseurs_dim3_ordre2
///  @{

//------------------------------------------------------------------
///  Definition des tenseur  derivees de dimension 3.
///          cas des composantes mixtes HB
//------------------------------------------------------------------
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97
class Tenseur3HB : public TenseurHB
{
 // surcharge de l'operator de lecture
  friend istream & operator >> (istream &, Tenseur3HB &);
 // surcharge de l'operator d'ecriture
  friend ostream & operator << (ostream &, const Tenseur3HB &);
  friend class Tenseur2HB; // pour le passage 2D 3D: méthode Affectation_2D_a_3D(..
  public :
      // Constructeur
    Tenseur3HB() ; // par défaut
    // initialisation de toutes les composantes a une meme valeur val 
    Tenseur3HB ( const double val) ;  
    // initialisation avec 9 valeurs différentes correspodantes aux trois
    // lignes : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    //  car le tableau n'est pas symetrique !!!!
    //  le premier indice = ligne, le second = colonne
    Tenseur3HB
      ( const double val1,  const double val2,  const double val3,   // 1ere  ligne
        const double val4,  const double val5,  const double val6,   // 2ieme ligne
        const double val7,  const double val8,  const double val9) ; // 3ieme ligne
    // constructeur a partir d'une instance non differenciee  
    Tenseur3HB (  const TenseurHB &); 
    // constructeur de copie  
    Tenseur3HB (  const Tenseur3HB &); 

    // DESTRUCTEUR :
    ~Tenseur3HB();
    
    // METHODES PUBLIQUES :
    // initialise toutes les composantes à val
    void Inita(double val);   
    // operations 
    TenseurHB & operator + ( const TenseurHB &) const ;
    void operator += ( const TenseurHB &);
    TenseurHB & operator - () const ;  // oppose du tenseur
    TenseurHB & operator - ( const TenseurHB &) const ;
    void operator -= ( const TenseurHB &);
    TenseurHB & operator = ( const TenseurHB &);
    TenseurHB & operator = ( const Tenseur3HB & B)
        { return this->operator=((TenseurHB &) B); };
    TenseurHB & operator * ( const double &) const ;
    void operator *= ( const double &);
    TenseurHB & operator / ( const double &) const ;
    void operator /= ( const double &);
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0 
    void Affectation_2D_a_3D(const Tenseur2HB & B,bool plusZero);  
             
    // affectation de B dans this,  plusZero = false: les données manquantes sont inchangées,
    // plusZero = true: les données manquantes sont mises à 0
    // si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
    // des données possibles
    void Affectation_trans_dimension(const TenseurHB & B,bool plusZero);
 
    // produit contracte avec un vecteur
    CoordonneeH operator * ( const CoordonneeH & ) const ;
    
    // produit contracte contracté une fois A(i,j)*B(j,k)=A.B
    // -> donc c'est l'indice du milieu qui est contracté
    TenseurHH & operator * ( const TenseurHH &) const ;
    TenseurHB & operator * ( const TenseurHB &) const ; // produit une fois contracte
    // produit contracte contracté deux fois A(i,j)*B(j,i)=A..B c-c-d : A^i_{.k} * B^k_{.i}
    // -> on contracte d'abord l'indice du milieu puis l'indice externe
    // cela permet d'utiliser les mêmes variances pour les deux tenseurs
    double  operator && ( const TenseurHB &) const ; // produit deux fois contracte
     
    // test
    int operator == ( const TenseurHB &) const ;
    int operator != ( const TenseurHB &) const ;
    
    // calcul du tenseur inverse par rapport au produit contracte
    TenseurHB & Inverse() const  ;
                  
    double  Trace() const ;   // trace du tenseur ou premier invariant
    double  II() const ;      // second invariant = trace (A*A)
    double  III() const ;     // troisieme invariant = trace ((A*A)*A)
    double  Det() const ;     // determinant de la matrice des coordonnees
    
    // valeurs propre  dans le vecteur  de retour, classée par ordres "décroissants"
    // cas indique le cas de valeur propre: 
    // cas = -1, si l'extraction des valeurs propres n'a pas pu se faire
    //           dans ce cas les valeurs propres de retour sont nulles par défaut
    // dim = 3 , cas = 1 si 3 val propres différentes, cas = 0 si les 3 sont identiques,
    //           cas = 2 si val(1)=val(2), cas = 3 si val(2)=val(3)
    virtual Coordonnee ValPropre(int& cas) const ;
    // idem met en retour la matrice mat contiend par colonne les vecteurs propre
    // elle doit avoir la dimension du tenseur
    // les vecteurs propre sont exprime dans le repere naturel  
    virtual Coordonnee ValPropre(int& cas, Mat_pleine& mat) const ;  

    // ici il s'agit uniquement de calculer les vecteurs propres, les valeurs propres
    // étant déjà connues
    // en retour VP les vecteurs propre: doivent avoir la dimension du tenseur
    // les vecteurs propre sont exprime dans le repere naturel (pour les tenseurs dim 3
    // pour dim=2:le premier vecteur propre est exprime dans le repere naturel 
    //            le second vecteur propre est exprimé dans le repère dual
    // pour dim=1 le vecteur est dans la base naturelle (mais ça importe pas)
    //   en sortie cas = -1 s'il y a eu un problème, dans ce cas, V_P est quelconque
    //             sinon si tout est ok, cas est identique en sortie avec l'entrée
    virtual void VecteursPropres(const Coordonnee& Val_P,int& cas, Tableau <Coordonnee>& V_P) const;
 
    // tenseur transpose
    TenseurBH & Transpose() const ; 
    // permute Bas Haut, mais reste dans le même tenseur
    void PermuteHautBas();
     
    // calcul du maximum en valeur absolu des composantes du tenseur
     double MaxiComposante() const;
             
    // retourne la composante i,j en lecture et écriture
	   double& Coor( const int i, const int j);
          
    // retourne la composante i,j en lecture seulement
	   double operator () ( const int i, const int j) const ;
    
//    inline operator TenseurHB & (void) 
//      { return *this;};
 
    //fonctions static définissant le produit tensoriel de deux vecteurs
    static TenseurHB & Prod_tensoriel(const CoordonneeH & aH, const CoordonneeB & bB);
	 
	   // lecture et écriture de données
    istream & Lecture(istream & entree);
    ostream & Ecriture(ostream & sort) const ;
	 	 
    // transformation 2 indices -> 1 indice (c-a-d vecteur unicolonne)
    // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    static int OdVect(const int i, const int j)  {return Tenseur3HB::cdex.odVect(i,j);};
    // transformation 1 indice -> 2 indices
    // en retour 2 indices : (k)(1) et (k)(2) -> les indices (i,j) 
    // dans l'ordre : (1,1) (1,2) (1,3) ; (2,1) (2,2) (2,3) ; (3,1) (3,2) (3,3) 
    static int idx_i(const int k)  {return Tenseur3HB::cdex.idx_i(k);};
    static int idx_j(const int k)  {return Tenseur3HB::cdex.idx_j(k);};
	 	 	 
	  protected :
	    // allocator dans la liste de data
     listdouble9Iter ipointe;
     // --- gestion   d'index ----
     class ChangementIndex
      { public:
        ChangementIndex(); 
        // passage pour les index de la forme vecteur à la forme i,j
        Tableau <int> idx_i,idx_j; 
        // passage pour les index de la forme i,j à la forme vecteur
        Tableau2 <int> odVect;  
       };
     static const ChangementIndex  cdex;
};
/// @}  // end of group

#include "Tenseur2.h" 
     
#ifndef MISE_AU_POINT
  #include "Tenseur3-1.cc"
  #include "Tenseur3-2.cc"
  #include "Tenseur3_ns.cc"
  #define  Tenseur3_H_deja_inclus
#endif
    
 
#endif  
