// FICHIER : Loi_Umat.cp
// CLASSE : Loi_Umat


// 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/>.


//#include "Debug.h"

# include <iostream>
using namespace std;  //introduces namespace std
#include <math.h>
#include <stdlib.h>
#include "Sortie.h"
#include "TypeConsTens.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "CharUtil.h"
#include "Util.h"

#include "Loi_Umat.h"

// ------------------fonctions interne template ------------
// multiplication de tenseur par des bases
template <class T1,class T2,class Base2,class Base1>  
T1 & produit_1_pourLoiUmat(T1 & A,T2& Nous, const Base2 & gi2, const Base1 & gi1)
    {  int dim = abs(A.Dimension());
        int dimint = abs(Nous.Dimension());
        for (int i=1;i<= dim; i++)
             for (int j=1; j<= dim; j++)
               { A.Coor(i,j) = 0.;
                  for (int al=1; al<= dimint; al++)
                     for (int be=1; be<= dimint; be++)
                        A.Coor(i,j) += Nous(al,be)* (gi1.Coordo(al)(i)*gi2.Coordo(be)(j)+gi2.Coordo(al)(i)*gi1.Coordo(be)(j));
                 }       
        return A;      
    };
      

//==================== cas de la class de sauvegarde SaveResul ===================

// constructeur  par défaut
Loi_Umat::SaveResul_Loi_Umat::SaveResul_Loi_Umat() :
	save_pour_loi_ext(NULL),hsurh0(ConstMath::tresgrand),h_tsurh0(ConstMath::tresgrand)
  {}; 

// constructeur de copie 
Loi_Umat::SaveResul_Loi_Umat::SaveResul_Loi_Umat(const Loi_Umat::SaveResul_Loi_Umat& sav ):
	save_pour_loi_ext(sav.save_pour_loi_ext),hsurh0(sav.hsurh0),h_tsurh0(sav.h_tsurh0)
	 {}; 
  
// affectation
Loi_comp_abstraite::SaveResul &
     Loi_Umat::SaveResul_Loi_Umat::operator = ( const Loi_comp_abstraite::SaveResul & a)
  { Loi_Umat::SaveResul_Loi_Umat& sav = *((Loi_Umat::SaveResul_Loi_Umat*) &a);
    // on affecte si non dimensionné, sinon on crée à l'identique
    if (sav.save_pour_loi_ext != NULL)
     { if (save_pour_loi_ext == NULL)
         {save_pour_loi_ext = sav.save_pour_loi_ext->Nevez_SaveResul();}
       else
         {(*save_pour_loi_ext) = *(sav.save_pour_loi_ext);};
     };
    hsurh0 = sav.hsurh0; h_tsurh0 = sav.h_tsurh0;
    return *this;
  };


//============= 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)
void Loi_Umat::SaveResul_Loi_Umat::Lecture_base_info (istream& ent,const int cas)
  {  // ici toutes les données sont toujours a priori variables
     // ou en tout cas pour les méthodes appelées, elles sont gérées par le paramètre: cas
     string toto; ent >> toto;
     int titi=0.;
     ent >> titi;
     if (titi == 1 )
       ent >> toto >> hsurh0; h_tsurh0 = hsurh0;
     
     #ifdef MISE_AU_POINT	 	 
      if (toto != "S_R_LoiUmat")
          { cout << "\n erreur en lecture du conteneur pour la loi Umat"
                 << " \n Loi_Umat::SaveResul_Loi_Umat::Lecture_base_info(..";
            Sortie(1);     
          }
     #endif
     if (save_pour_loi_ext!=NULL) 
        {save_pour_loi_ext->Lecture_base_info(ent,cas);};
  }; 

// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Loi_Umat::SaveResul_Loi_Umat::Ecriture_base_info (ostream& sort,const int cas)
   { // ici toutes les données sont toujours a priori variables
     // ou en tout cas pour les méthodes appelées, elles sont gérées par le paramètre: cas
     sort << "\n S_R_LoiUmat  "; 
     if (hsurh0 != ConstMath::tresgrand )
       sort << "\n 1 " << "CP:hsurh0= " << h_tsurh0;
     else  sort << "\n 0 ";
     if (save_pour_loi_ext!=NULL)
        {save_pour_loi_ext->Ecriture_base_info(sort,cas);};
   };
	        
	        // mise à jour des informations transitoires en définitif s'il y a convergence 
	        // par exemple (pour la plasticité par exemple)
void Loi_Umat::SaveResul_Loi_Umat::TdtversT() 
   {  if (save_pour_loi_ext!=NULL) 
        save_pour_loi_ext->TdtversT();
      // CP par défaut: car c'est aussi rapide que le test (sans doute ?)
      h_tsurh0 = hsurh0;
      
	  }; 
void Loi_Umat::SaveResul_Loi_Umat::TversTdt() 
   {  if (save_pour_loi_ext!=NULL) 
        save_pour_loi_ext->TversTdt();
      // CP par défaut: car c'est aussi rapide que le test (sans doute ?)
      hsurh0 = h_tsurh0;
	  };

//==================== fin du cas de la class de sauvegarde SaveResul ============

Loi_Umat::Loi_Umat (Enum_comp enu)  : // Constructeur par defaut
  Loi_comp_abstraite(enu,CAT_MECANIQUE,0)
  ,nom_de_la_loi("_")
  ,umatAbaqus(ParaGlob::Dimension(),Loi_Umat::Choix_dim(enu))
  ,loi_ext(NULL)
  ,utilisation_umat_interne(NULL)
  ,umat_met3D(),umat_met2D(),umat_met1D()
  ,d_sigma_deps_2D(),d_sigma_deps_1D()
  ,gabBB_tdt(NULL),gabHH_tdt(NULL),gabBB_t(NULL),gabHH_t(NULL)
  ,gixB_0(),gixB_t(),gixB_tdt(),gixH_0(),gixH_t(),gixH_tdt() 
  // des pointeurs nulles pour les grandeurs qui actuellement ne servent pas
  ,ggaB_0null(NULL),ggaB_tnull(NULL),ggaH_0null(NULL)
  ,ggradVmoyBB_tnull(NULL),ggradVmoyBB_tdtnull(NULL),ggradVBB_tdtnull(NULL)

  // --//\\-- grandeurs particulières pour le cas contraintes planes
  // -- conteneur des métriques
  ,umat_cont_3D(NULL)
  ,umat_cont_2D(NULL)
  ,Ip2_B(ParaGlob::Dimension(),2) // pour définir la base 2D locale dans l'espace de travail
  // -- les variables pointées dans les conteneurs, et leur pointeur associé éventuellement
  ,giB_0_3D(),giH_0_3D(),giB_t_3D(),giH_t_3D(),giB_tdt_3D(),giH_tdt_3D()
  ,gijBB_0_3D(),gijHH_0_3D(),gijBB_t_3D(),gijHH_t_3D()
  ,gijBB_tdt_3D(),gijHH_tdt_3D()
  ,gradVmoyBB_t_3D(),gradVmoyBB_tdt_3D(),gradVBB_tdt_3D()
  ,gradVmoyBB_t_3D_P(NULL),gradVmoyBB_tdt_3D_P(NULL),gradVBB_tdt_3D_P(NULL)
  ,jacobien_tdt_3D(0.),jacobien_0_3D(0.)
  // idem en 2D
  ,Ip3B_0_3D(),Ip3H_0_3D() // ne fait pas partie de umat_cont_2D
  ,giB_0_2D(ParaGlob::Dimension(),2),giH_0_2D(ParaGlob::Dimension(),2)
  ,giB_t_2D(ParaGlob::Dimension(),2),giH_t_2D(ParaGlob::Dimension(),2)
  ,giB_tdt_2D(ParaGlob::Dimension(),2),giH_tdt_2D(ParaGlob::Dimension(),2)
  ,gijBB_0_2D(),gijHH_0_2D(),gijBB_t_2D(),gijHH_t_2D()
  ,gijBB_tdt_2D(),gijHH_tdt_2D()
  ,gradVmoyBB_t_2D(),gradVmoyBB_tdt_2D(),gradVBB_tdt_2D()
  ,gradVmoyBB_t_2D_P(NULL),gradVmoyBB_tdt_2D_P(NULL),gradVBB_tdt_2D_P(NULL)
  ,jacobien_tdt_2D(0.),jacobien_0_2D(0.)

  // --//\\-- fin grandeurs particulières pour le cas contraintes planes

    { // définition de la métrique umat
      int dim_base=3;
      int nbvec_base_3D=3;
      DdlElement  tabddl; // init par défaut -> pas de ddl élément
      int nb_noeud_interpol=0; // par de noeud, on n'a pas a s'en servir normalement
	     umat_met3D.Dim_NbVec(dim_base,nbvec_base_3D,tabddl,nb_noeud_interpol);
      int nbvec_base_2D=2;//dim_base=2;
      umat_met2D.Dim_NbVec(dim_base,nbvec_base_2D,tabddl,nb_noeud_interpol);
      int nbvec_base_1D=1;//dim_base=1;
      umat_met1D.Dim_NbVec(dim_base,nbvec_base_1D,tabddl,nb_noeud_interpol);
	     // on definit les variables a priori toujours utiles
      Tableau<Enum_variable_metrique> tab(13);
      tab(1)=igiB_0;tab(2)=igiB_t;tab(3)=igiB_tdt;
      tab(4)=igiH_0;tab(5)=igiH_t;tab(6)=igiH_tdt ;
      tab(7)=igijBB_0;tab(8)=igijBB_t;tab(9)=igijBB_tdt;
      tab(10)=igijHH_0;tab(11)=igijHH_t;tab(12)=igijHH_tdt ;
      tab(13)=igradVmoyBB_t;
      umat_met3D.PlusInitVariables(tab) ;
      umat_met2D.PlusInitVariables(tab) ;
      umat_met1D.PlusInitVariables(tab) ;

      // --//\\-- grandeurs particulières pour le cas contraintes planes
      umat_cont_3D = new Met_abstraite::Umat_cont  // constructeur normal
                          (&giB_0_3D,&giH_0_3D,&giB_t_3D,&giH_t_3D,&giB_tdt_3D,&giH_tdt_3D
                          ,&gijBB_0_3D,&gijHH_0_3D,&gijBB_t_3D,&gijHH_t_3D
                          ,&gijBB_tdt_3D,&gijHH_tdt_3D
                          ,gradVmoyBB_t_3D_P,gradVmoyBB_tdt_3D_P,gradVBB_tdt_3D_P      // pas affecté par défaut
                          ,&jacobien_tdt_3D,&jacobien_t_3D,&jacobien_0_3D);
       // idem 2D
       umat_cont_2D = new Met_abstraite::Umat_cont  // constructeur normal
                          (&giB_0_2D,&giH_0_2D,&giB_t_2D,&giH_t_2D,&giB_tdt_2D,&giH_tdt_2D
                          ,&gijBB_0_2D,&gijHH_0_2D,&gijBB_t_2D,&gijHH_t_2D
                          ,&gijBB_tdt_2D,&gijHH_tdt_2D
                          ,gradVmoyBB_t_2D_P,gradVmoyBB_tdt_2D_P,gradVBB_tdt_2D_P      // pas affecté par défaut
                          ,&jacobien_tdt_2D,&jacobien_t_2D,&jacobien_0_2D);
     // --//\\-- fin grandeurs particulières pour le cas contraintes planes

     
    };
	
// Constructeur de copie
Loi_Umat::Loi_Umat (const Loi_Umat& loi) :
   Loi_comp_abstraite(loi)
   ,nom_de_la_loi(loi.nom_de_la_loi),umatAbaqus(loi.umatAbaqus)
   ,loi_ext(loi.loi_ext),utilisation_umat_interne(loi.utilisation_umat_interne)
   ,umat_met3D(loi.umat_met3D),umat_met2D(loi.umat_met2D),umat_met1D(loi.umat_met1D)
   ,d_sigma_deps_2D(loi.d_sigma_deps_2D),d_sigma_deps_1D(loi.d_sigma_deps_1D)
   ,gabBB_tdt(NULL),gabHH_tdt(NULL),gabBB_t(NULL),gabHH_t(NULL)
   ,gixB_0(),gixB_t(),gixB_tdt(),gixH_0(),gixH_t(),gixH_tdt() 

  // -- conteneur des métriques: ce sont des pointeurs, pour l'instant on ne les affecte pas
  ,umat_cont_3D(NULL)
  ,umat_cont_2D(loi.umat_cont_2D) // umat_cont_2D avec uniquement des pointeurs
  ,Ip2_B(loi.Ip2_B) // pour définir la base 2D locale dans l'espace travail
  // -- les variables pointées dans les conteneurs
  ,giB_0_3D(loi.giB_0_3D),giH_0_3D(loi.giH_0_3D),giB_t_3D(loi.giB_t_3D),giH_t_3D(loi.giH_t_3D)
  ,giB_tdt_3D(loi.giB_tdt_3D)
  ,gijBB_0_3D(loi.gijBB_0_3D),gijHH_0_3D(loi.gijHH_0_3D)
  ,gijBB_t_3D(loi.gijBB_t_3D),gijHH_t_3D(loi.gijHH_t_3D),gijBB_tdt_3D(loi.gijBB_tdt_3D)
  ,gijHH_tdt_3D(loi.gijHH_tdt_3D),gradVmoyBB_t_3D(loi.gradVmoyBB_t_3D)
  ,gradVmoyBB_tdt_3D(loi.gradVmoyBB_tdt_3D),gradVBB_tdt_3D(loi.gradVBB_tdt_3D)
  ,jacobien_0_3D(loi.jacobien_0_3D)
  // idem en 2D
  ,Ip3B_0_3D(loi.Ip3B_0_3D),Ip3H_0_3D(loi.Ip3H_0_3D) // ne fait pas partie de umat_cont_2D
  ,giB_0_2D(loi.giB_0_2D),giH_0_2D(loi.giH_0_2D),giB_t_2D(loi.giB_t_2D),giH_t_2D(loi.giH_t_2D)
  ,giB_tdt_2D(loi.giB_tdt_2D)
  ,gijBB_0_2D(loi.gijBB_0_2D),gijHH_0_2D(loi.gijHH_0_2D)
  ,gijBB_t_2D(loi.gijBB_t_2D),gijHH_t_2D(loi.gijHH_t_2D),gijBB_tdt_2D(loi.gijBB_tdt_2D)
  ,gijHH_tdt_2D(loi.gijHH_tdt_2D),gradVmoyBB_t_2D(loi.gradVmoyBB_t_2D)
  ,gradVmoyBB_tdt_2D(loi.gradVmoyBB_tdt_2D),gradVBB_tdt_2D(loi.gradVBB_tdt_2D)
  ,jacobien_0_2D(loi.jacobien_0_2D)

     { gabBB_tdt=NevezTenseurBB(*loi.gabBB_tdt);gabHH_tdt=NevezTenseurHH(*loi.gabHH_tdt);
       gabBB_t=NevezTenseurBB(*loi.gabBB_t);gabHH_t=NevezTenseurHH(*loi.gabHH_t);
       // association des pointeurs de grandeurs si nécessaire
       if (loi.gradVmoyBB_t_3D_P != NULL) {gradVmoyBB_t_3D_P = &gradVmoyBB_t_3D;};
       if (loi.gradVmoyBB_tdt_3D_P != NULL) {gradVmoyBB_tdt_3D_P = &gradVmoyBB_tdt_3D;};
       if (loi.gradVBB_tdt_3D_P != NULL) {gradVBB_tdt_3D_P = &gradVBB_tdt_3D;};
       umat_cont_3D = new Met_abstraite::Umat_cont  // constructeur normal
                          (&giB_0_3D,&giH_0_3D,&giB_t_3D,&giH_t_3D,&giB_tdt_3D,&giH_tdt_3D
                          ,&gijBB_0_3D,&gijHH_0_3D,&gijBB_t_3D,&gijHH_t_3D
                          ,&gijBB_tdt_3D,&gijHH_tdt_3D
                          ,gradVmoyBB_t_3D_P,gradVmoyBB_tdt_3D_P,gradVBB_tdt_3D_P      // pas affecté par défaut
                          ,&jacobien_tdt_3D,&jacobien_t_3D,&jacobien_0_3D);
       // idem 2D
       umat_cont_2D = new Met_abstraite::Umat_cont  // constructeur normal
                          (&giB_0_2D,&giH_0_2D,&giB_t_2D,&giH_t_2D,&giB_tdt_2D,&giH_tdt_2D
                          ,&gijBB_0_2D,&gijHH_0_2D,&gijBB_t_2D,&gijHH_t_2D
                          ,&gijBB_tdt_2D,&gijHH_tdt_2D
                          ,gradVmoyBB_t_2D_P,gradVmoyBB_tdt_2D_P,gradVBB_tdt_2D_P      // pas affecté par défaut
                          ,&jacobien_tdt_2D,&jacobien_t_2D,&jacobien_0_2D);
   };

Loi_Umat::~Loi_Umat ()
// Destructeur 
{ if (gabBB_tdt != NULL) delete gabBB_tdt;
  if (gabHH_tdt != NULL) delete gabHH_tdt;
  if (gabBB_t != NULL) delete gabBB_t;
  if (gabHH_t != NULL) delete gabHH_t;
  // les conteneurs de pointeurs:
  delete umat_cont_3D;
  delete umat_cont_2D;

  // pour les grandeurs de base, pas de new, donc pas de delete

};

// def d'une instance de données spécifiques, et initialisation
Loi_comp_abstraite::SaveResul * Loi_Umat::New_et_Initialise() 
  { Loi_comp_abstraite::SaveResul* sav = new SaveResul_Loi_Umat();
     // dans le cas ou la loi est interne on stocke ses infos égalements
    if (utilisation_umat_interne)
    	 { SaveResul_Loi_Umat* sv = (SaveResul_Loi_Umat*) sav;
    	   sv->save_pour_loi_ext = ((Loi_comp_abstraite*)loi_ext)->New_et_Initialise();
    	 };
    return sav;
  };

// fonction de travail
int Loi_Umat::Choix_dim(Enum_comp enu)
 {if(enu == LOI_VIA_UMAT_CP)
    return 2;
  else
    return 3;
 };


// Lecture des donnees de la classe sur fichier
void Loi_Umat::LectureDonneesParticulieres (UtilLecture * entreePrinc,LesCourbes1D&
                               ,LesFonctions_nD& lesFonctionsnD)
  { // lecture du nom de la loi
    string toto;
    *(entreePrinc->entree) >> toto >> nom_de_la_loi;
    if (toto != "nom_de_la_loi=") 
         { cout << "\n erreur en lecture du nom de la loi, on aurait du lire le mot cle nom_de_la_loi="
                << " suivi du nom de la loi ";
           entreePrinc->MessageBuffer("**erreur1: Loi_Umat::LectureDonneesParticulieres(... **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
    // lecture de la catégorie
    string categorie;
    *(entreePrinc->entree) >> toto >> categorie;
    if (toto != "categorie=") 
         { cout << "\n erreur en lecture du nom de la loi, on aurait du lire le mot cle categorie="
                << " suivi du nom de la categorie ";
           entreePrinc->MessageBuffer("**erreur2: Loi_Umat::LectureDonneesParticulieres(... **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
    // on met à jour la catégorie de la loi
    Enum_categorie_loi_comp cat = Id_nom_categorie_loi_comp(categorie.c_str());
    ChangeCategorie(cat);
    if (cat==CAT_THERMO_MECANIQUE) {thermo_dependant=true;}
    else                           {thermo_dependant=false;};
    // lecture de la dimension
    string dimension;
    *(entreePrinc->entree) >> toto >> dimension;
    if (toto != "dim_loi=") 
         { cout << "\n erreur en lecture du nom de la loi, on aurait du lire le mot cle dim_loi="
                << " suivi de la dimension: 1D ou 2D ou 3D ";
           entreePrinc->MessageBuffer("**erreur3: Loi_Umat::LectureDonneesParticulieres(... **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
    // on met à jour la dimension de la loi
    if ((dimension== "1D") || (dimension=="1"))        {Change_dimension(1); }
	   else if ((dimension == "2D") || (dimension=="2"))   {Change_dimension(2); }
	   else if ((dimension == "3D") || (dimension=="3"))   {Change_dimension(3); }
	   else
      { cout << "\n erreur en lecture de la dimension de la loi geree par umat"
             << " on devrait lire 1 ou 2 ou 3 ou 1D ou 2D ou 3D";
        entreePrinc->MessageBuffer("**erreur4: Loi_Umat::LectureDonneesParticulieres(... **");
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
      };
	 
    string nom_class_methode("Loi_Umat::LectureDonneesParticulieres");
	   // lecture de la ligne qui suit
	   entreePrinc->NouvelleDonnee(); 
	   *(entreePrinc->entree) >> toto;
	   if (toto != "fin_loi_Umat")
     { if (toto == "nom_pipe_envoi=") 
     	  {// lecture du nom du pipe d'envoi
     	   string nom_pipe_envoi; *(entreePrinc->entree) >> nom_pipe_envoi;
     	   umatAbaqus.Change_nom_pipe_envoi(nom_pipe_envoi);
     	   *(entreePrinc->entree) >> toto;
     	   // on regarde si éventuellement il y a le pipe de reception
     	   if(toto == "nom_pipe_reception=")
     	 	  { string nom_pipe_reception; *(entreePrinc->entree) >> nom_pipe_reception;
     	      umatAbaqus.Change_nom_pipe_reception(nom_pipe_reception);
     	 	  }
     	   else 	
          { cout << "\n erreur en lecture du nom du pipe de reception, on aurait du lire le mot "
                 << " cle nom_pipe_reception=, suivi du nom du pipe ";
            entreePrinc->MessageBuffer("**erreur5: Loi_Umat::LectureDonneesParticulieres(... **");
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);     
          };
         entreePrinc->NouvelleDonnee();// préparation du flot
         if(strstr(entreePrinc->tablcar,"permet_affichage_")!=0)
          {// on lit le niveau de commentaire
           string nom; *(entreePrinc->entree) >> nom;
           Lecture_permet_affichage(entreePrinc,lesFonctionsnD);
//           string mot_cle("permet_affichage_");
//           entreePrinc->Lecture_un_parametre_int(0,nom_class_methode
//                        ,0, 10,mot_cle,permet_affichage);
           entreePrinc->NouvelleDonnee();// préparation du flot
          };
     	  }
       else if (toto == "utilisation_umat_interne")	
        {// cas d'une umat interne
         utilisation_umat_interne=true;
         entreePrinc->NouvelleDonnee();// préparation du flot
         if(strstr(entreePrinc->tablcar,"permet_affichage_")!=0)
          {// on lit le niveau de commentaire
           string nom; *(entreePrinc->entree) >> nom;
           Lecture_permet_affichage(entreePrinc,lesFonctionsnD);
//           string mot_cle("permet_affichage_");
//           entreePrinc->Lecture_un_parametre_int(0,nom_class_methode
//                        ,0, 10,mot_cle,permet_affichage);
           entreePrinc->NouvelleDonnee();// préparation du flot
          };
         if(strstr(entreePrinc->tablcar,"fin_loi_Umat")==0)
          { cout << "\n erreur en lecture de la fin de la loi on devrait  avoir le mot cle fin_loi_Umat "
                 << " soit le mot cle : permet_affichage_ ";
            entreePrinc->MessageBuffer("**erreur6: Loi_Umat::LectureDonneesParticulieres(... **");
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);     
          };
        }
       else	
        { cout << "\n erreur en lecture de la fin de la loi on devrait soit avoir le mot cle fin_loi_Umat "
               << " ou alors les noms des pipes d'envoi et de reception (cf doc) ";
          entreePrinc->MessageBuffer("**erreur7: Loi_Umat::LectureDonneesParticulieres(... **");
          throw (UtilLecture::ErrNouvelleDonnee(-1));
          Sortie(1);     
        };
     };

    // appel au niveau de la classe mère
    Loi_comp_abstraite::Lecture_type_deformation_et_niveau_commentaire
                 (*entreePrinc,lesFonctionsnD);

  };

// affichage de la loi
void Loi_Umat::Affiche() const 
  { cout << "\n loi de comportement Umat "<<dim<<"D : "<< nom_de_la_loi << " ";
    if(thermo_dependant) {cout << " thermodependante ";};
    cout << " categorie " << Nom_categorie_loi_comp(categorie_loi_comp) << " "; 
    Loi_comp_abstraite::Affiche_don_classe_abstraite();
  };
            
// affichage et definition interactive des commandes particulières à chaques lois
void Loi_Umat::Info_commande_LoisDeComp(UtilLecture& entreePrinc)
 {  ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
	   cout << "\n definition standart (rep o) ou exemples exhaustifs (rep n'importe quoi) ? ";
	   string rep = "_";     // procédure de lecture avec prise en charge d'un retour chariot
    rep = lect_return_defaut(true,"o");

    sort << "\n# ----------------------------------------------------------"
         << "\n# |     exemple de loi de comportement defini en Umat      |"
         << "\n# |      via un processus qui dialogue avec herezh++       |"
         << "\n# ----------------------------------------------------------"
         << "\n    nom_de_la_loi= acier    categorie=   CAT_MECANIQUE   dim_loi=  3  "
         << "\n    nom_pipe_envoi= pipe_envoi nom_pipe_reception= pipe_reception  "
         << "\n        fin_loi_Umat  " << endl ;
	   if ((rep != "o") && (rep != "O" ) && (rep != "0") )
      { sort << "\n ....................................................................................."
         << "\n#  NB:  en contrainte plane, la loi se nomme LOI_VIA_UMAT_CP et il faut utiliser : dim_loi=  2  "
         << "\n#  - le nom de la loi, peut permettre le choix entre plusieurs Umat "
         << "\n#  - les differentes categorie sont: "
         << "\n#      CAT_MECANIQUE         pour une loi utilisable pour un calcul mecanique "
         << "\n#      CAT_THERMO_MECANIQUE  pour une loi utilisable pour un calcul thermo-mecanique "
         << "\n#      CAT_THERMO_PHYSIQUE   pour une loi thermo-physique "
         << "\n#  - dim_loi peut etre: "
//         << "\n#        1D   : permet la traction - compression "
         << "\n#        2D   : 2D contraintes planes ou deformations planes"
         << "\n#        3D   : 3D classique (sans particularite) "
         << "\n#  - la ligne suivante est facultative (par contre si elle existe elle doit etre complete)"
         << "\n#     nom_pipe_envoi= suivi du nom du pipe d'envoi (par defaut = Umat_reception_Hz "
         << "\n#     nom_pipe_reception= suivi du nom du pipe de recepetion (par defaut= Umat_envoi_Hz "
         << "\n#  - a la place des nom de pipe il est possible de mettre le mot cle: utilisation_umat_interne "         
         << "\n#    dans ce cas il n'est pas fait appel au pipe, on travail directement avec une loi interne "         
         << "\n#    defini dans le fichier .info d'entree d'herezh "
         << "\n#    permet_affichage_ <un entier> :"
         << "\n#  -  mot cle fin_loi_Umat "
         << "\n#  - ensuite il est possible de definir le type de deformation a utiliser "
         << "\n#    comme pour tous les autres lois "
         << "\n#:....................................................................................."
         << endl;
       };
    // appel de la classe mère
    Loi_comp_abstraite::Info_commande_don_LoisDeComp(entreePrinc); 
  };  		  	  

// test si la loi est complete
int Loi_Umat::TestComplet()
    { // appel de la fonction mère
      return LoiAbstraiteGeneral::TestComplet();
    }; 

	   //----- lecture écriture de restart -----
    
// 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)
void Loi_Umat::Lecture_base_info_loi(istream& ent,const int cas,LesReferences& lesRef,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
	{ string toto,nom; 
	  if (cas == 1) 
	   { ent >> toto >> thermo_dependant;
	    };   
   // cas de la structure UmatAbaqus  
   umatAbaqus.Lecture_base_info(ent,cas);   
	  // appel de la classe mère
	  Loi_comp_abstraite::Lecture_don_base_info(ent,cas,lesRef,lesCourbes1D,lesFonctionsnD); 	 
 };
       // cas donne le niveau de sauvegarde
       // = 1 : on sauvegarde tout
       // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Loi_Umat::Ecriture_base_info_loi(ostream& sort,const int cas)
 { if (cas == 1) 
       { sort << " " << Nom_comp(this->Id_comport()) << " " << thermo_dependant;
       };
   // cas de la structure UmatAbaqus  
   umatAbaqus.Ecriture_base_info(sort,cas);   
   // appel de la classe mère  	        
	  Loi_comp_abstraite::Ecriture_don_base_info(sort,cas);
	};
        // calcul d'un module d'young équivalent à la loi pour un chargement nul
double Loi_Umat::Module_young_equivalent(Enum_dure temps,const Deformation & def,SaveResul * )
 { if (thermo_dependant)
      {temperature_tdt = def.DonneeInterpoleeScalaire(TEMP,temps);
       temperature_t = def.DonneeInterpoleeScalaire(TEMP,TEMPS_t);
      };
   // comme on ne connait la loi, on fait un appel standart avec une déformation donnée
   // on en déduit le module d'young
   //    .. définition de jeux de données adoc
   umatAbaqus.Init_un();
   // *** on impose une déformation de traction et de cisaillement arbitraire ******
   double dep=0.001;// une valeur arbitraire
   (*(umatAbaqus.eps_meca)).Coor(1,1)=(*(umatAbaqus.delta_eps_meca)).Coor(1,1)=dep;
   (*(umatAbaqus.eps_meca)).Coor(1,2)=(*(umatAbaqus.delta_eps_meca)).Coor(1,2)=dep;
   (*(umatAbaqus.eps_meca)).Coor(2,1)=(*(umatAbaqus.delta_eps_meca)).Coor(2,1)=dep;
   umatAbaqus.temper_t= temperature_t;
   umatAbaqus.delta_temper=temperature_tdt-temperature_t;
   BaseH giH(3);
   double jacobien_0,jacobien =1.;
   EnergieMeca  energ,energ_t; // variables intermédiaires, ne sert pas vraiment ici
   double module_compressibilite=0.; double module_cisaillement=0. ;   
   // construction de la métrique umat associée: 
   // ici on considére que la base de référence actuelle est orthonormée
   // ainsi: gijBB_tdt -> gabBB = identitée, idem en HH
   // pour gijBB_0 et gijHH_0, on utilise la déformation arbitraire proposée
   
   // a faire *******************
   
   
   
 //     (*gabBB_0) =  (*gabBB_t)  = IdBB3 - 2. * (*(umatAbaqus.eps_meca));
 //     (*gabHH_0) = (*gabHH_t) = gabBB_0->Monte2Indices();
      // mise à jour du conteneur de la métrique umat
//	  umat_met3D.Mise_a_jour_grandeur(&gixB_0,&gixH_0,&gixB_t,&gixH_t,&gixB_tdt,&gixH_tdt
//		  	                        ,IdBB,IdHH,gabBB_t,gabHH_t,gabBB_tdt,gabHH_tdt
//		  	                        ,ggradVmoyBB_tnull,ggradVmoyBB_tdtnull,ggradVBB_tdtnull
//		  	                        ,&jacobien,&jacobien_0);
   // appel d'un calcul Umat
   bool en_base_orthonormee = true; // les tenseurs sont en orthonormee a priori
   Calcul_dsigma_deps (en_base_orthonormee, *(umatAbaqus.t_sigma),*(umatAbaqus.delta_eps_meca)
                ,(*(umatAbaqus.eps_meca)),(*(umatAbaqus.delta_eps_meca)),jacobien_0,jacobien
		  	           ,*(umatAbaqus.t_sigma),*(umatAbaqus.d_sigma_deps),energ,energ_t
		  	           ,module_compressibilite,module_cisaillement,umat_met3D.Conteneur_Umat()) ;
	  // calcul approché du E
	  //  a) calcul du coefficient de compressibilité
	  Tenseur3HH& sig= *((Tenseur3HH*) umatAbaqus.t_sigma);
	  Tenseur3BB& eps= *((Tenseur3BB*) umatAbaqus.eps_meca);
	  double Isig= sig(1,1)+sig(2,2)+sig(3,3);
	  double Ieps= dep; //eps(1,1)+eps(2,2)+eps(3,3);
	  double Kc=(Isig)/(Ieps);
	  //  b) calcul du coefficient de cisaillement moyen
	  double mu= sig(1,2)/dep;
	  //  c) calcul de E approchée
	  double E=(3*Kc*mu)/(2*Kc+mu);
   LibereTenseur(); 
   LibereTenseurQ(); 
   return E;	  	 
	 };  
          

 // ========== codage des METHODES VIRTUELLES  protegees:================
        // calcul des contraintes a t+dt
void Loi_Umat::Calcul_SigmaHH (TenseurHH& ,TenseurBB& ,DdlElement & tab_ddl,
             TenseurBB & ,TenseurHH & ,BaseB& ,BaseH& ,TenseurBB&  epsBB_,
             TenseurBB&  ,TenseurBB&  ,
		  	 TenseurHH & ,Tableau <TenseurBB *>& d_gijBB_,double& ,double& ,
		  	  TenseurHH & 
		  	,EnergieMeca & ,const EnergieMeca & 
		  	,double& ,double&  
		  	,const Met_abstraite::Expli_t_tdt& )
 {   
   #ifdef MISE_AU_POINT	 	 
	   if (epsBB_.Dimension() != 3)
	    { cout << "\nErreur : la dimension devrait etre 3 !\n";
		     cout << " Loi_Umat::Calcul_SigmaHH\n";
		     Sortie(1);
		   };
	   if (tab_ddl.NbDdl() != d_gijBB_.Taille())
	    { cout << "\nErreur : le nb de ddl est != de la taille de d_gijBB_  !\n";
		     cout << " Loi_Umat::Calcul_SigmaHH\n";
		     Sortie(1);
		   };		
   #endif
    cout << "\n pour l'instant le calcul en explicit n' implantees en Umat interne"
         << "\n Loi_Umat::Calcul_SigmaHH (.... ";
    Sortie(1);     
 };
        
        // calcul des contraintes a t+dt et de ses variations  
void Loi_Umat::Calcul_DsigmaHH_tdt (TenseurHH& sigHH_t_,TenseurBB& DepsBB_,DdlElement & tab_ddl
            ,BaseB& giB_t,TenseurBB & gijBB_t,TenseurHH & gijHH_t
            ,BaseB& giB_tdt,Tableau <BaseB> & d_giB_tdt,BaseH& giH_tdt,Tableau <BaseH> & d_giH_tdt
            ,TenseurBB & epsBB_tdt,Tableau <TenseurBB *>& d_epsBB
            ,TenseurBB & delta_epsBB_,TenseurBB & gijBB_tdt,TenseurHH & gijHH_tdt
		          ,Tableau <TenseurBB *>& d_gijBB_tdt
		  	       ,Tableau <TenseurHH *>& d_gijHH_tdt,double& jacobien_0,double& jacobien
		  	       ,Vecteur& d_jacobien_tdt,TenseurHH& sigHH_tdt,Tableau <TenseurHH *>& d_sigHH
		  	       ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
		  	       ,const Met_abstraite::Impli& ex)
 {
    #ifdef MISE_AU_POINT	 	 
	   if (tab_ddl.NbDdl() != d_gijBB_tdt.Taille())
	    { cout << "\nErreur : le nb de ddl est != de la taille de d_gijBB_tdt  !\n";
		     cout << " Loi_Umat::Calcul_DsigmaHH_tdt\n";
		     Sortie(1);
		   };
    #endif
    
    // en fonction de la dimension on modifie les tenseurs de passage dans l'umat
    switch (abs(epsBB_tdt.Dimension()))
     { case 2: // cas de tenseur en 2 dimension
        { const Tenseur2BB & epsBB = *((Tenseur2BB*) &epsBB_tdt); // passage explicite en dim 2
          const Tenseur2BB & delta_epsBB = *((Tenseur2BB*) &delta_epsBB_); // passage en dim 2
          const Tenseur2BB & DepsBB = *((Tenseur2BB*) &DepsBB_); // passage en dim 2
          const Tenseur2HH & gijHH = *((Tenseur2HH*) &gijHH_tdt); //   "      "  "  "
          Tenseur2HH & sigHH = *((Tenseur2HH*) &sigHH_tdt);  //   "      "  "  "
          Tenseur2HH & sigHH_t = *((Tenseur2HH*) &sigHH_t_);  //   "      "  "  "
          
          // on définit des tenseurs intermédiaires pour la contrainte et la déformation
          Tenseur2BB eps_orthoBB(epsBB),delta_eps_orthoBB(delta_epsBB);
          Tenseur2HH sig_orthoHH(sigHH_t);
          Tenseur2BB D_orthoBB(DepsBB);
         
          //la loi en dimension 2 doit s'exprimer dans un repère orthonormé de dimension 2
          // on va utiliser une méthode particulière de la déformation associé
          #ifdef MISE_AU_POINT
          // vérif que le pointeur est ok
          if (def_en_cours == NULL)
            { cout << "\nErreur : la deformation en cours n'est pas utilisable  "
                   << " on ne peut pas continuere ! !\n" ;
              cout << " Loi_Umat::Calcul_DsigmaHH_tdt\n";
              Sortie(1);
            };
          #endif
          // détermination d'une bases particulière orthonormée pour représenter les tenseurs
          // on est en contrainte plane ou déformation plane, la géométrie interpolée est de type 2D
          // et on considère que la normale suivant laquelle la contrainte ou la déformation 33 est nulle
          // est normale à la géométrie 2D, d'où l'utilisation d'une méthode ad hoc de la déformation en cours
         
          // en sortie on a une  matrice de passage, qui permet 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(alpha) -> IP^beta ,
          //  c-a-d Aa(alpha,beta) = les coordonnées de gH(alpha) dans la base IP^beta,
          //    ou encore: la ligne alpha de Aa = les coordonnées locales de gH(alpha)
          //  NB: si on a besoin du passage de gB(alpha) on utilise la matrice
          // inverse transposée de Aa
          Mat_pleine Aa(2,2); // matrice de passage
          bool absolue = false; // on utilise un repère locale ad hoc
          def_en_cours->BasePassage(absolue,(*ex.giB_0),(*ex.giH_0),Aa);
         
          // pour le changement de repère: la nouvelle base doit-être tel que
          // gp^i = gamma^i_{.j} * g^j et gp_i = beta_i^{.j} g_j
          // ici gp^i = Ip^i d'où [gamma] = [Aa]^{-1T} et [beta] = [Aa]^T
          Mat_pleine gamma(Aa.Inverse().Transpose());
          Mat_pleine beta(Aa.Transpose());

          // on passe ensuite les tenseurs dans la base locale orthonormée
          eps_orthoBB.ChBase(beta);
          delta_eps_orthoBB.ChBase(beta);
          D_orthoBB.ChBase(beta);
          sig_orthoHH.ChBase(gamma);
          sigHH.ChBase(gamma); // normalement ne sert à rien car est un résultat
          
          // maintenant on va calculer l'équivalent local des bases à 0
          ex.giB_0->ChangeBase_curviligne(Aa,giB_0_2D,giH_0_2D,Ip3B_0_3D);
          // giB_0_2D et giH_0_2D contiennent les coordonnées des gi initiaux dans la nouvelle
          // base ortho: mais il s'agit toujours des gi relatifs aux theta i de départ
          // Ip3B_0_3D contient les coordonnées de la base ortho 2D + 1D (normal aux 2 premiers)
          // , exprimées dans le repère 3D
          // on doit avoir Ip3H_0_3D = Ip3B_0_3D mais comme la variance n'est pas la même il faut les
          // affecter en passant outre la variance
          Ip3H_0_3D.Affectation_trans_variance(Ip3B_0_3D);
         
          // on change de base: pour exprimer  les bases précédentes mais maintenant dans le nouveau
          // repère Ip3B_0_3D
          ex.giB_t->Change_repere(Ip3H_0_3D,giB_t_2D);
          ex.giB_tdt->Change_repere(Ip3H_0_3D,giB_tdt_2D);
          ex.giH_t->Change_repere(Ip3B_0_3D,giH_t_2D);
          ex.giH_tdt->Change_repere(Ip3B_0_3D,giH_tdt_2D);
          // donc maintenant umat_cont_2D contient via ses pointeurs les nouvelles bases
          #ifdef MISE_AU_POINT
          if (Permet_affichage() > 5)
           {cout << "\n\n Loi_Umat::Calcul_DsigmaHH_tdt (.. ";
            cout << "\n gamma= "; Aa.Affiche();
            cout << " base ex.giB_0:" << (*ex.giB_0);
            cout << "\n base Ip : "<<Ip3B_0_3D;
            cout << "\n base ex.giB_t:" << (*ex.giB_t);
            cout << "\n dans Ip:" << giB_t_2D;
            cout << "\n base ex.giB_tdt:" << (*ex.giB_tdt);
            cout << "\n dans ip:" << giB_tdt_2D;
            cout << "\n def epsBB: "<<epsBB;
            cout << "\n def eps_orthoBB: "<< eps_orthoBB;
           }
          #endif

          // maintenant on peut construire le reste de la métrique
          const Met_abstraite::Umat_cont& umat_cont = umat_met2D.Construction_Umat(*umat_cont_2D);
         
          #ifdef MISE_AU_POINT
          if (Permet_affichage() > 5)
           {cout << "\n base gip_B_t:" << (*umat_cont.giB_t);
            cout << "\n base gip_B_tdt:" << (*umat_cont.giB_tdt);
           };
          #endif

          bool en_base_orthonormee=true; // ici les tenseurs sont en orthonormee a priori
          // c'est-à-dire dans un repère orthonormée, la direction 3 correspond à la direction
          // pour laquelle sig^33 = 0
 
 
          // appel de la procedure umat
          Calcul_dsigma_deps (en_base_orthonormee, sig_orthoHH,D_orthoBB
                              ,eps_orthoBB,delta_eps_orthoBB,jacobien_0,jacobien
		  	                         ,sigHH,d_sigma_deps_2D,energ,energ_t
		  	                         ,module_compressibilite,module_cisaillement,umat_cont);
     
          #ifdef MISE_AU_POINT
          if (Permet_affichage() > 5)
           {cout << "\n contrainte sigHH dans Ip_a : "<<sigHH;
            cout << "\n d_sigma_deps_2D dans Ip_a  :" << d_sigma_deps_2D;
           };
          #endif

          // la contrainte résultat :  est tel qu'elle représente les composantes
          // du tenseur contrainte dans le repère non orthonormée \hat I'_a
          // les composantes de \hat I'_a dans I'_a sont giB_tdt_2D
          // on a par définition: \hat I'_al = gamma(be,al) * \hat g_be
          // la matrice gamma est utilisée sous forme de sa transposée
          // maintenant on veut le tenseur des contraintes dans la base \hat g_be
          // donc la relation \hat I'_al = gamma(be,al) * \hat g_be la relation de changement
          // de base de l'ancienne base \hat I'_al à la nouvelle voulue \hat g_be
          // avec comme matrice de changement: transposée (gamma)
          sigHH.ChBase(gamma.Transpose(),true);
          #ifdef MISE_AU_POINT
          if (Permet_affichage() > 5)
           {cout << "\n sigHH dans g_i :" <<sigHH;
           };
          #endif

          // calcul de l'opérateur tangent / ddl
          int nbddl = d_gijBB_tdt.Taille();
          // ---- première solution --- on travail dans le repère local
          int cas_resoudre = 1;
          if (cas_resoudre==1)
           {// on ramène l'opérateur tangent dans le repère local
            Tenseur2HHHH d_sigma_depsHHHH; // init
            // en sortie de Calcul_dsigma_deps, d_sigma_deps_2D est relatif à l'opérateur tangent
            // dans le repère
            // giH_tdt_2D

            // ---- rappel du changement de repère pour le 4ième ordre ----
            // changement des composantes du tenseur, retour donc dans la même variance
            // en argument : A -> une reference sur le tenseur résultat qui a la même dimension
            // retour d'une reference sur A
            // A = A^{ijkl) g_i rond g_j rond g_k rond g_l =  A'^{efgh) gp_i rond gpp_j rond g_k rond gp_l
            // g_i = beta_i^j gp_j --> A'^{efgh) = A^{ijkl) beta_i^e beta_j^f beta_k^g beta_l^h
            //    TenseurHHHH & ChangeBase(TenseurHHHH & A,const BaseB & gi) const;

            // pour simplifier on définit un nouveau repère qui va nous servir pour le
            // changement de base, ceci à partir de la relation
            // \hat I'_al = gamma(be,al) * \hat g_be
            // gammaB est construit à partir de la matrice gamma transposée
            BaseB gammaB(2,2);
            gammaB.CoordoB(1)(1) = gamma(1,1);gammaB.CoordoB(1)(2) = gamma(2,1);
            gammaB.CoordoB(2)(1) = gamma(1,2);gammaB.CoordoB(2)(2) = gamma(2,2);
            // on change de repère
            d_sigma_deps_2D.ChangeBase(d_sigma_depsHHHH,gammaB);
            
            #ifdef MISE_AU_POINT
            if (Permet_affichage() > 5)
             {cout << "\n d_sigma_deps_2D: dans g_i" << d_sigma_deps_2D;
             };
            #endif
            
            for (int i = 1; i<= nbddl; i++)
             {  Tenseur2HH & dsigHH = *((Tenseur2HH*) (d_sigHH(i)));  // passage en dim 2
                const Tenseur2BB & depsBB = *((Tenseur2BB *) (d_epsBB(i))); //    "
                dsigHH = d_sigma_depsHHHH && depsBB;
             };
            };
           // l'autre cas, voir 3D n'est pas d'actualité pour l'instant
           break;
        }
       case 3: // cas en 3 dimension
        { const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
          const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
          const Tenseur3BB & DepsBB = *((Tenseur3BB*) &DepsBB_); // passage en dim 3
          const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_tdt); //   "      "  "  "
          Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_tdt);  //   "      "  "  "
          Tenseur3HH & sigHH_t = *((Tenseur3HH*) &sigHH_t_);  //   "      "  "  "
         
          // on définit des tenseurs intermédiaires pour la contrainte et la déformation
          Tenseur3BB epsAA,delta_epsAA; Tenseur3HH sigAA;
         
  //        cout << "\n epsBB " << epsBB;
          //  calcul de la déformation et de l'accroissement dans le repère orthonormee
          epsBB.BaseAbsolue(epsAA,giH_tdt);
  //        cout << "\n epsAA "; (umatAbaqus.eps_meca)->Ecriture(cout);
  //        int toto; cout << "\n une lettre ? "; cin >> toto;
          delta_epsBB.BaseAbsolue(delta_epsAA,giH_tdt);
          // calcul de la vitesse de déformation dans le repère orthonormee
          Tenseur3BB D_abs_epsBB;
          DepsBB.BaseAbsolue(D_abs_epsBB,giH_tdt);
          // calcul de la contrainte initiale dans le repère orthonormee
          sigHH_t.BaseAbsolue(sigAA,giB_tdt);
          
          #ifdef MISE_AU_POINT
          if (Permet_affichage() > 5)
           {cout << "\n\n Loi_Umat::Calcul_DsigmaHH_tdt (.. ";
            cout << "\n eps en absolu :";epsAA.Ecriture(cout);
            cout << "\n Deps en absolu :";D_abs_epsBB.Ecriture(cout);
            cout << "\n delta_eps en absolu :";delta_epsAA.Ecriture(cout);
            cout << "\n sig_t en absolu :";sigAA.Ecriture(cout);
           }
          #endif

          // construction de la métrique umat associée à la métrique actuelle,
          // c'est-à-dire construction de la métrique correspondant aux coordonnées initiales
          // considérées comme paramétrage matériel
          const Met_abstraite::Umat_cont& umat_cont = umat_met3D.Construction_Umat(ex);
          bool en_base_orthonormee=true; // ici les tenseurs sont en orthonormee a priori
          // appel de la procedure umat
          Calcul_dsigma_deps (en_base_orthonormee, sigAA,D_abs_epsBB
                              ,epsAA,delta_epsAA,jacobien_0,jacobien
                       ,*(umatAbaqus.t_sigma),*(umatAbaqus.d_sigma_deps),energ,energ_t
                       ,module_compressibilite,module_cisaillement,umat_cont);
          // passage de la contrainte dans la base locale HH
          Tenseur3HH & sigabHH_tdt = *((Tenseur3HH*) (umatAbaqus.t_sigma));  // // passage en dim 3 explicite
          sigabHH_tdt.Baselocale(sigHH,*(ex.giH_tdt));
          // calcul de l'opérateur tangent / ddl
          int nbddl = d_gijBB_tdt.Taille();
          Tenseur3HHHH & d_sigma_deps = *((Tenseur3HHHH *) umatAbaqus.d_sigma_deps);
         
          // ---- première solution --- on travail dans le repère local
          int cas_resoudre = 1;
          if (cas_resoudre==1)
           {// on ramène l'opérateur tangent dans le repère local
            Tenseur3HHHH d_sigma_depsHHHH;
            d_sigma_deps.Baselocale(d_sigma_depsHHHH,*(ex.giH_tdt));
            for (int i = 1; i<= nbddl; i++)
             {  Tenseur3HH & dsigHH = *((Tenseur3HH*) (d_sigHH(i)));  // passage en dim 3
                const Tenseur3BB & depsBB = *((Tenseur3BB *) (d_epsBB(i))); //    "
                dsigHH = d_sigma_depsHHHH && depsBB;
             };
           }
          else // ---- cas on travail dans le repère global ---- (ne fonctionne pas !!)
           {
             Tenseur3BB depsAA; Tenseur3BB dep1AA,dep2AA;
             Tenseur3HH dsigAA; Tenseur3HH dsig1AA;
             // on rajoute l'effet de la déformation
             // terme sigma.D + D.sigma
             d_sigma_deps += 2*Tenseur3HHHH::Prod_tensoriel_barre(sigabHH_tdt,IdHH3);

             for (int i = 1; i<= nbddl; i++)
              {  Tenseur3HH & dsigHH = *((Tenseur3HH*) (d_sigHH(i)));  // passage en dim 3
                 const Tenseur3BB & d_gijBB =  *((Tenseur3BB*)(d_gijBB_tdt(i)));  // passage en dim 3
                 const Tenseur3HH & dgijHH = *((Tenseur3HH*)(d_gijHH_tdt(i))) ; // pour simplifier l'ecriture
                 const Tenseur3BB & depsBB = *((Tenseur3BB *) (d_epsBB(i))); //    "
                 // tout d'abord variation de la déformation en orthonormee
                 depsBB.BaseAbsolue(depsAA,*(ex.giH_tdt)); // 1) prise en compte de la variation de depsBB
                 // 2) puis on tiens compte de la variation des gamma_a^i qui servent au changement de base
                 // de la base locale à la base orthonormee
                 depsAA += produit_1_pourLoiUmat(dep1AA,epsBB,(*(ex.d_giH_tdt))(i),*(ex.giH_tdt));
                 // dérivée de sigma^ab / d_ddl
                 dsigAA = d_sigma_deps && depsAA;
                 // dérivée de sigma^ij / d_ddl
                 dsigAA.Baselocale(dsigHH,*(ex.giH_tdt)); // 1) prise en compte de la variation de dsigAA
                 // 2) puis prise en compte de la variation des gamma_a^i qui servent au changement de base
                 // du global au locale (c'est-à-dire l'opération inverse que pour la déformation) mais dans
                 // les deux cas c'est les gamma_a^i qui servent !
                 //   a priori ces les termes -W.sigma + sigma.W ?????
                 dsigHH += produit_1_pourLoiUmat(dsig1AA,sigabHH_tdt,(*(ex.d_giH_tdt))(i),*(ex.giH_tdt));
              };
           };
          break;
        }
       default:
         	{cout << "\n pour l'instant seules les lois 3D sont implantees en Umat interne"
         	      << "\n Loi_Umat::Calcul_DsigmaHH_tdt (.... ";
         	 Sortie(1);     
         	}
     };
    // on libère les tenseurs intermédiaires
    LibereTenseur(); 
    LibereTenseurQ(); 
 }; 

// calcul des contraintes et ses variations  par rapport aux déformations a t+dt
// en_base_orthonormee:  le tenseur de contrainte en entrée est  en orthonormee
//                  le tenseur de déformation et son incrémentsont également en orthonormees
//                 si = false: les bases transmises sont utilisées
// ex: contient les éléments de métrique relativement au paramétrage matériel = X_(0)^a
void Loi_Umat::Calcul_dsigma_deps (bool en_base_orthonormee, TenseurHH & sigHH_t_,TenseurBB& DepsBB
            ,TenseurBB & epsBB_tdt,TenseurBB & delta_epsBB_,double& jacobien_0,double& jacobien
		  	,TenseurHH& sigHH_tdt,TenseurHHHH& d_sigma_deps
		  	,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
		  	,const Met_abstraite::Umat_cont& ex)
 {

    // si l'on est dans une utilisation interne de l'umat on appel
    // directement la loi interne
    if (utilisation_umat_interne)
     { // il faut passer les informations à la loi interne
       ((Loi_comp_abstraite*)loi_ext)->saveResul = ((SaveResul_Loi_Umat*) saveResul)->save_pour_loi_ext;
       RepercuteChangeTemperature(TEMPS_tdt);
       ((Loi_comp_abstraite*)loi_ext)->Calcul_dsigma_deps (en_base_orthonormee, sigHH_t_,DepsBB,epsBB_tdt
                                 ,delta_epsBB_,jacobien_0,jacobien,sigHH_tdt
                                 ,d_sigma_deps,energ,energ_t,module_compressibilite,module_cisaillement,ex
                                 );
       // on met à jour la variation d'épaisseur constatée
       Loi_Umat::SaveResul_Loi_Umat& sav = *((Loi_Umat::SaveResul_Loi_Umat*) &saveResul);
       sav.h_tsurh0 = ((Loi_comp_abstraite*)loi_ext)->HsurH0(((Loi_comp_abstraite*)loi_ext)->saveResul);
      return;
     };
    // sinon on dialogue via les pipes d'où le remplissage du conteneur UmatAbaqus
  
  
  
//    const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
//    const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
//    Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_tdt);  //   "      "  "  "
//    Tenseur3HH & sigHH_t = *((Tenseur3HH*) &sigHH_t_);  //   "      "  "  "
    SaveResul_Loi_Umat & save_resul = *((SaveResul_Loi_Umat*) saveResul);
    //    .. définition de jeux de données adoc
    //   si on a des tenseurs à 2 dimensions, on considère que l'on est en CP par défaut
  
    int dim_reel_tens = 3 ; // init par défaut: nb sigii
    int nb_reel_tau_ij = 3 ; // idem
    if (ex.giB_t->NbVecteur() == 2 )
      {dim_reel_tens = 2; nb_reel_tau_ij=1; };
    umatAbaqus.Init_un(dim_reel_tens,nb_reel_tau_ij);
  
    // on renseigne la position du pti
    // on devrait pouvoir le récupérer de l'appel venant de loi_comp_abstraite
    // mais c'est pas simple donc je recalcule
    umatAbaqus.coor_pt = def_en_cours->Position_tdt();
  
//    umatAbaqus.Init_un();
    //  init de la déformation et de l'accroissement
    // la dimension des tenseurs passés en paramètre, peut-être 2 ou 3
// non    // par contre dans l'umatAbaqus on est toujours en 3D
    // on fait donc une affectation trans dimension
    bool plusZero = true; // on ajoute des zéros par défaut
//    (umatAbaqus.eps_meca)->Affectation_trans_dimension(epsBB_tdt,plusZero);
    *(umatAbaqus.eps_meca) = epsBB_tdt;
//    (umatAbaqus.delta_eps_meca)->Affectation_trans_dimension(delta_epsBB_,plusZero);
    *(umatAbaqus.delta_eps_meca) = delta_epsBB_;
    // init de la contrainte initiale
//    (umatAbaqus.t_sigma)->Affectation_trans_dimension(sigHH_t_,plusZero);
    *(umatAbaqus.t_sigma)=sigHH_t_;
    // récup des températures
    umatAbaqus.temper_t=temperature_t; // température initiale
    umatAbaqus.delta_temper=temperature_tdt-temperature_t; // variation de température
    // récup des temps
    const VariablesTemps& v_temps = ParaGlob::Variables_de_temps();  
    umatAbaqus.temps_tdt = v_temps.TempsCourant();
    umatAbaqus.delta_t = v_temps.IncreTempsCourant();
    umatAbaqus.temps_t = umatAbaqus.temps_tdt-umatAbaqus.delta_t;
    // init des énergies
    umatAbaqus.energie_elastique=energ_t.EnergieElastique();
    umatAbaqus.dissipation_plastique=energ_t.DissipationPlastique();
    umatAbaqus.dissipation_visqueuse=energ_t.DissipationVisqueuse();
    // init des gradients
    // les bases dans l'umatAbaqus ont toujours 3 vecteurs, mais
    // ex peut en avoir que 2 : cas CP par exemple
    int nb_vecteur = (ex.giB_t)->NbVecteur();
    bool pas_Zero_base=false; // on ne veut pas changer le 3ième vecteur
       // qui a été initialisé normalement correctement avec umatAbaqus.Init_un();
//    umatAbaqus.giB_t.Affectation_partielle(nb_vecteur, *(ex.giB_t),pas_Zero_base);
    umatAbaqus.giB_t = *(ex.giB_t);
//    umatAbaqus.giB_tdt.Affectation_partielle(nb_vecteur, *(ex.giB_tdt),pas_Zero_base);
    umatAbaqus.giB_tdt = *(ex.giB_tdt);
    // si on est en tenseur 2D et en dimension 3 il faut définir les normales
    if ((ex.giB_t->NbVecteur() == 2 )&& (ParaGlob::Dimension()==3))
     { umatAbaqus.N_t = Util::ProdVec_coorB( (*ex.giB_t)(1), (*ex.giB_t)(2));
       umatAbaqus.N_tdt = Util::ProdVec_coorB( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2));
     };
    // coordonnées du point, longueur caractéristique, les indices
	   if (umatAbaqus.nb_increment==1)
	      umatAbaqus.nom_materiau = nom_de_la_loi;
    // le nombre d'itération  est sytématiquement laissé à 1
    // idem pour  le nb de plis le np de pt d'integ dans le plis
    // la longueur caractéristique est mise à 1. par défaut
    // appel des routines Umat
    umatAbaqus.EcritureDonneesPourUmat(utilisation_umat_interne,Permet_affichage());
    umatAbaqus.LectureResultatUmat(utilisation_umat_interne,Permet_affichage());
    // on met à jour la variation d'épaisseur constatée
    Loi_Umat::SaveResul_Loi_Umat& sav = *((Loi_Umat::SaveResul_Loi_Umat*) &saveResul);
    sav.hsurh0 = umatAbaqus.N_tdt.Norme();
    // ------ retour des résultats
    // les énergies
    energ.ChangeEnergieElastique(umatAbaqus.energie_elastique);
    energ.ChangeDissipationPlastique(umatAbaqus.dissipation_plastique);
    energ.ChangeDissipationVisqueuse(umatAbaqus.dissipation_visqueuse);
    // les contraintes
    // les contraintes de l'umatAbaqus sont toujours en 3D,
    // par contre l'utilisation interne peut-être en 2D: par exemple en CP
//    sigHH_tdt.Affectation_trans_dimension(*(umatAbaqus.t_sigma),plusZero);
    sigHH_tdt = *(umatAbaqus.t_sigma);
    // l'opérateur tangent
//    d_sigma_deps.Affectation_trans_dimension(*(umatAbaqus.d_sigma_deps),plusZero);
    d_sigma_deps=*(umatAbaqus.d_sigma_deps);
    // il faut maintenant calculer les modules de compressibilité et de cisaillement
    Calcul_compressibilite_cisaillement(ex,module_compressibilite,module_cisaillement);
    // on libère les tenseurs intermédiaires
    LibereTenseur(); 
    LibereTenseurQ(); 
 };

    
       // fonction interne utilisée par les classes dérivées de Loi_comp_abstraite
       // pour répercuter les modifications de la température
       // ici utiliser pour modifier la température des lois élémentaires
       // l'Enum_dure: indique quel est la température courante : 0 t ou tdt
 void Loi_Umat::RepercuteChangeTemperature(Enum_dure temps)
  { // la répercution n'est licite que s'il y a une loi interne
    if (loi_ext != NULL)
      {// pour l'instant on se place dans le cas d'une Loi_comp_abstraite
       Loi_comp_abstraite * lois_interne = (Loi_comp_abstraite*) loi_ext;
  
       lois_interne->temperature_0 = this->temperature_0;
       lois_interne->temperature_t = this->temperature_t;
       lois_interne->temperature_tdt = this->temperature_tdt;
       lois_interne->dilatation=dilatation;

       lois_interne->RepercuteChangeTemperature(temps);
       // on répercute également les déformations thermiques, qui ne sont utilisées
       // telles quelles que pour certaines lois: ex: loi hyper-élastique
       if (dilatation)
        {//  a- dimensionnement des tenseurs intermédiaires 
         int dim_tens = epsBB_therm->Dimension();
             // -- cas de la déformation
         if (lois_interne->epsBB_therm == NULL) { lois_interne->epsBB_therm = NevezTenseurBB(dim_tens);}
         else if (lois_interne->epsBB_therm->Dimension() != dim_tens)
            { delete lois_interne->epsBB_therm;lois_interne->epsBB_therm = NevezTenseurBB(dim_tens);};
             // -- cas de la vitesse de déformation
         if (lois_interne->DepsBB_therm == NULL) { lois_interne->DepsBB_therm = NevezTenseurBB(dim_tens);}
         else if (lois_interne->DepsBB_therm->Dimension() != dim_tens)
          { delete lois_interne->DepsBB_therm;lois_interne->DepsBB_totale = NevezTenseurBB(dim_tens);};
         // b- affectation des tenseurs
         (*lois_interne->epsBB_therm)=(*epsBB_therm);
         (*lois_interne->DepsBB_therm)=(*DepsBB_therm);
        };
       switch (temps)
         { case TEMPS_0: 
            {lois_interne->temperature = &lois_interne->temperature_0;
             break;
             }
           case TEMPS_t: 
            {lois_interne->temperature = &lois_interne->temperature_t;
             break;
             }
           case TEMPS_tdt: 
            {lois_interne->temperature = &lois_interne->temperature_tdt;
             break;
             }
           default:
                { cout << "\n erreur, cas de temps non prevu !! "
                       << "\n LoiContraintesPlanes::RepercuteChangeTemperature(...";
                  Sortie(1);      
                };
         };
      };

  };

// passage des grandeurs métriques de l'ordre 2 à 3
void Loi_Umat::Passage_metrique_ordre2_vers_3(const Met_abstraite::Umat_cont& ex)
{// on s'occupe du redimensionnement éventuel
 // la partie dépendant des vitesses: entre accolades pour pouvoir fermer
 {if (ex.gradVmoyBB_t != NULL) {umat_cont_3D->gradVmoyBB_t= gradVmoyBB_t_3D_P = &gradVmoyBB_t_3D;};
  if (ex.gradVmoyBB_tdt != NULL) {umat_cont_3D->gradVmoyBB_tdt=gradVmoyBB_tdt_3D_P = &gradVmoyBB_tdt_3D;};
  if (ex.gradVBB_tdt != NULL) {umat_cont_3D->gradVBB_tdt=gradVBB_tdt_3D_P = &gradVBB_tdt_3D;};
 }; // fin de la partie dédiée à la vitesse
 // on commence par recopier les grandeurs de l'ordre 2 à 3
 bool plusZero = true; // on complète avec des 0 dans un premier temps
 int type_recopie=0; //   = 0 -> on transfert les grandeurs à 0, t et tdt
 umat_cont_3D->Passage_de_Ordre2_vers_Ordre3(ex,plusZero,type_recopie);
 
 // maintenant on s'occupe de mettre à jour les grandeurs manquantes
 // - les bases naturelles: le vecteur normal est normé et est identique pour les bases naturelles et duales
 giB_0_3D.CoordoB(3) = (Util::ProdVec_coorB(giB_0_3D(1),giB_0_3D(2))).Normer();
 giH_0_3D.CoordoH(3) = giB_0_3D(3).Bas_haut();
 giB_t_3D.CoordoB(3) = (Util::ProdVec_coorB(giB_t_3D(1),giB_t_3D(2))).Normer();
 giH_t_3D.CoordoH(3) = giB_t_3D(3).Bas_haut();
    // cas particulier du vecteur tdt
 giB_tdt_3D.CoordoB(3) = (Util::ProdVec_coorB(giB_tdt_3D(1),giB_tdt_3D(2))); // calcul du vecteur normal non normé
 double norme_N_tdt = giB_tdt_3D(3).Norme(); // calcul de la norme qui nous servira pour les variations
 giB_tdt_3D.CoordoB(3) /= norme_N_tdt;
 giH_tdt_3D.CoordoH(3) = giB_tdt_3D(3).Bas_haut();
   //  - les tenseurs métriques: au début 1 pour la direction 3
 gijBB_0_3D.Coor(3,3)=gijHH_0_3D.Coor(3,3)=gijBB_t_3D.Coor(3,3)=gijHH_t_3D.Coor(3,3)=gijBB_tdt_3D.Coor(3,3)=gijHH_tdt_3D.Coor(3,3)=1.;
 
};


// calcul des modules de compressibilité et de cisaillement
// en fonction des résultats de l'umat
void Loi_Umat::Calcul_compressibilite_cisaillement(const Met_abstraite::Umat_cont& ex
                                  ,double & module_compressibilite,double & module_cisaillement)
{
  switch (umatAbaqus.t_sigma->Dimension())
   {case 3:
     {Tenseur3HB sigHB = (*umatAbaqus.t_sigma) * (*ex.gijBB_tdt);
      // cas du module de compressibilité
      double trace_sig_sur_trois = 1./3. * sigHB.Trace();
      double log_V = log((*ex.jacobien_tdt));
      module_compressibilite = trace_sig_sur_trois / log_V;
      // cas du module de cisaillement
      double Qsig = sigHB.II();
      Tenseur3HB epsHB =  (*ex.gijHH_tdt) * (*umatAbaqus.eps_meca) ;
      double deux_Qeps = 2.*epsHB.II();
      module_cisaillement = Qsig / deux_Qeps;
      break;
     }
    case 2: // en CP
     {if ((umatAbaqus.dim_tens == 2) && (umatAbaqus.nb_tau_ij == 1))
       {Tenseur2HB sigHB = (*umatAbaqus.t_sigma) * (*ex.gijBB_tdt);
        // cas du module de compressibilité
        // la contrainte 33 = 0
        double trace_sig_sur_trois = 1./3. * sigHB.Trace();
        // on démarre d'une base ortho donc le jacobien initial par principe = 1
        double V = Dabs((*ex.jacobien_tdt)); // cas de la surface
        // il faut maintenant introduire la surface
        // la normale en 3 = 1 initialement
        double var_3 = umatAbaqus.N_tdt.Norme();
        V *= var_3;
        double log_V = log(V);
        // pour éviter une division de 0/0 on régularise
        module_compressibilite = Dabs(trace_sig_sur_trois / (log_V+DSigne(log_V)*ConstMath::petit));
        // cas du module de cisaillement
        double Qsig = sigHB.II();
        // il faut que l'on reconstruise un tenseur 3D avec la déformation d'épaisseur
        Tenseur3HB epsHB; double eps_33=0;double delta_eps_33 = 0.;
        double var_3_t = umatAbaqus.N_t.Norme();
        epsHB.Affectation_trans_dimension((*ex.gijHH_tdt) * (*umatAbaqus.eps_meca),true);
        // N_tdt = la nouvelle normale, compte tenu de la variation d'épaisseur
        // et on part de N_0 qui est normé, d'où on considère que ||N_tdt|| = h/h0
        switch (type_de_deformation)
         {case  DEFORMATION_STANDART :  case DEFORMATION_POUTRE_PLAQUE_STANDART :
               // cas d'une déformation d'Almansi
               {  // epsBB33 = 1/2 * (1. - (h0/h)^2), en orthonormee
                  // dans le repère local: epsBB33 = 1/2 * (h^2 - 1.), or h0=1. donc : epsBB33 = 1/2 * ((h/h0)^2 - 1.)
                  eps_33 = 0.5 * (var_3 * var_3 - 1.);
                  delta_eps_33 = 0.5 * (var_3 * var_3 - var_3_t * var_3_t);
               };
               break;
          case DEFORMATION_LOGARITHMIQUE : case DEF_CUMUL_CORROTATIONNEL : case DEFORMATION_CUMU_LOGARITHMIQUE :
              // cas d'une def logarithmique ou une approximation
               {  eps_33 = log(var_3);
                  delta_eps_33 = log(var_3) - log(var_3_t);
               };
               break;
          default :
            cout << "\nErreur : type de deformation qui n'est pas actuellement pris en compte, type= "
                 << Nom_type_deformation(type_de_deformation);
            cout << "\n Loi_Umat::Calcul_compressibilite_cisaillement(.. \n";
            Sortie(1);
         };
        // le vecteur normal est normal à g_i à tous les temps (on considère que l'on reste dans le plan principal
        // du coup g^{33} = h0^2/h^2 ce qui permet de calculer eps^3_3
        epsHB.Coor(3,3)=eps_33 /(var_3*var_3);
        double deux_Qeps = 2.*epsHB.II();
        // pour éviter une division de 0/0 on régularise
        module_cisaillement = Qsig / (deux_Qeps+ConstMath::petit);;
       }
      else
       { cout << "\n ** erreur, ce cas n'est pas encore pris en compte: "
              << " tenseur d'ordre 2 et situation non en contrainte plane !";
         cout << "\n Loi_Umat::Calcul_compressibilite_cisaillement(.. \n";
         Sortie(1);
       };
      break;
     }
    default:
       cout << "\n ** erreur, ce cas n'est pas encore pris en compte: ";
       cout << "\n Loi_Umat::Calcul_compressibilite_cisaillement(.. \n";
       Sortie(1);
       break;
   };
 
 #ifdef MISE_AU_POINT
 if (Permet_affichage() > 4)
  {cout << "\n module_compressibilite= " << module_compressibilite;
   cout << "\n module_cisaillement= " << module_cisaillement;
  };
 #endif

 
 
};