
// 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-2022 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: Calcul des differentes grandeurs liee a la deformation      *
 *     La classe fonctionne comme une boite a outil. On y choisit ce    *
 *     dont on a besoin. Bien faire attention a l'ordre d'appel des     *
 *     differentes methodes  lorsque il faut suivre une chronologie.    *
 *     Cette classe calcul mais ne stocke pas (ou très peu).            *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef DEFORMATION_H
#define DEFORMATION_H

#include "Tableau_T.h"
#include "Met_abstraite.h"
#include "Noeud.h"
#include "Enum_type_deformation.h"
#include "EnumTypeGradient.h"
#include "EnumTypeViteRotat.h"
#include "ThermoDonnee.h"
#include "TypeQuelconque.h"
#include "Enum_type_stocke_deformation.h"

/** @defgroup groupe_des_deformations
*
*     BUT: Calcul des differentes grandeurs liee a la deformation
*     La classe fonctionne comme une boite a outil. On y choisit ce
*     dont on a besoin. Bien faire attention a l'ordre d'appel des
*     differentes methodes  lorsque il faut suivre une chronologie.
*     Cette classe calcul mais ne stocke pas (ou très peu).
*
*
* \author    Gérard Rio
* \version   1.0
* \date       23/01/97
* \brief       groupe relatif aux calculs de déformation
*
*/

/// @addtogroup groupe_des_deformations
///  @{
///

///     BUT: Calcul des differentes grandeurs liee a la deformation
///     La classe fonctionne comme une boite a outil. On y choisit ce
///     dont on a besoin. Bien faire attention a l'ordre d'appel des
///     differentes methodes  lorsque il faut suivre une chronologie.
///     Cette classe calcul mais ne stocke pas (ou très peu).
///
///
/// \author    Gérard Rio
/// \version   1.0
/// \date       23/01/97

class  Deformation
{
  public :

    
    // CONSTRUCTEURS :
    Deformation () ; // par defaut ne doit pas etre utilise -> message
                       // d'erreur en phase de mise au point
    // constructeur normal dans le cas d'un ou de plusieurs pt d'integration             	  
    Deformation (Met_abstraite & ,Tableau<Noeud *>& tabnoeud,     
           Tableau <Mat_pleine> const & tabDphi,Tableau <Vecteur>const  & tabPhi, 
           Enum_type_deformation type_de_deformation = DEFORMATION_STANDART); 
    // constructeur de copie       
    Deformation (const Deformation &);  
    // DESTRUCTEUR :
    virtual ~Deformation (); 


// ----------------------------------------------------------------------------------------------
//     conteneurs basiques pour le stockage de variables spécifiques à un point de calcul 		 
// ----------------------------------------------------------------------------------------------

   // stockage métrique: uniquement les grandeurs à un instant donnée t, sans les variations
   // >>>> Grandeurs réellement créées (et non des pointeurs!!) -> sert pour les déformations par exemple	
   class Stmet
     { // surcharge de l'operator de lecture  avec le type
       friend istream & operator >> (istream &, Stmet &);
       // surcharge de l'operator d'ecriture
       friend ostream & operator << (ostream &, const Stmet &);
      public :
       Stmet ();// constructeur par défaut
        // constructeur normal : 
        //       dim_base: dimension des vecteurs de base, 
        //       nbvec_base : nb de vecteur de la base naturelle	
       Stmet (int dim_base, int nbvec_base);	  	        
       Stmet (const Stmet& ex) ; // constructeur de copie
       ~Stmet(); // destructeur
       Stmet& operator= (const Stmet& ex);  // surcharge d'affectation  
       void Affiche(); // affichage des infos
     // variables :
       BaseB *  giB_; BaseH * giH_; TenseurBB * gijBB_; TenseurHH * gijHH_; 
             TenseurBB * gradVmoyBB_;TenseurBB * gradVBB_; double* jacobien_;
     };

// ----------------------------------------------------------------------------------------------
//     fin: conteneurs pour le stockage de variables spécifiques à un point de calcul 		 
// ----------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// //   définition d'une classe conteneur spécifique à chaque point ou la déformation 
// //   est calculée

		class SaveDefResul 
		 { friend class Deformation;		 
		   public :
		    // Constructeurs 
		    SaveDefResul(); // constructeur par défaut-> à ne pas utiliser -> message d'erreur
		    SaveDefResul(const Met_abstraite& meta); // le constructeur recevable
		    SaveDefResul(const SaveDefResul& a); // constructeur de copie
		    ~SaveDefResul(); // destructeur
		    
		    // surcharge de l'optérateur d'affectation
		    virtual SaveDefResul& operator= (const SaveDefResul& a);  // surcharge d'affectation
		    
		    // affichage des infos
		    virtual void Affiche();	
		    // idem sur un ofstream
		    virtual void Affiche(ofstream& sort);			        
	     //============= lecture écriture dans base info ==========
         // cas donne le niveau de la récupération
         // = 1 : on récupère tout
         // = 2 : on récupère uniquement les données variables (supposées comme telles)
	     virtual void Lecture_base_info (ifstream& ent,const int cas);
         // cas donne le niveau de sauvegarde
         // = 1 : on sauvegarde tout
         // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
	     virtual void Ecriture_base_info(ofstream& sort,const int cas);
	     
	     // mise à jour des informations transitoires en définitif, ou l'inverse
	     virtual void TdtversT() {meti_t = meti_tdt;(*D_BB_t)=(*D_BB_tdt);};
	     virtual void TversTdt() {meti_tdt = meti_t;(*D_BB_tdt)=(*D_BB_t);};
	     // mise à jour des grandeurs meti_00 et à t
      // *** non car dans le cas d'un restart ce n'est pas vrai !!!! //et init par recopie des grandeurs sur t
	     virtual void MiseAJourGrandeurs_a_0(const Met_abstraite * metrique);
         // mise à jour des grandeurs meti_tdt
      virtual void MiseAJourGrandeurs_a_tdt(const Met_abstraite * metrique,const TenseurBB& Deps_BB);
         // il n'y a pas de mise à jour des grandeurs à t, car celles-ci sont mise à jour à l'aide
         // de la méthode TdtversT !!
				
				  // lecture des infos des métriques
				  const Deformation::Stmet& Meti_00() const {return meti_00;}
				  const Deformation::Stmet& Meti_t() const {return meti_t;}
				  const Deformation::Stmet& Meti_tdt() const {return meti_tdt;}
            
      Enum_type_stocke_deformation Type_stocke() const {return enu_type;};
	     
      protected :   // VARIABLES PROTEGEES :   
      Deformation::Stmet meti_00,meti_t,meti_tdt; // les infos à 0 à t et à tdt
      TenseurBB* D_BB_t,* D_BB_tdt; // vitesse de déformation à t et tdt:
         // on sauvegarde la vitesse, pour en particulier le cas ou on a un deltat trop petit
         // pour éviter une indécision, on reprend la valeur précédente stockée
    
      Enum_type_stocke_deformation enu_type; // type de stockage pour le cast lors de la verif de surchage
                                                   // entre instances non différenciées
   };

        // création d'une instance de SaveDefResul et initialisation.
		 virtual SaveDefResul * New_et_Initialise() {return (new SaveDefResul(*metrique));};
		 // affichage des donnees particulieres a l'elements
		 // de matiere traite ( c-a-dire au pt calcule)
		 virtual void AfficheDataSpecif(ofstream& sort,SaveDefResul * a) const {a->Affiche(sort);};
		 // met à jour les données spécifiques du point considéré
		 void Mise_a_jour_data_specif(Deformation::SaveDefResul* don) {saveDefResul=don;};		

//  //  fin de définition relatif à la  classe conteneur spécifique à chaque point  
//  //  ou la déformation est calculée
//------------------------------------------------------------------------------------
		      
   // définition d'une déformation du même type, permet d'utiliser des types dérivée surchargé
   virtual Deformation * Nevez_deformation(Tableau <Noeud *> & tabN) const 
     { Deformation* def = new Deformation(*this);def->PointeurTableauNoeud(tabN);return def;} ; 
   
   // réafectation du pointeur de tableau de noeuds interne
   // il faut que le nouveau tableau ait la même taille que l'ancien (sert pour créer de nouveau éléments
   // de même type par exemple, sinon ce n'est pas la bonne solution, 
   // il vaut mieux creer une nouvelle def
   void PointeurTableauNoeud(Tableau <Noeud *> & tabN);
   
   // Surcharge de l'operateur = : realise l'affectation
	  virtual Deformation& operator= (const Deformation& def);

   // change le type de déformation 
   virtual void Change_type_de_deformation(Enum_type_deformation type_de_def);
   
   
   // METHODES PUBLIQUES :
   
   // affichage des informations
   virtual void Affiche() const;

// ---------------- calcul des variables primaires pour la mécanique --------    
   // calcul explicit à t : tous les parametres sont des resultats
   virtual const Met_abstraite::Expli&  Cal_explicit_t
//                    (bool gradV_instantane,TenseurBB & epsBB_t,Tableau <TenseurBB *> & d_epsBB
//                    ,TenseurBB& DepsBB,TenseurBB& DeltaEpsBB,bool premier_calcul);
                   // def_equi_t: est la def equi au debut du pas, et def_equi est la def finale
                    (const Tableau <double>& def_equi_t,TenseurBB & epsBB_t,Tableau <TenseurBB *> & d_epsBB
                    ,Tableau <double>& def_equi,TenseurBB& DepsBB,TenseurBB& DeltaEpsBB,bool premier_calcul);
   // calcul explicit à tdt : tous les parametres sont des resultats
   virtual const Met_abstraite::Expli_t_tdt&  Cal_explicit_tdt
//                    ( bool gradV_instantane,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
//                     ,TenseurBB& DepsBB,TenseurBB& delta_epsBB_tdt,bool premier_calcul);
                    (const Tableau <double>& def_equi_t,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
                     ,Tableau <double>& def_equi,TenseurBB& DepsBB,TenseurBB& delta_epsBB_tdt,bool premier_calcul);
	  // cas implicite
	  virtual const Met_abstraite::Impli& Cal_implicit
//        ( bool gradV_instantane,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
//          ,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul);
         (const Tableau <double>& def_equi_t,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
          ,Tableau <double>& def_equi,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul);
 
//// ---------------- pour la mécanique calcul de l'élongation d'épaisseur pour les contraintes planes --------
//// ce calcul doit faire suite à un appel d'une des 3 fonctions précédentes
//   // calcul de l'élongation dans le sens de l'épaisseur. Cette déformaion n'est utile que pour des lois en contraintes planes
//   // - pour les lois 3D : retour d'un nombre très grand, indiquant que cette fonction est invalide
//   // - pour les lois 2D def planes: retour de 0
//   virtual double Elongation3_explicit() const {return ConstMath::tresgrand;};
//   // le tableau d_lambda3 contient les dérivées de l'élongation / au ddl
//   virtual double Elongation3_implicit(Tableau <double>& d_lambda3) const;
//

// ---------------- calcul des variables primaires autre que pour la mécanique --------
// ------------     donc pas de retour relatif aux déformations   
   // calcul explicit à t : tous les parametres sont des resultats
//   virtual const Met_abstraite::Expli&  Cal_explicit_t(bool gradV_instantane,bool premier_calcul)
//      {return metrique->Cal_explicit_t(tabnoeud,gradV_instantane,(*tabDphi)(numInteg),nbNoeud,premier_calcul);};
   virtual const Met_abstraite::Expli&  Cal_explicit_t(bool premier_calcul) 
      {return metrique->Cal_explicit_t(*tabnoeud,false,(*tabDphi)(numInteg),nbNoeud,(*tabPhi)(numInteg),premier_calcul);};
   // calcul explicit à tdt : tous les parametres sont des resultats
//   virtual const Met_abstraite::Expli_t_tdt&  Cal_explicit_tdt(bool gradV_instantane,bool premier_calcul)
//      {return metrique->Cal_explicit_tdt(*tabnoeud,gradV_instantane,(*tabDphi)(numInteg),nbNoeud,premier_calcul);};
   virtual const Met_abstraite::Expli_t_tdt&  Cal_explicit_tdt(bool premier_calcul)
      {return metrique->Cal_explicit_tdt(*tabnoeud,false,(*tabDphi)(numInteg),nbNoeud,(*tabPhi)(numInteg),premier_calcul);};
	  // cas implicite	
//	  virtual const Met_abstraite::Impli& Cal_implicit(bool gradV_instantane,bool premier_calcul)
//         {return metrique->Cal_implicit(*tabnoeud,gradV_instantane,(*tabDphi)(numInteg),nbNoeud,pa.Var_D(),premier_calcul);};
// avec_var_Xi  : par défaut true, si false indique que l'on ne calcule pas les variations / au ddl Xi
	  virtual const Met_abstraite::Impli& Cal_implicit(bool premier_calcul,bool avec_var_Xi=true)
         {return metrique->Cal_implicit(*tabnoeud,false,(*tabDphi)(numInteg),nbNoeud,(*tabPhi)(numInteg),premier_calcul,avec_var_Xi);};
//  ------------------------ flambage linéaire ------------------------------
     // le calcul est identique au cas implicite sauf que l'on doit absolument calculer la dérivée seconde de la déformation
	  virtual const Met_abstraite::flambe_lin& Cal_flambe_lin
//         ( bool gradV_instantane,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
//           ,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul);
         (const Tableau <double>& def_equi_t,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
           ,Tableau <double>& def_equi,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul);
// ------------------------- cas de la dynamique ------------------------
   // calcul des grandeurs utils pour les raideurs inertielles: c'est-à-dire le calcul de la matrice masse
   virtual const Met_abstraite::Dynamiq&  Cal_matMass()
       { return metrique->Cal_pourMatMass( *tabnoeud,(*tabDphi)(numInteg),nbNoeud,(*tabPhi)(numInteg));};
// ---------------- calcul de données interpolées aux même points d'integ que  la mécanique -------- 
//       et utilisées par la mécanique (ex: température, taux de cristalinité, vitesse, etc..)    
   virtual double DonneeInterpoleeScalaire(Enum_ddl enu,Enum_dure temps) const
       { return metrique->DonneeInterpoleeScalaire(*tabnoeud,(*tabPhi)(numInteg),nbNoeud,enu,temps); };
// --------- calcul de la variation d'une donnée interpolée par rapport aux ddl de la donnée ------
//       aux même points d'integ que  la mécanique --------
//       et utilisées par la mécanique (ex: température, taux de cristalinité, vitesse, etc..)
// en sortie : d_A
   virtual Tableau <double >&  DerDonneeInterpoleeScalaire(Tableau <double >& d_A, Enum_ddl enu,Enum_dure temps) const
       { return metrique->DerDonneeInterpoleeScalaire
                  (d_A,*tabnoeud,(*tabPhi)(numInteg),nbNoeud,enu); };
// ---------------- calcul du gradient d'une donnée interpolée aux même points d'integ que  la mécanique --------
//       et utilisées par la mécanique (ex: température, taux de cristalinité, vitesse, etc..)
// en sortie : gradB
   virtual CoordonneeB& GradDonneeInterpoleeScalaire(CoordonneeB& gradB, Enum_ddl enu,Enum_dure temps) const
       { return metrique->GradDonneeInterpoleeScalaire(gradB,*tabnoeud,(*tabDphi)(numInteg),nbNoeud,enu,temps); };
// --------- calcul de la variation du gradient d'une donnée interpolée par rapport aux ddl de la donnée ------
//       aux même points d'integ que  la mécanique --------
//       et utilisées par la mécanique (ex: température, taux de cristalinité, vitesse, etc..)
// en sortie : d_gradB
   virtual Tableau <CoordonneeB >& DerGradDonneeInterpoleeScalaire(Tableau <CoordonneeB >& d_gradB, Enum_ddl enu) const
       { return metrique->DerGradDonneeInterpoleeScalaire
                  (d_gradB,*tabnoeud,(*tabPhi)(numInteg),(*tabDphi)(numInteg),nbNoeud,enu); };
// --------- calcul de la variation seconde du gradient d'une donnée interpolée par rapport aux ddl de la donnée ------
//       aux même points d'integ que  la mécanique --------
//       et utilisées par la mécanique (ex: température, taux de cristalinité, vitesse, etc..)
// en sortie : d2_gradB
//  si d2_gradB est NULL cela signifie qu'il ne faut pas considérer cette grandeur
   virtual Tableau2 <CoordonneeB>*  Der2GradDonneeInterpoleeScalaire
               (Tableau2 <CoordonneeB>* d2_gradTB, Enum_ddl enu) const
       {return metrique->Der2GradDonneeInterpoleeScalaire
                  (d2_gradTB,*tabnoeud,(*tabPhi)(numInteg),(*tabDphi)(numInteg),nbNoeud,enu); };

//   virtual Vecteur& DonneeInterpoleeVecteur(Enum_ddl enu,Vecteur& v, Enum_dure temps)
//       { return metrique->DonneeInterpoleeVecteur(*tabnoeud,(*tabPhi)(numInteg),nbNoeud,enu,v,temps); };
//   virtual TenseurBB& DonneeInterpoleeTenseurBB(Enum_ddl enu,TenseurBB& t);
// ------------------------- cas de la dilatation thermique ------------------------
   // l'objectif est de calculer la déformation d'origine thermique et la déformation d'origine mécanique
   // temperature_tdt,temperature_t : températures, temperature_0: température initiale
   // atdt : booléen qui indique si les grandeurs à tdt sont disponible ou pas
   // avec_repercution_sur_def_meca: si oui on met à jour la déformation méca, sinon, on ne calcul que les def thermiques
   virtual void DeformationThermoMecanique(const double& temperature_0,const ThermoDonnee& dTP
                               ,const TenseurBB & epsBB_totale,TenseurBB & epsBB_therm,const double& temperature_tdt,TenseurBB & epsBB_meca
                               ,const TenseurBB & delta_epsBB_totale,TenseurBB & delta_epsBB_therm,TenseurBB & delta_epsBB_meca
                               ,const double& temperature_t,TenseurBB & DepsBB_totale,TenseurBB & DepsBB_therm,TenseurBB & DepsBB_meca
                               ,const Met_abstraite::Impli* ex_impli
                               ,const Met_abstraite::Expli_t_tdt* ex_expli_tdt
                               ,const Met_abstraite::Umat_cont* ex_umat
                               ,bool atdt, bool avec_repercution_sur_def_meca);
   // ----------- calcul et récupération de la dérivée de la vitesse de déformation virtuelle ----
   // calcul et récupération de la dérivée de la vitesse de déformation virtuelle à tdt
   // dans le cas d'une discrétisation classique simple, ce calcul est indépendant des coordonnées
   // donc peut être effectué indépendament du reste, il dépend cependant du point d'intégration 
   // dans le cas de discrétisation complexe, il faut s'assurer que les autres grandeurs utiles de la métrique
   // sont déjà calculé (cf. D2_gijBB_tdt() ) 
   //   total = true : indique que le calcul est complet, à partir des données de base 
   //                  c-a-d calcul de la variation de vecteur de base puis calcul de la variation seconde
   //         = false: le calcul est simplifié, on considère que la variation des vecteurs de base vient
   //                  juste d'être calculé, dans un calcul implicit, on ne calcul alors que la variation seconde
       
   void Cal_var_def_virtuelle(bool total,Tableau2 <TenseurBB *>& d2_epsBB_tdt);
   
	// ========== remontee aux informations =========================
	// calcul :
	// M0 : point d'integration numInteg a t = 0
	// Mt ou Mtdt : point d'integration final
	// Aa0 et Aafin : matrice de passage initiale et finale dans un repere ortho tel que
 // la nouvelle base Aa est calculee  par projection de "Ipa" sur Gi
 // gijHH et gijBB : metrique finale
 // Aa(i,a) = Aa^i_{.a}, avec  g^i = Aa^i_{.a} * Ip^a
 // tout ce passe comme si Ip^a est la nouvelle base vers laquelle on veut évoluer

   // cas sortie d'un calcul implicit
   virtual const Met_abstraite::InfoImp RemontImp(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // idem sans le calcul des matrices de passage
   virtual const Met_abstraite::InfoImp RemontImp();
   // cas sortie d'un calcul explicit à t
   virtual const Met_abstraite::InfoExp_t RemontExp_t(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // idem sans le calcul des matrices de passage
   virtual const Met_abstraite::InfoExp_t RemontExp_t();
   // cas sortie d'un calcul explicit à tdt
   virtual const Met_abstraite::InfoExp_tdt RemontExp_tdt(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // idem sans le calcul des matrices de passage
   virtual const Met_abstraite::InfoExp_tdt RemontExp_tdt();
   // cas sortie d'un calcul à 0, t et tdt
   virtual const Met_abstraite::Info0_t_tdt Remont0_t_tdt(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aat,Mat_pleine& Aatdt);
   // idem sans le calcul des matrices de passage
   virtual const Met_abstraite::Info0_t_tdt Remont0_t_tdt();

   // mêmes fct que précédemment mais dans le cas où les éléments de métrique viennent justes
   // d'être calculés, donc les seules grandeurs qui sont réellement calculées sont les matrices
   // Aa0 et Aafin
   // cas sortie d'un calcul implicit
   virtual const Met_abstraite::InfoImp RemontImpSansCalMet(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // cas sortie d'un calcul explicit à t
   virtual const Met_abstraite::InfoExp_t RemontExp_tSansCalMet(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // cas sortie d'un calcul explicit à tdt
   virtual const Met_abstraite::InfoExp_tdt RemontExp_tdtSansCalMet(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // cas sortie d'un calcul à 0, t et tdt
   virtual const Met_abstraite::Info0_t_tdt Remont0_t_tdtSansCalMet(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aat,Mat_pleine& Aatdt);
   // cas sortie d'un calcul à 0, t et tdt, y compris les métriques pour tous les temps
   virtual const Met_abstraite::Info_et_metrique_0_t_tdt Remont_et_metrique_0_t_tdtSansCalMet(bool absolue,Mat_pleine& Aa0,Mat_pleine& Aat,Mat_pleine& Aatdt);
   // cas sortie d'un calcul à 0, t et tdt, y compris les métriques pour tous les temps, pas de calcul de matrice
   // de passage
   virtual const Met_abstraite::Info_et_metrique_0_t_tdt Remont_et_metrique_0_t_tdtSansCalMet()
     { return metrique->Recup_Info_et_metrique_0_t_tdt();  };

   // calcul d'une déformation au temps donné: 
   // on suppose que gijHH et gijBB ont déjà été calculé à t=0, et à temps
   virtual void  Cal_deformation (Enum_dure temps, TenseurBB & epsBB);
                  
   // ramène le type de déformation actuellement utilisé
   Enum_type_deformation Type_de_deformation() const {return type_deformation;}; 
   // ramène le type de gradient de vitesse actuellement utilisé
   Enum_type_gradient  Type_de_gradient_vitesse() const {return type_gradient_vitesse;};	    

   // récupération des grandeurs particulière (hors ddl )
   // correspondant à liTQ
   // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
   virtual void Grandeur_particuliere(bool absolue,List_io<TypeQuelconque>& ) const {};
   // récupération de la liste de tous les grandeurs particulières
   // ces grandeurs sont ajoutées à la liste passées en paramètres
   // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
   virtual void ListeGrandeurs_particulieres(bool absolue,List_io<TypeQuelconque>& ) const {};
       
	  // -------------- fonctions utilitaires ----------------------------------
	  // ramene la taille du premier element de tabPhi, ce qui represente en general
	  // le nombre de point d'integration  pour les element  simple    
	  inline int Phi1_Taille() const { return tabPhi->Taille();};
      
   // change le numero d'integration courant
   virtual void ChangeNumInteg(int ni) {sauve_numInteg = numInteg; numInteg = ni;};
   // retourne le numero d'integration courant
   int NumInteg_en_cours() const {return numInteg;};
   // gestion du parcours de tous les points d'integration
   virtual void PremierPtInteg();
   virtual bool DernierPtInteg();
   virtual void NevezPtInteg();
   // méthode pour revenir au pti précédant
   virtual void Retour_pti_precedant();
   
   // calcul de la position dans le repère absolu du point d'intégration
   virtual const Coordonnee& Position_0()  // à t=0
     {return metrique->PointM_0(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Coordonnee& Position_t() // à t
     {return metrique->PointM_t(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Coordonnee& Position_tdt() // à t+dt
     {return metrique->PointM_tdt(*tabnoeud,(*tabPhi)(numInteg));}; 
   // calcul de la  variation dans le repère absolu du point d'intégration
   virtual const Tableau <Coordonnee>& Der_Pos_t() // à t
     {return metrique->D_PointM_t(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Tableau <Coordonnee>& Der_Posi_tdt() // à t+dt
     {return metrique->D_PointM_tdt(*tabnoeud,(*tabPhi)(numInteg));}; 
     
   // calcul de la vitesse dans le repère absolu du point d'intégration
   // dans le cas où les ddl de vitesse existent, ils sont directement interpolés
   // dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
   // à priori on calcul au point d'intégration: cas de la première fonction
   // on peut également appeler la fonction avec un numéro de noeud ou un pointeur de noeud
   // dans ces deux derniers cas la vitesses est calculée au noeud spécifié
   virtual const Coordonnee& VitesseM_0() {return metrique->VitesseM_0(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Coordonnee& VitesseM_0(int num_n) {return metrique->VitesseM_0((*tabnoeud)(num_n));}; 
   virtual const Coordonnee& VitesseM_0(const Noeud* noe) {return metrique->VitesseM_0(noe);}; 

   virtual const Coordonnee& VitesseM_t() {return metrique->VitesseM_t(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Coordonnee& VitesseM_t(int num_n) {return metrique->VitesseM_t((*tabnoeud)(num_n));}; 
   virtual const Coordonnee& VitesseM_t(const Noeud* noe) {return metrique->VitesseM_t(noe);}; 

   virtual const Coordonnee& VitesseM_tdt() {return metrique->VitesseM_tdt(*tabnoeud,(*tabPhi)(numInteg));}; 
   virtual const Coordonnee& VitesseM_tdt(int num_n) {return metrique->VitesseM_tdt((*tabnoeud)(num_n));}; 
   virtual const Coordonnee& VitesseM_tdt(const Noeud* noe) {return metrique->VitesseM_tdt(noe);}; 

   // calcul de la  variation dans le repère absolu de la vitesse du point d'intégration
   // ddl_vitesse : indique si oui ou non il s'agit de variation par rapport 
   //               aux ddl de vitesse ou au ddl de position 
   virtual const Tableau <Coordonnee>& Der_VitesseM_t(bool& ddl_vitesse) // à t
     {return metrique->D_VitesseM_t(*tabnoeud,(*tabPhi)(numInteg),ddl_vitesse);};
   virtual const Tableau <Coordonnee>& Der_VitesseM_t(bool& ddl_vitesse,int num_noeud) // à t
     {return metrique->D_VitesseM_t((*tabnoeud)(num_noeud),ddl_vitesse);};
   virtual const Tableau <Coordonnee>& Der_VitesseM_t(bool& ddl_vitesse,const Noeud* noe) // à t
     {return metrique->D_VitesseM_t(noe,ddl_vitesse);};

   virtual const Tableau <Coordonnee>& Der_VitesseM_tdt(bool& ddl_vitesse) // à t
     {return metrique->D_VitesseM_tdt(*tabnoeud,(*tabPhi)(numInteg),ddl_vitesse);};
   virtual const Tableau <Coordonnee>& Der_VitesseM_tdt(bool& ddl_vitesse,int num_noeud) // à t
     {return metrique->D_VitesseM_tdt((*tabnoeud)(num_noeud),ddl_vitesse);};
   virtual const Tableau <Coordonnee>& Der_VitesseM_tdt(bool& ddl_vitesse,const Noeud* noe) // à t
     {return metrique->D_VitesseM_tdt(noe,ddl_vitesse);};
            
   // détermination d'une bases particulière orthonormée pour représenter les tenseurs
   // en sortie on a une (ou plusieurs) matrices de passage, qui permettent de passer de la base curviligne
   // à cette base particulière que l'on va appeler IPa
   //  Le choix qui est fait est de calculer le passage gH(i) -> IPa ,
   //  c-a-d Aa(i,a) = les coordonnées de gH(i) dans la base IPa,
   //    ou encore: la ligne i de Aa = les coordonnées de gH(i)
   //  g^i = Aa^i_{.a} * Ip^a
   //  NB: si on a besoin du passage de gB(i) on utilise la matrice inverse de Aa
   //
   // 1)cas d'une base naturelle avec un nombre de vecteur == à la dimension de l'espace:
   // -> on retient comme base intéressante la base absolue Ia, donc ici IPa = Ia
   //  c-a-d que l'on calcul une matrice de passage pour arriver dans la base Ia à partir de gH(i)
   //  c'est le cas le plus simple qui semble naturel,
   //
   // 2)cas où le nombre de vecteur de la base naturelle = 2 dans un espace 3D
   // la nouvelle base IPa est calculee par projection de "Ia" sur Galpha
   // Premier cas: la projection du vecteur $\vec I_{1}$ sur l'élément est non nulle. Dans ce cas, cette projection
   //   est normalisée et tient lieu de premier vecteur de la base locale. Le troisième vecteur est constitué de
   //   la normale à l'élément, et le second vecteur est obtenu par produit vectoriel des deux premiers.
   // Second cas: la projection du vecteur $\vec I_{1}$  sur l'élément est nulle, on utilise alors la projection du
   //   vecteur $\vec I_{2}$ qui tient lieu alors de premier vecteur. La suite est identique au premier cas.
   //
   // 3)cas où le nombre de vecteur de la base naturelle = 1 dans un espace 2D
   // IP1 = le vecteur normé collinéaire avec gH(1) (qui est également collinéaire avec gB(1)
   // IP2 est normal à IP1, et choisit dans le sens direct
   //
   // 4) cas où le nombre de vecteur de la base naturelle = 1 dans un espace 3D
   // IP1 = le vecteur normé collinéaire avec gH(1) (qui est également collinéaire avec gB(1)
   // IP2 et IP3 sont normaux à IP1, et choisit de manière arbitraire dans le plan normal à IP1
   // normalement IP2 et IP3 ne servent pas pour exprimer des tenseurs qui utilisent la base naturelle
   // c'est pour cela qu'a priori on peut les choisir de manière quelconque
 
   // détermination des bases de passages (seules les données en entrées et sortie
   // sont utilisées: soit Aa(i,j) la matrice de passage (= Aa0, Aafin)
   virtual void BasePassage(bool absolue,const BaseB & giB0,const  BaseB & giB,const  BaseH & giH0,
          const BaseH & giH,Mat_pleine& Aa0,Mat_pleine& Aafin);
   // cas où l'on veut les matrices de passages à 0 t et tdt       
   virtual void BasePassage(bool absolue,const BaseB & giB0,const  BaseB & giB_t,const  BaseB & giB_tdt
                           ,const  BaseH & giH0,const BaseH & giH_t,const BaseH & giH_tdt
                              ,Mat_pleine& Aa0,Mat_pleine& Aa_t,Mat_pleine& Aa_tdt);
   // cas où l'on veut la matrice de passage à 0 uniquement
   virtual void BasePassage(bool absolue,const BaseB & giB0,const  BaseH & giH0,Mat_pleine& Aa0);
 
	  // ====== informations diverses (mais cohérentes, c-a-d, peuvent être appelées directement sans init) ====
	  double JacobienInitial()
	    { return metrique->JacobienInitial(*tabnoeud,(*tabDphi)(numInteg),nbNoeud,(*tabPhi)(numInteg));};

protected :      
   // VARIABLES PROTEGEES :
   Met_abstraite * metrique; // boite a outil pour le calcul 
                             // des differents tenseurs lies a la metrique
   // on utilise un pointeur de tableau pour tabnoeud car il faut pouvoir le réafecter,
   // par exemple après un constructeur de copie: il faut même bien faire attention de ne pas oublier !!                          
   Tableau<Noeud *>* tabnoeud;    // le tableau de noeud qui est interpolé 
	                              // mais on n'utilise pas forcément tous les noeuds !! le nombre de noeud
					  // utilisé est nbNoeud                        
   Tableau <Mat_pleine> const * tabDphi; // derivees de tous les fonctions d'interpolation
   Tableau <Vecteur> const * tabPhi;     // toutes les fonctions d'interpolation
      // derivees et fonctions d'interpolations au point d'integration courant
      // on utilise un tableau car certaine classe dérivee on 
   int nbNoeud;   // nb de noeud de l'interpolation  
   int numInteg; // numero du point d'integration en cours 
                        // dans le cas d'élément coque numInteg représente le pt d'integ de la surface
                        // dans le cas d'élément poutre, numInteg représente le pt d'integ de la ligne
   int sauve_numInteg; // sauvegarde pour un retour au pti précédant avec la  méthode Retour_pti_precedant();

   // identificateur interne de type de déformation, permet pour les classes dérivées
   // de faire du cast
   Enum_type_deformation type_deformation; 
   Enum_type_gradient  type_gradient_vitesse;  // idem pour le gradient de vitesse
   // une instance de données particulière
   SaveDefResul * saveDefResul; 
   
   // --- gestion   d'index ----
   class UtilIndexDeformation
	   { public:
	     UtilIndexDeformation(); 
        // def de deux tableaux d'indices pour avoir la suite: 12  21  13  31  23  32  à partir de 6 nombres
	     Tableau <int> iii,jjj; 
	    };
	  static const UtilIndexDeformation  ccdex;
	  // variables intermédiaires utilisées pour les calculs relatifs aux déformations cumulées ou logarithmiques
	  
	  TenseurBH* B_BH_tr; // tenseur B_BH
	  Tableau <TenseurBH * >* d_B_BH_tr; // variation du tenseur B_BH
	  Coordonnee ki; // vecteur des valeurs propres
	  Tableau <Coordonnee >* d_ki; // variation des valeurs propres
	  Tableau <TenseurBH* >* Palpha_BH_tr; // projecteurs propres
	  Tableau <Tableau <TenseurBH* > >* d_Palpha_BH_tr; // tableau des variation des projecteurs propres
	  int dimensionnement_tableaux; // =0 au début, =1 si dim des tab sans var, =2 si dim des tab avec var
	  
	  //-------- partie statique ou sont stocké tous les cas différents des variables précédentes
	  static list <Tableau <TenseurBH * > > list_var_tens_BH;
	  static list <Tableau <Tableau <TenseurBH* > > > list_var_var_tens_BH;
	  static list <Tableau <Coordonnee > > list_tab_coor;
	  static int nombre_d_instance_deformation;
   
   // METHODES PROTEGEES :
   // calcul implicite dans le cas d'une déformation d'Almansi
	  const Met_abstraite::Impli& Cal_implicit_Almansi (bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
           ,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul
           ,const Met_abstraite::Impli& ex);
   // calcul implicite dans le cas d'une déformation Logarithmique
	  const Met_abstraite::Impli& Cal_implicit_Logarithmique (bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
           ,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul
           ,const Met_abstraite::Impli& ex);
   // calcul implicite dans le cas d'une déformation tensorielle cumulée
	  const Met_abstraite::Impli& Cal_implicit_def_cumule (bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB
           ,TenseurBB& DepsBB,TenseurBB& delta_epsBB,bool premier_calcul
           ,const Met_abstraite::Impli& ex);
   // calcul explicite dans le cas d'une déformation d'Almansi
	  const Met_abstraite::Expli& Cal_explicit_Almansi (bool gradV_instantane
           ,TenseurBB & epsBB_t,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli& ex);
   // calcul explicite dans le cas d'une déformation logarithmique
	  const Met_abstraite::Expli& Cal_explicit_Logarithmique (bool gradV_instantane
           ,TenseurBB & epsBB_t,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli& ex);
   // calcul explicite dans le cas d'une déformation tensorielle cumulée
	  const Met_abstraite::Expli& Cal_explicit_def_cumule (bool gradV_instantane
           ,TenseurBB & epsBB_t,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli& ex);
   // calcul explicite à t et tdt dans le cas d'une déformation d'Almansi
	  const Met_abstraite::Expli_t_tdt& Cal_explicit_Almansi_tdt(bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli_t_tdt& ex);
   // calcul explicite à t et tdt dans le cas d'une déformation logarithmique
	  const Met_abstraite::Expli_t_tdt& Cal_explicit_logarithmique_tdt(bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli_t_tdt& ex);
   // calcul explicite à t et tdt dans le cas d'une déformation tensorielle cumulée
	  const Met_abstraite::Expli_t_tdt& Cal_explicit_def_cumule_tdt(bool gradV_instantane
           ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *> & d_epsBB,TenseurBB& DepsBB
           ,TenseurBB& delta_epsBB,bool premier_calcul,const Met_abstraite::Expli_t_tdt& ex);
   // ----- calcul uniquement de la déformation ------
       // on suppose que gijHH et gijBB ont déjà été calculé à t=0, et à temps
   // calcul de la deformation au temps donné  dans le cas d'une déformation d'Almansi
	  void Cal_Almansi_auTemps(Enum_dure temps, TenseurBB & epsBB);
   // calcul de la deformation au temps donné dans le cas d'une déformation logarithmique
	  void Cal_logarithmique_auTemps(Enum_dure temps, TenseurBB & epsBB);
   // calcul de la deformation au temps donnét dans le cas d'une déformation tensorielle cumulée
	  void Cal_def_cumule_auTemps(Enum_dure temps, TenseurBB & epsBB);
   // --- méthodes de vérifications ----
   void VerifCal_implicit(bool gradV_instantane,const Met_abstraite::Impli & ex,TenseurBB& DepsBB);
   // indicateur utilisé par VerifCal_deflog  
   static int indic_VerifCal_implicit; 
   
   // calcul d'une vitesse de rotation cohérente avec un référentiel objectif particulier
   void Cal_vite_rota_objectif(EnumTypeViteRotat type_rotation,bool variation,const TenseurBB&  gradVBB
                 ,const Tableau <TenseurBB * >& d_gradVBB
                 ,const TenseurBH& gijHH_0,const TenseurBB& gij_BB,Tableau <TenseurBB *> & d_gijBB
                 ,const TenseurHH& gij_HH,Tableau <TenseurHH *> & d_gijHH
                 ,const TenseurBB& D_BB, Tableau <TenseurBB *> & d_D_BB
                 ,TenseurBB& OmegaBB,Tableau <TenseurBB* > & d_OmegaBB);
   // fonction f et f' utilisé dans la méthode  Cal_vite_rota_objectif:
   double  F_pour_rotat_objectif(EnumTypeViteRotat type_rotation,const double& x);           
   double  Fprime_pour_rotat_objectif(EnumTypeViteRotat type_rotation,const double& x); 
   // calcul des valeurs propres, les projections propres, et les variations d'un tenseurs BH 
   // utilisé dans  Cal_vite_rota_objectif
   // cas_ki indique le cas des valeurs et vecteurs propres (cf TenseurBH)
     // quelque soit la dimension: 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 = 1, cas=1 pour une valeur propre; 
     // dim = 2 , cas = 1 si deux valeurs propres distinctes, cas = 0 si deux val propres identiques
     // dim = 3 , cas = 1 si 3 val propres différentes, cas = 0 si les 3 sont identiques,
     //           cas = 2 si ki(1)=ki(2), cas = 3 si ki(2)=ki(3)
   void Val_et_projection_prop_tenseur(const TenseurBH & B_BH,const Tableau <TenseurBH * >& d_B_BH
                     ,Coordonnee& ki,Tableau <TenseurBH* >& Palpha_BH,bool variation
                     ,Tableau <Coordonnee >& d_ki, Tableau <Tableau <TenseurBH* > >& d_Palpha_BH
                     ,int& cas_ki);
   // intégration de la vitesse de rotation
   void Integ_vitesse_rotation(); 
   // dimensionement ou vérif des dimensions des variables intermédiaires
   // utilisées pour les mesures cumulées et/ou log 
   void DimensionementVarLog(int dima,bool avec_var,int nbvar);                  
  private: // ---- fonctions internes de gestion de dimension  et autres----
   // verif si tableau de tenseur est bien dimensionné, ou alloue si nécessaire
   Tableau <TenseurBH * >* ExisteTabTenseur_BH_tr(int nbvar,Tableau <TenseurBH * >* tab_Tens,int dima) const ;
   // verif si le tableau de tableau de tenseur est bien dimensionné, ou alloue si nécessaire
   // dima: dimension des tenseur et du premier tableau, nbvar: dimension du tableau extérieur
   Tableau <Tableau <TenseurBH* > >* ExisteTabTabTenseur_BH_tr(int dima,Tableau <Tableau <TenseurBH* > >* tab_Tens,int nbvar) const ;
   // verif si tableau de Coordonnee est bien dimensionné, ou alloue si nécessaire
   Tableau <Coordonnee>* ExisteTabCoor_tr(int nbvar,Tableau <Coordonnee>* tab_coor,int dima) const ;
   // fonction qui calcule le tenseur logarithmique et sa variation éventuelle
   void Cal_Logarithmique (const TenseurBB & gijBB_0,const TenseurHH& gijHH_0,Tableau <TenseurBB *> & d_epsBB
                           ,const TenseurBB& gijBB,const TenseurHH& gijHH,TenseurBB & epsBB
                           ,const Tableau <TenseurBB *>& d_gijBB,bool variation);
   // méthode de vérification par différences finies du calcul des différentes dérivées                       
   void VerifCal_deflog(bool gradV_instantane,const Met_abstraite::Impli & ex,TenseurBB& epsBB_tdt
                         ,Tableau <TenseurBB *> & d_epsBB_tdt);

 };
 /// @}  // end of group

#endif  
