// FICHIER : Loi_ortho2D_C_entrainee.cc
// CLASSE : Loi_ortho2D_C_entrainee


// 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 "Loi_ortho2D_C_entrainee.h"
#include "NevezTenseur.h"
#include "MathUtil.h"
#include "Util.h"

#include "Enum_TypeQuelconque.h"
#include "TypeQuelconqueParticulier.h"
#include "TenseurQ2gene.h"
#include "MathUtil.h"
#include "MathUtil2.h"
#include "CharUtil.h"
#include "Coordonnee2.h"


// ========== fonctions pour la classe de sauvegarde des résultats =========

// constructeur par défaut
Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee(const int type_transport):
     O_B(NULL), O_H(NULL),Op_H(2,2),Op_H_t(2,2),eps_loc_HH(NULL),sig_loc_HH(NULL)
     ,para_loi(NULL)
  {
  };

// constructeur de copie
Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee(const SaveResulLoi_ortho2D_C_entrainee& sav):
   O_B(NULL), O_H(NULL),Op_H(2,2),Op_H_t(2,2),eps_loc_HH(NULL),sig_loc_HH(NULL)
   ,para_loi(NULL)
 {
   // partie repère d'orthotropie
   if (sav.O_B != NULL)
     O_B = new BaseB(*sav.O_B);
   if (sav.O_H != NULL)
     O_H = new BaseH(*sav.O_H);
   if (sav.eps_loc_HH != NULL)
     eps_loc_HH = NevezTenseurHH(*sav.eps_loc_HH);
   if (sav.sig_loc_HH != NULL)
     sig_loc_HH = NevezTenseurHH(*sav.sig_loc_HH);
   if (sav.para_loi != NULL)
     para_loi = new Vecteur (*sav.para_loi);
 };

// destructeur
Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::~SaveResulLoi_ortho2D_C_entrainee()
   {
    // partie repère d'orthotropie
    if (O_B != NULL)
      delete O_B;
    if (O_H != NULL)
      delete O_H;
    if (eps_loc_HH != NULL)
      delete eps_loc_HH;
    if (sig_loc_HH != NULL)
      delete sig_loc_HH;
    if (para_loi != NULL)
      delete para_loi;
   };

// affectation
Loi_comp_abstraite::SaveResul & Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::operator = ( const Loi_comp_abstraite::SaveResul & a)
  { Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee& sav = *((Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee*) &a);
  
    eps33=sav.eps33;eps33_t=sav.eps33_t;
    // partie repère d'orthotropie
    if (sav.O_B != NULL)
     {if (O_B == NULL) {O_B = new BaseB(*sav.O_B);}
      else {*O_B = *sav.O_B;};
     }
    else // sinon cas NULL
    {if (O_B != NULL) {delete O_B;O_B=NULL;}} ;
   
    if (sav.O_H != NULL)
     {if (O_H == NULL) {O_H = new BaseH(*sav.O_H);}
      else {*O_H = *sav.O_H;};
     }
    else // sinon cas NULL
    {if (O_H != NULL) {delete O_H;O_H=NULL;}} ;
   
    if (sav.eps_loc_HH != NULL)
     {if (eps_loc_HH == NULL) {eps_loc_HH = NevezTenseurHH(*sav.eps_loc_HH);}
      else {*eps_loc_HH = *sav.eps_loc_HH;};
     }
    else // sinon cas NULL
    {if (eps_loc_HH != NULL) {delete eps_loc_HH;eps_loc_HH=NULL;}} ;
   
    if (sav.sig_loc_HH != NULL)
     {if (sig_loc_HH == NULL) {sig_loc_HH = NevezTenseurHH(*sav.sig_loc_HH);}
      else {*sig_loc_HH = *sav.sig_loc_HH;};
     }
    else // sinon cas NULL
    {if (sig_loc_HH != NULL) {delete sig_loc_HH; sig_loc_HH= NULL;};
    } ;
   
    if (sav.para_loi != NULL)
     {if (para_loi == NULL) para_loi = new Vecteur (*sav.para_loi);
      else {*para_loi = *sav.para_loi; };
     }
    else // sinon cas NULL
    {if (para_loi != NULL) {delete para_loi;para_loi=NULL;}} ;
    // et la base
    Op_H = sav.Op_H;
    Op_H_t = sav.Op_H_t;

    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_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Lecture_base_info(ifstream& ent,const int cas)
   {  string nom;
      ent >>  nom ;

      #ifdef MISE_AU_POINT
      if (nom != "S_Ortho_2D_C")
          { cout << "\nErreur : on attendait le mot cle: S_Ortho_2D_C "
                 << " et on a lue "<<nom;
            cout << " Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Lecture_base_info\n";
            Sortie(1);
          };
      #endif
      // on lit que ce qui est à 0 et à t, ce qui est à tdt est considéré une zone de travail
      switch (cas)
       { case 1 :
          {
           // la base initiale
           if (O_B != NULL)
            { ent >> nom >> *O_B;}
           else if (O_H != NULL)
            { ent >> nom >> *O_H;}
           // la base convectée
           ent >> nom >> Op_H_t ;
           Op_H = Op_H_t;
           // les stockages conditionnels
           int test;
           ent >> nom >> test;
           if (test == 0)
            { if (eps_loc_HH != NULL)
                {delete eps_loc_HH;eps_loc_HH=NULL;}
              if (sig_loc_HH != NULL)
                {delete sig_loc_HH;sig_loc_HH=NULL;}
              if (para_loi != NULL)
                {delete para_loi;para_loi=NULL;}
            }
           else // sinon cas où on a des données additionnelles
            { if (eps_loc_HH == NULL) eps_loc_HH = NevezTenseurHH(2);
              ent >> nom ; eps_loc_HH->Lecture(ent);
              if (sig_loc_HH == NULL) sig_loc_HH = NevezTenseurHH(2);
              ent >> nom ; sig_loc_HH->Lecture(ent);
              if (para_loi == NULL) para_loi = new Vecteur (7);
              ent >> *para_loi;
            };
           break;
          }
         case 2 :
          {
           // la base convectée
           ent >> nom >> Op_H_t ;
           // les stockages conditionnels
           int test;
           ent >> nom >> test;
           if (test == 0)
            { if (eps_loc_HH != NULL)
                {delete eps_loc_HH;eps_loc_HH=NULL;}
              if (sig_loc_HH != NULL)
                {delete sig_loc_HH;sig_loc_HH=NULL;}
              if (para_loi != NULL)
                {delete para_loi;para_loi=NULL;}
            }
           else // sinon cas où on a des données additionnelles
            { if (eps_loc_HH == NULL) eps_loc_HH = NevezTenseurHH(2);
              ent >> nom ; eps_loc_HH->Lecture(ent);
              if (sig_loc_HH == NULL) sig_loc_HH = NevezTenseurHH(2);
              ent >> nom ; sig_loc_HH->Lecture(ent);
              if (para_loi == NULL) para_loi = new Vecteur(7);
              ent >> nom  >> *para_loi;
            };
           break;
          }
         default:
            cout << "\n cas non considere !!: cas= " << cas
                 << "\n   Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Ecriture_base_info(...";
            Sortie(1);
       };
  };

// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables
//(supposées comme telles)
void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Ecriture_base_info(ofstream& sort,const int cas )
   {  sort << "\n S_Ortho_2D_C  ";
      // on ne sauvegarde que ce qui est à 0 et à t, ce qui est à tdt est considéré une zone de travail
      switch (cas)
       { case 1 :
          {
           // la base initiale
           if (O_B != NULL)
            { sort << " O_B: "<< *O_B;}
           else if (O_H != NULL)
            { sort << " O_H: "<< *O_H;}
           // la base convectée
           sort << " Op_H_t: "<< Op_H_t << " ";
           // les stockages conditionnels
           if (eps_loc_HH != NULL)
            { sort << " addi: 1 " << "\n eps_loc_HH: ";
              eps_loc_HH->Ecriture(sort);
              sort << "\n sig_loc_HH: ";
              sig_loc_HH->Ecriture(sort);
              sort << "\n para_loi: " << *para_loi << " ";
            }
           else
            { sort << " addi: 0 ";};
           break;
          }
         case 2 :
          {
           // la base convectée
           sort << " Op_H_t: "<< Op_H_t << " ";
           // les stockages conditionnels
           if (eps_loc_HH != NULL)
            { sort << "\n addi: 1 "<< "\n eps_loc_HH: " ;
              eps_loc_HH->Ecriture(sort);
              sort << "\n sig_loc_HH: " ;
              sig_loc_HH->Ecriture(sort);
              sort << "\n para_loi: " << *para_loi << " ";
            }
           else
            { sort << "\n addi: 0 ";};
           break;
          }
         default:
            cout << "\n cas non considere !!: cas= " << cas
                 << "\n   Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Ecriture_base_info(...";
            Sortie(1);
       };
  };

// mise à jour des informations transitoires
void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::TdtversT()
   { Op_H_t = Op_H;
     eps33_t=eps33;
   };

void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::TversTdt()
   { Op_H = Op_H_t;
     eps33=eps33_t;
   };

// affichage à l'écran des infos
void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Affiche() const
{ cout << "\n SaveResulLoi_ortho2D_C_entrainee: " ;
  if (O_B != NULL)
    {cout << "\n O_B= "; O_B->Affiche();
    };
  if (O_H != NULL)
    {cout << "\n O_H= "; O_H->Affiche();
    };
  cout << "\n Op_H= ";Op_H.Affiche();

  // les tenseurs intermédiaires
  if (eps_loc_HH != NULL)
   { cout << "\n eps_loc_HH= "; eps_loc_HH->Ecriture(cout);
   };
  if (sig_loc_HH != NULL)
   { cout << "\n sig_loc_HH= "; sig_loc_HH->Ecriture(cout);
   };
  // paramètre variables éventuelles de la loi
  if (para_loi != NULL)
   { cout << "\n para_loi: ";
     for (int i=1; i< 8;i++)
       cout << " coef("<<i<<")= "<< (*para_loi)(i);
     cout << " ";
   };


  cout  << "\n .. fin SaveResulLoi_ortho2D_C_entrainee ... ";
};

//changement de base de toutes les grandeurs internes tensorielles stockées
// b(i,j) represente les coordonnees de la nouvelle base naturelle gpB dans l'ancienne gB
// gpB(i) = beta(i,j) * gB(j), i indice de ligne, j indice de colonne
// gpH(i) = gamma(i,j) * gH(j)
void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::ChBase_des_grandeurs(const Mat_pleine& beta,const Mat_pleine& gamma)
{ // on ne s'intéresse qu'aux grandeurs tensorielles
  // il faut que l'on exprime le repère d'orthotropie dans le nouveau repère
  // !!! on travaille ici en 2D -> dans un plan
  #ifdef MISE_AU_POINT
  if ((beta.Nb_colonne() != 2) || (beta.Nb_ligne() != 2))
   { cout << "\nErreur : la dimension devrait etre 2 pour la matrice de changement de base = beta!"
          << " alors n_colonne= " << beta.Nb_colonne() << " et nb_ligne= " << beta.Nb_ligne()
          << " \n SaveResulLoi_ortho2D_C_entrainee::ChBase_des_grandeurs(... ";
     Sortie(1);
   };
  if ((gamma.Nb_colonne() != 2) || (gamma.Nb_ligne() != 2))
   { cout << "\nErreur : la dimension devrait etre 2 pour la matrice de changement de base = gamma!"
          << " alors n_colonne= " << gamma.Nb_colonne() << " et nb_ligne= " << gamma.Nb_ligne()
          << " \n SaveResulLoi_ortho2D_C_entrainee::ChBase_des_grandeurs(... ";
     Sortie(1);
   };
  #endif
  if (O_B != NULL)
   {for (int i=1;i<3;i++)
     { CoordonneeB Ap_B(2); // inter
       MathUtil2::ChBase(O_B->CoordoB(i),beta,Ap_B);
       O_B->CoordoB(i)=Ap_B;
     }
   };
  if (O_H != NULL)
   {for (int i=1;i<3;i++)
     { CoordonneeH Ap_H(2); // inter
       MathUtil2::ChBase(O_H->CoordoH(i),gamma,Ap_H);
       O_H->CoordoH(i)=Ap_H;
     }
   };
  // les autres grandeurs sont issues du calcul
  // normalement elles sont calculées en même temps que les contraintes
  // mais on les change de repère néanmoins, au cas on on ferait une sortie
  // d'info sans calcul (c'est pénalisant pour le cas avec calcul, mais cela
  //  évite peut-être des pb potentiels ??)
  // Op_H est toujours calculé
  {for (int i=1;i<3;i++)
     { CoordonneeH Ap_H(2); // inter
       MathUtil2::ChBase(Op_H_t.CoordoH(i),gamma,Ap_H);
       Op_H_t.CoordoH(i)=Ap_H;
     }
   };
  // cas des grandeurs locales si elles sont sauvegardées
  if (eps_loc_HH != NULL)
   { eps_loc_HH->ChBase(gamma);};
  if (sig_loc_HH != NULL)
   { sig_loc_HH->ChBase(gamma);};

};

// procedure permettant de completer éventuellement les données particulières
// de la loi stockées
// au niveau du point d'intégration par exemple: exemple: un repère d'anisotropie
// completer est appelé apres sa creation avec les donnees du bloc transmis
// peut etre appeler plusieurs fois
Loi_comp_abstraite::SaveResul* Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee
         ::Complete_SaveResul(const BlocGen & bloc, const Tableau <Coordonnee>& tab_coor
                              ,const Loi_comp_abstraite* loi)
  {// on regarde  s'il s'agit d'un repère d'orthotropie
   if (bloc.Nom(1) == "repere_anisotropie_")
    {// ensuite on vérifie le nom de l'identificateur
     Loi_ortho2D_C_entrainee* loiOrtho = (Loi_ortho2D_C_entrainee*) loi;
     // dimensionnement des bases d'orthotropie
     //   . elles ont la dimension de l'espace: donc soit 2 soit 3
     //   . on utilise seulement les deux premiers vecteurs
     int dim = ParaGlob::Dimension();
     if (loiOrtho->Type_transport() == 0)
      {O_H = new BaseH(dim,2); sig_loc_HH = NevezTenseurHH(2);  }
     else
      {O_B = new BaseB(dim,2); eps_loc_HH = NevezTenseurHH(2);  };
     // récupération du repère
     if (bloc.Nom(2) == loiOrtho->NomRepere())
       {// c'est le bon, récupération des 2 premiers vecteurs
        if (O_B != NULL)
         {for (int i=1;i<3;i++)
           O_B->CoordoB(i).Change_val(tab_coor(i));
         };
        if (O_H != NULL)
         {for (int i=1;i<3;i++)
           O_H->CoordoH(i).Change_val(tab_coor(i));
         };
       };
    };
   //
   return this;
  };

// initialise les informations de travail concernant le pas de temps en cours
void Loi_ortho2D_C_entrainee::SaveResulLoi_ortho2D_C_entrainee::Init_debut_calcul()
   { };

// ========== fin des fonctions pour la classe de sauvegarde des résultats =========

Loi_ortho2D_C_entrainee::Loi_ortho2D_C_entrainee ()  : // Constructeur par defaut
  Loi_comp_abstraite(ORTHOELA2D_C,CAT_MECANIQUE,2)
  ,E1(-ConstMath::trespetit),E2(-ConstMath::trespetit),E3(-ConstMath::trespetit)
  ,nu12(-ConstMath::trespetit),nu13(-ConstMath::trespetit),nu23(-ConstMath::trespetit)
  ,G12(-ConstMath::trespetit)
  ,fct_para(7),cas_calcul(0),type_transport(0)
  ,verification_convexite(1),sortie_post(0)
  ,nom_repere("")
  ,inv_loi(2,2),Op_B(2,2),d_Op_B(2,2),d_Op_H(2,2),pO_B(2,2),pO_H(2,2)
  ,beta_inv(2,2),beta(2,2),gamma(2,2),beta_transpose(2,2),gamma_transpose(2,2)
  ,alpha_H(2,2)
  ,I_x_I_HHHH(),I_xbarre_I_HHHH(),I_x_eps_HHHH(),Ixbarre_eps_HHHH()
    {for (int i=1;i< 8;i++)
       fct_para(i) = NULL;
     null_fct_para=1; // pour l'instant pas de fonction
    };

		// Contructeur fonction de tous les paramètres constants de la loi
Loi_ortho2D_C_entrainee::Loi_ortho2D_C_entrainee(const double& EE1,const double& EE2,const double& EE3
                                   ,const double& nunu12,const double& nunu13,const double& nunu23
                                   ,const double& GG12
                                   ,const string& nom_rep):
   Loi_comp_abstraite(ORTHOELA2D_C,CAT_THERMO_MECANIQUE,2)
   ,E1(EE1),E2(EE2),E3(EE3),nu12(nunu12),nu13(nunu13),nu23(nunu23)
   ,G12(GG12)
   ,fct_para(7),cas_calcul(0),type_transport(0)
   ,verification_convexite(1),sortie_post(0)
   ,nom_repere(nom_rep)
   ,inv_loi(2,2),Op_B(2,2),d_Op_B(2,2),d_Op_H(2,2),pO_B(2,2),pO_H(2,2)
   ,beta_inv(2,2),beta(2,2),gamma(2,2),beta_transpose(2,2),gamma_transpose(2,2)
   ,alpha_H(2,2)
   ,I_x_I_HHHH(),I_xbarre_I_HHHH(),I_x_eps_HHHH(),Ixbarre_eps_HHHH()
    {for (int i=1;i< 8;i++)
       fct_para(i) = NULL;
     null_fct_para=1; // pour l'instant pas de fonction
    };

// Constructeur de copie
Loi_ortho2D_C_entrainee::Loi_ortho2D_C_entrainee (const Loi_ortho2D_C_entrainee& loi) :
   Loi_comp_abstraite(loi)
   ,E1(loi.E1),E2(loi.E2),E3(loi.E3),nu12(loi.nu12),nu13(loi.nu13),nu23(loi.nu23)
   ,G12(loi.G12)
   ,fct_para(loi.fct_para),cas_calcul(loi.cas_calcul)
   ,inv_loi(loi.inv_loi),Op_B(2,2),d_Op_B(2,2),d_Op_H(2,2),pO_B(2,2),pO_H(2,2)
   ,beta_inv(2,2),beta(2,2),gamma(2,2),beta_transpose(2,2),gamma_transpose(2,2)
   ,alpha_H(2,2)
   ,type_transport(loi.type_transport)
   ,verification_convexite(loi.verification_convexite),sortie_post(loi.sortie_post)
   ,nom_repere(loi.nom_repere)
   ,I_x_I_HHHH(),I_xbarre_I_HHHH(),I_x_eps_HHHH(),Ixbarre_eps_HHHH()
	 {// on regarde s'il s'agit d'une courbe locale ou d'une courbe globale
   for (int i=1;i< 8;i++)
	   {if (fct_para(i) != NULL)
	     {null_fct_para=0; // dans tous les cas on indique qu'il y a des fonctions
       if (fct_para(i)->NomFonction() == "_")
        {// comme il s'agit d'une fonction locale on la redéfinie (sinon pb lors du destructeur de loi)
         string non_fonction("_");
         fct_para(i) = Fonction_nD::New_Fonction_nD(*fct_para(i));
        };
      };
    };
  };

Loi_ortho2D_C_entrainee::~Loi_ortho2D_C_entrainee ()
  // Destructeur
  { for (int i=1;i< 8;i++)
      {if (fct_para(i) != NULL)
         if (fct_para(i)->NomFonction() == "_") delete fct_para(i);
      };
  };

// Lecture des donnees de la classe sur fichier
void Loi_ortho2D_C_entrainee::LectureDonneesParticulieres (UtilLecture * entreePrinc,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  {
    // on lit les coefficients dans l'ordre
    string nom_class_methode("Loi_ortho2D_C_entrainee::LectureDonneesParticulieres");
    double val_defaut=0.;
    double min = 0.; double max = -1; // max < min => la condition n'est pas prise en compte
   
    // pour faire une boucle de lecture on constitue un tableau de mots clés
    Tableau <string > tab_mot_cle(7);
    tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
    tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
    tab_mot_cle(7) = "G12";
    // puis un tableau pour les valeurs
    Tableau < double * > coef(7);
    coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
    coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
    coef(7) = & G12;

    // on boucle sur les 7 coefficients
    for (int i=1;i< 8;i++)
     {string mot_cle1=tab_mot_cle(i)+"=";
      string mot_cle2=tab_mot_cle(i)+"_fonction_nD:";
      if(strstr(entreePrinc->tablcar,mot_cle2.c_str())==0)
       {// lecture du paramètre
        if (i<4) // dans le cas des Ei, il faut qu'ils soient tous non nulles
                 // sinon on ne peut pas calculer inv_loi
         { min = ConstMath::unpeupetit; max = ConstMath::grand; }
        else {min = 0.; max = -1; };// max < min => la condition n'est pas prise en compte
        if (!entreePrinc->Lecture_un_parametre_double(val_defaut,nom_class_methode
                                                        ,min,max,mot_cle1, *coef(i) ))
           { entreePrinc->MessageBuffer("**erreur en lecture**  "+mot_cle1);
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
           };
       }
      else // on lit une fonction
       {// on passe le mot clé générique
        bool lec = entreePrinc->Lecture_et_verif_mot_cle(nom_class_methode,mot_cle1);
        // on lit le nom de la fonction
        string nom_fonct;
        lec = lec && entreePrinc->Lecture_mot_cle_et_string(nom_class_methode,mot_cle2,nom_fonct);
        if (!lec )
           { entreePrinc->MessageBuffer("**erreur en lecture**  "+mot_cle2);
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
           };
        null_fct_para=0; // on indique qu'il y a des fonctions
        // maintenant on définit la fonction
        if (lesFonctionsnD.Existe(nom_fonct))
         {fct_para(i) = lesFonctionsnD.Trouve(nom_fonct);
         }
        else
         {// sinon il faut la lire maintenant
          string non("_");
          fct_para(i) = Fonction_nD::New_Fonction_nD(non, Id_Nom_Fonction_nD(nom_fonct));
          // lecture de la courbe
          fct_para(i)->LectDonnParticulieres_Fonction_nD (non,entreePrinc);
          // maintenant on vérifie que la fonction est utilisable
          if (fct_para(i)->NbComposante() != 1 )
           { cout << "\n erreur en lecture, la fonction " << nom_fonct
                  << " est une fonction vectorielle a   " << fct_para(i)->NbComposante()
                  << " composante alors qu'elle devrait etre scalaire ! "
                  << " elle n'est donc pas utilisable !! ";
             string message("\n**erreur08** \n"+nom_class_methode+"(...");
             entreePrinc->MessageBuffer(message);
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
           };
        };
        if (i != 7)
          entreePrinc->NouvelleDonnee(); // on se positionne sur un nouvel enreg
       };
     }; // fin de la boucle for (int i=1;i< 7;i++)
     
    // lecture du repère d'orthotropie entraîné, associé
    string mot_cle("nom_repere_associe_");
    entreePrinc->NouvelleDonnee(); // on se positionne sur un nouvel enreg
    bool lec = entreePrinc->Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_repere);
    if (!lec )
       { entreePrinc->MessageBuffer("**erreur en lecture**  "+mot_cle);
         throw (UtilLecture::ErrNouvelleDonnee(-1));
         Sortie(1);
       };
   
    // --- lecture éventuelle des paramètres de réglage ----
    cas_calcul = 0;   // par défaut
    if(strstr(entreePrinc->tablcar,"avec_parametres_de_reglage_")!=0)
     {string nom;
      entreePrinc->NouvelleDonnee(); // on se positionne sur un nouvel enreg
      // on lit tant que l'on ne rencontre pas la ligne contenant "fin_parametres_reglage_"
      // ou un nouveau mot clé global auquel cas il y a pb !!
      MotCle motCle; // ref aux mots cle
      while (strstr(entreePrinc->tablcar,"fin_parametres_reglage_")==0)
       {
        // si on a  un mot clé global dans la ligne courante c-a-d dans tablcar --> erreur
        if ( motCle.SimotCle(entreePrinc->tablcar))
         { cout << "\n erreur de lecture des parametre de reglage : on n'a pas trouve le mot cle "
                << " fin_parametres_reglage_ et par contre la ligne courante contient un mot cle global  ";
           entreePrinc->MessageBuffer("** erreur5 des parametres de reglage de la loi de comportement de Loi_ortho2D_C_entrainee **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         };
        
        // lecture d'un mot clé
        *(entreePrinc->entree) >> nom;
        
        if ((entreePrinc->entree)->rdstate() == 0)
          {} // lecture normale
        #ifdef ENLINUX
        else  if ((entreePrinc->entree)->fail())
           // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
          {   entreePrinc->NouvelleDonnee();  // lecture d'un nouvelle enregistrement
              *(entreePrinc->entree) >>nom;
           }
        #else
        else  if ((entreePrinc->entree)->eof())
          // la lecture est bonne mais on a atteind la fin de la ligne
          { if(nom != "fin_parametres_reglage_")
              {entreePrinc->NouvelleDonnee(); *(entreePrinc->entree) >> nom;};
          }
        #endif
        else // cas d'une erreur de lecture
         { cout << "\n erreur de lecture inconnue  ";
           entreePrinc->MessageBuffer("** erreur4 des parametres de reglage de la loi de comportement de Loi_ortho2D_C_entrainee **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         };
        
        // type de transport
        if (nom == "type_transport_")
         { // lecture du type
           *(entreePrinc->entree) >> type_transport;
           if ((type_transport!=0)&&(type_transport!=1))
             { cout << "\n le type de transport lue pour la loi de Loi_ortho2D_C_entrainee:  "<< type_transport
                    << " n'est pas acceptable (uniquement 0 ou 1), on utilise le type par defaut (0)"
                    << " qui correspond a un transport de type  contravariant ";
               type_transport = 0;
             };
         }
        // forcer un affichage particulier pour les méthodes
        else if (nom == "permet_affichage_")
         {Lecture_permet_affichage(entreePrinc,lesFonctionsnD);
         }
        // on regarde si le calcul est éventuellement uniquement déviatorique
        else if (nom == "seule_deviatorique")
         {if (cas_calcul == 2) {cas_calcul=0;} else {cas_calcul = 1;};}
        // idem pour la partie sphérique
        else if (nom == "seule_spherique")
         {if (cas_calcul == 1) {cas_calcul=0;} else {cas_calcul = 2;};}
        // cas de la vérification de la convexité
        else if (nom == "verification_convexite_")
         {*(entreePrinc->entree) >> verification_convexite;
         }
        // forcer un stockage pour des sorties
        else if (nom == "sortie_post_")
         {*(entreePrinc->entree) >> sortie_post;
         }

        // sinon ce n'est pas un mot clé connu, on le signale
        else if (nom != "fin_parametres_reglage_")
         { cout << "\n erreur en lecture d'un parametre, le mot cle est inconnu "
                << " on a lu : " << nom << endl;
           if (ParaGlob::NiveauImpression()>3)
                cout << "\n Loi_ortho2D_C_entrainee::LectureDonneesParticulieres(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         }
       }; //-- fin du while
      }; //-- fin de la lecture des paramètres de réglage

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

    // dans le cas particulier où il n'y a pas de fonction nD on peut calculer inv_loi
    if (null_fct_para)
     {// on vérifie la convexité
      if (verification_convexite)
        Verif_convexite();
      // on commence par remplir la matrice
      inv_loi(1,1) = 1./E1;inv_loi(2,2) = 1./E2;
      inv_loi(1,2) = inv_loi(2,1) = -nu12/E1;
      inv_loi = inv_loi.Inverse(); // on inverse la matrice
     };
   
   
  };
// affichage de la loi
void Loi_ortho2D_C_entrainee::Affiche() const
  { // pour faire une boucle  on constitue un tableau de mots clés
    Tableau <string > tab_mot_cle(7);
    tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
    tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
    tab_mot_cle(7) = "G12";
    // puis un tableau pour les valeurs
    Tableau < const double * > coef(7);
    coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
    coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
    coef(7) = & G12;

    // on boucle sur les 7 coefficients
    cout << "\n loi de comportement orthotrope elastique 2D CP ";
    for (int i=1;i< 8;i++)
     {string mot_cle1=tab_mot_cle(i)+"= ";
      string mot_cle2=tab_mot_cle(i)+"_fonction_nD:";
      cout <<  mot_cle1 ;
      if (fct_para(i) == NULL)
        cout << *coef(i) << " ";
      else
        {cout << mot_cle2 << " ";
         if (fct_para(i)->NomFonction() != "_")
           cout << fct_para(i)->NomFonction();
         else
           fct_para(i)->Affiche();
         cout << "\n";
        };
     };
    // le nom du repère associé
    cout << "\n nom_repere_associe " << nom_repere;

    // indicateur de cas de calcul
    if (cas_calcul != 0)
    	{ if (cas_calcul == 1)
    	   {cout << "\n calcul uniquement deviatorique ";}
    	  else if (cas_calcul == 2)
    	   {cout << " calcul uniquement spherique ";}
    	  else
    	   {cout << " cas de calcul mal defini !! ";}; 
    	};
    // affichage du type de transport
    cout << " type_transport: " << type_transport;
    // niveau d'affichage
    cout << " niveau_affichage_local: ";
    Affiche_niveau_affichage();
    cout << " verification_convexite: "<< verification_convexite;
    cout << " sortie_post: "<< sortie_post;
    cout << endl;
    // appel de la classe mère
    Loi_comp_abstraite::Affiche_don_classe_abstraite();
  };
            
// affichage et definition interactive des commandes particulières à chaques lois
void Loi_ortho2D_C_entrainee::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");

  // pour faire une boucle  on constitue un tableau de mots clés
  Tableau <string > tab_mot_cle(7);
  tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
  tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
  tab_mot_cle(7) = "G12";
  // puis un tableau pour les valeurs
  Tableau < double * > coef(7);
  coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
  coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
  coef(7) = & G12;

  E1=100000; E2= 50000;E3= 20000;
  nu12= 0.2; nu13 = 0.3; nu23 = 0.1;
  G12 = 20000;
  

  sort << "\n# .......  loi de comportement orthotrope elastique 2D contrainte plane........"
       << "\n#    7 parametres materiau: 3 modules, 3 coef de Poisson, 1 module de cisaillement  "
       << "\n#  et un nom de repere associe  ";
  for (int i=1;i< 8;i++)
   {string mot_cle1=tab_mot_cle(i)+"= ";
    string mot_cle2=tab_mot_cle(i)+"_fonction_nD:";
    sort << mot_cle1 << setprecision(6) << *coef(i) << " ";
   };
  sort << "\n nom_repere_associe_  repere1 ";
  sort << endl;

  // cas avec plus d'information
	 if ((rep != "o") && (rep != "O" ) && (rep != "0") )
      { // cas d'une loi thermo dépendante
        sort << "\n# .... infos complementaires ...."
             <<"\n# 1) Pour chaque parametre materiau, individuellement, il est possible "
             <<"\n#    d'utiliser une fonction nD a la place d'une valeur numerique. "
             <<"\n#    La fonction nD peut alors dependre de toutes les grandeurs disponibles "
             <<"\n#    localement, en particulier la position, les donnees imposees par l'utilisateur "
             <<"\n#    par exe: une temperature, ou tout ddl obtenu directement ou par interpolation "
             <<"\n#    suivant sa disponibilite, sachant que l'on regarde d'abord si la grandeur est "
             <<"\n#    directement disponible au point d'integration, sinon on regarde si elle est "
             <<"\n#    disponible par interpolation. "
             <<"\n#    "
             <<"\n#    Supposons que l'on veuille que E2 soit une fonction nD on ecrira: "
             <<"\n#     soit a: "
             <<"\n#        E2= E2_fonction_nD: un_nom_de_fonction_existant "
             <<"\n#     soit b: "
             <<"\n#        E2= E2_fonction_nD: un_nom_de_type_de_fonction_existant "
             <<"\n#      suivit sur la ligne suivante de la definition specifique de la fonction "
             <<"\n# "
             <<"\n#    exemple d'un cas a: "
             <<"\n#        E2= E2_fonction_nD: f1_temperature  "
             <<"\n#      fi_temperature doit alors avoir ete definie dans les fonctions nD"
             <<"\n# "
             <<"\n#    exemple d'un cas b: "
             <<"\n#        E2= E2_fonction_nD: FONCTION_EXPRESSION_LITTERALE_nD  "
             <<"\n#               deb_list_var_ TEMP  fin_list_var_  "
             <<"\n#               fct= (100726-101325)/50*TEMP + 101325  "
             <<"\n#               fin_parametres_fonction_expression_litterale_  "
             <<"\n# "
             <<"\n# Remarques: "
             <<"\n#    a) apres chaque definition d'une fonction nD on change de ligne "
             <<"\n#    b) pour les autres coefficients, on remplace E2 par E1,  ou"
             <<"\n#       nu12 ou nu13 ou n23 ou G12  "
             <<"\n# "
             <<"\n# 2) Par defaut, la base initiale d'orthotropie est transportee dans l'etat courant "
             <<"\n#    via une methode de type transport contravariant (cf. doc) "
             <<"\n#    Il est possible d'indiquer un transport de type covariant. Pour ce faire "
             <<"\n#    on utilise le mot cle: type_transport_ suivi de 0 ou 1 "
             <<"\n#    0 : pour un transport de type contravariant (valeur par defaut) "
             <<"\n#    1 : pour un transport de type covariant "
             <<"\n# "
             <<"\n# 3)"
             << "\n# -------------- affichage des erreurs et des warning ---------- "
             << "\n# - l'affichage normale est fonction du parametre global d'affichage gerer"
             << "\n# par le niveau d'affichage cependant pour des raisons par exemple de mise au point,"
             << "\n#  il est possible de permettre l'affichage  a un niveau particulier "
             << "\n#  (mot cle : permet_affichage_ suivi d'un nombre entier) en plus de l'affichage normal. "
             << "\n# l'affichage s'effectuera donc en fonction de l'affichage normale et de l'affichage particulier."
             << "\n# Le fonctionnement de l'affichage particulier suit les mêmes règles que l'affichage globale"
             << "\n# soit permet_affichage_ est nulle (cas par defaut), dans ce cas l'affichage est fonction du niveau global"
             << "\n# soit permet_affichage_ vaut n par exemple, dans ce cas l'affichage est fonction uniquement de n "
             << "\n# "
             << "\n# ex: permet_affichage_ 5  "
             << "\n#             "
             <<"\n# "
             <<"\n# 4) Il est possible de calculer que la partie spherique du tenseur de contrainte "
             <<"\n#    ou que la partie deviatorique "
             <<"\n#   Pour ce faire on indique a la suite des autres parametres:"
             <<"\n#    soit le mot clef : seule_deviatorique "
             <<"\n#    soit le mot clef : seule_spherique "
             <<"\n# "
             <<"\n# 4) Par defaut, on verifie la convexite du potentiel (cf. theorie) "
             <<"\n# mais le calcul ne s'arrete pas si le potentiel n'est pas convexe,"
             <<"\n# il y a seulement un message d'erreur"
             <<"\n# "
             <<"\n# on peut supprimer cette verification a l'aide du mote cle "
             <<"\n# verification_convexite_ "
             <<"\n# suivi de 0 ou 1 (val par defaut) suivant que l'on ne veut pas de verification "
             <<"\n# ou le contraire "
             <<"\n# "
             << "\n# 5) --------------- acces en sortie a des grandeurs intermediaires de calcul  -------"
             << "\n#  A chaque resolution, il est possible de stocker:  "
             << "\n#  - le tenseur des contraintes exprime dans le repere d'anisotropie "
             << "\n#  - le tenseur des deformation exprime dans le repere d'anisotropie "
             << "\n#  - les parametres d'orthotropie entrainee: interessant s'ils varient  "
             << "\n#  le mot cle est sortie_post_ , par defaut il vaut 0, dans ce cas aucun indicateur n'est stoke"
             << "\n#  s'il est different de 0, on peut acceder aux grandeurs "
             << "\n#  seules les grandeurs en cours sont disponibles, il n'y a pas de stockage sur plusieurs increment "
             << "\n# "
             << "\n# ex: sortie_post_ 1 "
             << "\n# "
             <<"\n# "
             ;
      };

    // appel de la classe mère
    Loi_comp_abstraite::Info_commande_don_LoisDeComp(entreePrinc);     
  };  		  	  

// test si la loi est complete
int Loi_ortho2D_C_entrainee::TestComplet()
    { int ret = LoiAbstraiteGeneral::TestComplet();
  
      // pour faire une boucle  on constitue un tableau de mots clés
      Tableau <string > tab_mot_cle(7);
      tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
      tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
      tab_mot_cle(7) = "G12";
      // puis un tableau pour les valeurs
      Tableau < double * > coef(7);
      coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
      coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
      coef(7) = & G12;
      for (int i=1;i< 8;i++)
       if ((*coef(i) == -ConstMath::trespetit) && (fct_para(i) == NULL))
         {string mot_cle1=tab_mot_cle(i)+"= ";
          cout <<  mot_cle1  << " n'est pas defini \n " ;
          ret = 0;
         };
      // test du cas de calcul
      if ((cas_calcul < 0) || (cas_calcul > 2))
       { cout << "\n l'indicateur de calcul cas_calcul= " << cas_calcul << " n'est pas correcte "
              << "\n ceci pour la Loi_ortho2D_C_entrainee";
         ret = 0;
       };
      // le nom du repère associé
      if (nom_repere.length() == 0)
       { cout << "\n le nom du repere assoce  n'est pas defini "
              << "\n ceci pour la Loi_ortho2D_C_entrainee";
         ret = 0;
       };

      // info globale disponible actuellement
      if (!ret)
       { cout << "\n loi ortho elastique incomplete : ";
         Affiche();
       };
      // retour
      return ret;
    }; 



// 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
void Loi_ortho2D_C_entrainee::Grandeur_particuliere
              (bool ,List_io<TypeQuelconque>& liTQ,Loi_comp_abstraite::SaveResul * saveDon,list<int>& decal) const
{  // ici on est en 2D et les grandeurs sont par principe en locale, donc la variable absolue ne sert pas
   // on passe en revue la liste
   List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end();
   list<int>::iterator idecal=decal.begin();
   for (itq=liTQ.begin();itq!=itqfin;itq++,idecal++)
     {TypeQuelconque& tipParticu = (*itq); // pour simplifier
      if (tipParticu.EnuTypeQuelconque().Nom_vide()) // veut dire que c'est un enum pur
       switch (tipParticu.EnuTypeQuelconque().EnumTQ())
       {
          //  -----cas de la déformation d'épaisseur à t
          case DEF_EPAISSEUR:
           {SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveDon);Tab_Grandeur_scalaire_double& tyTQ= *((Tab_Grandeur_scalaire_double*) (*itq).Grandeur_pointee()); // pour simplifier
             tyTQ(1+(*idecal)) = save_resul.eps33;
            break;
           };
          case REPERE_D_ANISOTROPIE:
           // a) ----- cas du repère d'anisotropie
            { SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveDon);
              Tab_Grandeur_BaseH& tyTQ= *((Tab_Grandeur_BaseH*) (*itq).Grandeur_pointee()); // pour simplifier
              tyTQ(1+(*idecal))=save_resul.Op_H;
             
//////----- debug
//cout << "\n debug Loi_ortho2D_C_entrainee::Grandeur_particuliere(.. "
//     << "\n save_resul.Op_H: "<< save_resul.Op_H << "\n ";
//Signature_pti_encours(cout);
//
//////----- fin debug
                                     
              (*idecal)++; break;
            }
          case EPS_TRANSPORTEE_ANISO:
           //  ----- cas de la déformation transportée dans le repère d'orthotropie
            { SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveDon);

              Tab_Grandeur_TenseurHH& tyTQ= *((Tab_Grandeur_TenseurHH*) (*itq).Grandeur_pointee()); // pour simplifier
              if (sortie_post) {tyTQ(1+(*idecal))=  *(save_resul.eps_loc_HH);}
              else {tyTQ(1+(*idecal)).Inita(0.);};
              (*idecal)++; break;
            }
          case SIGMA_DANS_ANISO:
           //  ----- cas de la contrainte calculée dans le repère d'orthotropie
            { SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveDon);
              Tab_Grandeur_TenseurHH& tyTQ= *((Tab_Grandeur_TenseurHH*) (*itq).Grandeur_pointee()); // pour simplifier
              if (sortie_post) {tyTQ(1+(*idecal))=  *(save_resul.sig_loc_HH);}
              else {tyTQ(1+(*idecal)).Inita(0.);};
              (*idecal)++; break;
            }
          case PARA_ORTHO:
           //  ----- cas des paramètres d'orthotropie
            { SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveDon);
              Tab_Grandeur_Vecteur& tyTQ= *((Tab_Grandeur_Vecteur*) (*itq).Grandeur_pointee()); // pour simplifier
              if (sortie_post) {tyTQ(1+(*idecal))=  *(save_resul.para_loi);}
              else {tyTQ(1+(*idecal)).Zero();};
              (*idecal)++; break;
            }

          default: ;// on ne fait rien
       };

     };
};

// récupération et création 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
void Loi_ortho2D_C_entrainee::ListeGrandeurs_particulieres(bool absolue,List_io<TypeQuelconque>& liTQ) const
 {
  
  // pour le stockage
  Tableau <double> tab_double(1);
  Tab_Grandeur_scalaire_double grand_courant(tab_double);   //  $$$ cas du repère local d'orthotropie
  int dim_espace = ParaGlob::Dimension();
  {List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end(); bool nexistePas = true;
   for (itq=liTQ.begin();itq!=itqfin;itq++)
     if ((*itq).EnuTypeQuelconque() == REPERE_D_ANISOTROPIE)
      { Tab_Grandeur_BaseH& tyTQ= *((Tab_Grandeur_BaseH*) (*itq).Grandeur_pointee()); // pour simplifier
        int taille = tyTQ.Taille()+1;
        tyTQ.Change_taille(taille); nexistePas = false;
      };
   if (nexistePas)
     {Grandeur_BaseH v_rep(dim_espace,2);
      Tab_Grandeur_BaseH grand5(v_rep,1); // def d'une grandeur courante 
      TypeQuelconque typQ6(REPERE_D_ANISOTROPIE,EPS11,grand5);
      liTQ.push_back(typQ6);
     };
  };
  //  -----cas de la déformation d'épaisseur à t uniquement
  //on regarde si ce type d'info existe déjà: si oui on augmente la taille du tableau, si non on crée
  {List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end(); bool nexistePas = true;
   for (itq=liTQ.begin();itq!=itqfin;itq++)
     if ((*itq).EnuTypeQuelconque() == DEF_EPAISSEUR)
       { Tab_Grandeur_scalaire_double& tyTQ= *((Tab_Grandeur_scalaire_double*) (*itq).Grandeur_pointee()); // pour simplifier
         int taille = tyTQ.Taille()+1;
         tyTQ.Change_taille(taille); nexistePas = false;
       };
   if (nexistePas)
     {TypeQuelconque typQ1(DEF_EPAISSEUR,EPS11,grand_courant);
      liTQ.push_back(typQ1);
     };
  };

  // ---- la suite dépend de l'indicateur : sortie_post
  if (sortie_post)
   {   // $$$ cas de la déformation transportée dans le repère d'orthotropie
    {List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end(); bool nexistePas = true;
     for (itq=liTQ.begin();itq!=itqfin;itq++)
       if ((*itq).EnuTypeQuelconque() == EPS_TRANSPORTEE_ANISO)
        {Tab_Grandeur_TenseurHH& tyTQ= *((Tab_Grandeur_TenseurHH*) (*itq).Grandeur_pointee()); // pour simplifier
         int taille = tyTQ.Taille()+1;
         tyTQ.Change_taille(taille); nexistePas = false;
        };
     if (nexistePas)
       {TenseurHH* tens = NevezTenseurHH(2); // un tenseur typique
        Tab_Grandeur_TenseurHH eps_loc_HH(*tens,1);
        // def d'un type quelconque représentatif
        TypeQuelconque typQ(EPS_TRANSPORTEE_ANISO,EPS11,eps_loc_HH);
        liTQ.push_back(typQ);
        delete tens; // car on n'en a plus besoin
      };
    };
    // $$$ cas de la contrainte calculée dans le repère d'orthotropie
    {List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end(); bool nexistePas = true;
     for (itq=liTQ.begin();itq!=itqfin;itq++)
       if ((*itq).EnuTypeQuelconque() == SIGMA_DANS_ANISO)
        {Tab_Grandeur_TenseurHH& tyTQ= *((Tab_Grandeur_TenseurHH*) (*itq).Grandeur_pointee()); // pour simplifier
         int taille = tyTQ.Taille()+1;
         tyTQ.Change_taille(taille); nexistePas = false;
        };
     if (nexistePas)
       {TenseurHH* tens = NevezTenseurHH(2); // un tenseur typique
        Tab_Grandeur_TenseurHH eps_loc_HH(*tens,1);
        // def d'un type quelconque représentatif
        TypeQuelconque typQ(SIGMA_DANS_ANISO,SIG11,eps_loc_HH);
        liTQ.push_back(typQ);
        delete tens; // car on n'en a plus besoin
      };
    };
    // $$$ cas des paramètres de la loi de comportement
    {List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end(); bool nexistePas = true;
     for (itq=liTQ.begin();itq!=itqfin;itq++)
       if ((*itq).EnuTypeQuelconque() == PARA_ORTHO)
        {Tab_Grandeur_Vecteur& tyTQ= *((Tab_Grandeur_Vecteur*) (*itq).Grandeur_pointee()); // pour simplifier
         int taille = tyTQ.Taille()+1;
         tyTQ.Change_taille(taille); nexistePas = false;
        };
     if (nexistePas)
       {Vecteur  tens(7); // les 7 paramètres
        Tab_Grandeur_Vecteur gr_vec_para(tens,1);
        // def d'un type quelconque représentatif
        TypeQuelconque typQ(PARA_ORTHO,EPS11,gr_vec_para);
        liTQ.push_back(typQ);
      };
    };

   }; // fin du cas ou sortie_post est actif, c-a-d que l'on veut des infos sur les indicateurs
   // de résolution

 };


	   //----- 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_ortho2D_C_entrainee::Lecture_base_info_loi(ifstream& ent,const int cas,LesReferences& lesRef,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
	{ string toto,nom;
   if (cas == 1)
    { ent >> nom ;
      if (nom != "ORTHOELA2D_C")
       {cout <<"\n *** erreur en lecture du type de la loi de comportement, on attendait"
             << " la chaine de caracteres: ORTHOELA2D_C et on a lu "
             << nom <<" !!! on ne peut pas continuer "
             << "\n Loi_ortho2D_C_entrainee::Lecture_base_info_loi(.. "
             << flush;
        Sortie(1);
       };
      // pour faire une boucle  on constitue un tableau de mots clés
      Tableau <string > tab_mot_cle(7);
      tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
      tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
      tab_mot_cle(7) = "G12";
      // puis un tableau pour les valeurs
      Tableau < double * > coef(7);
      coef(1) = &E1; coef(2) = & E2; coef(3) = &E3;
           coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
           coef(7) = & G12;
      // cela va permettre de choisir entre une valeur fixe et une fonction nD
      for (int i=1;i< 8;i++)
        { ent >> toto >> nom;
          string mot_cle2=tab_mot_cle(i)+"_fonction_nD:";
          if (nom == mot_cle2)
            // cas d'une fonction nD
            {fct_para(i) = lesFonctionsnD.Lecture_pour_base_info(ent,cas,fct_para(i));
            }
          else // cas d'une valeur fixe
           {(*coef(i)) = ChangeReel(nom);};
        };
      // lecture du repère associé
      ent >> nom >> nom_repere;
      // indicateur pour les calculs partielles
      ent >> nom >> cas_calcul ;
      // le type de transport
      ent >> nom >> type_transport;
      // le niveau d'affichage
      Lecture_permet_affichage(ent,cas,lesFonctionsnD);
      // sortie_post
      ent >> nom >> sortie_post;
    };

	  // 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_ortho2D_C_entrainee::Ecriture_base_info_loi(ofstream& sort,const int cas)
   { if (cas == 1)
       { sort << " ORTHOELA2D_C " ;
         // pour faire une boucle  on constitue un tableau de mots clés
         Tableau <string > tab_mot_cle(7);
         tab_mot_cle(1) = "E1";tab_mot_cle(2) = "E2";tab_mot_cle(3) = "E3";
         tab_mot_cle(4) = "nu12";tab_mot_cle(5) = "nu13";tab_mot_cle(6) = "nu23";
         tab_mot_cle(7) = "G12";
         // puis un tableau pour les valeurs
         Tableau < double * > coef(7);
         coef(1) = &E1; coef(2) = & E2; coef(3) = &E3;
         coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
         coef(7) = & G12;

         // on boucle sur les 7 coefficients
         sort << "\n loi de comportement orthotrope elastique 2D contrainte plane";
         for (int i=1;i< 8;i++)
          {string mot_cle1=tab_mot_cle(i)+"= ";
           string mot_cle2=tab_mot_cle(i)+"_fonction_nD:";
           sort <<  mot_cle1 ;
           if (fct_para(i) == NULL)
             sort << *coef(i) << " ";
           else
             {sort << mot_cle2 << " ";
              if (fct_para(i)->NomFonction() != "_")
                sort << fct_para(i)->NomFonction();
              else
                fct_para(i)->Affiche();
              sort << "\n";
             };
          };
         // le nom du repère associé
         sort << "\n nom_repere_associe_ "<< nom_repere;
         // indicateur de cas de calcul
         if (cas_calcul != 0)
          { if (cas_calcul == 1)
             {sort << "\n seul_deviatorique ";}
            else if (cas_calcul == 2)
             {sort << " seul_spherique ";}
            else
             {sort << " cas_de_calcul_mal_defini ";};
          };
         // affichage du type de transport
         sort << " type_transport: " << type_transport;
         // niveau d'affichage
         Affiche_niveau_affichage(sort,cas);
         sort << " verification_convexite: "<< verification_convexite;
         sort << " sortie_post: "<<sortie_post;
         sort << endl;
       };
   // 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_ortho2D_C_entrainee::Module_young_equivalent(Enum_dure temps,const Deformation & def,SaveResul * )
    { /*if (!thermo_dependant)
	       { return E;}
	     else
	       { temperature_tdt = def.DonneeInterpoleeScalaire(TEMP,temps);
          return E_temperature->Valeur(temperature_tdt);
        };
*/
     cout << "\n *** attention, methode non implante: "
          << "\n Loi_ortho2D_C_entrainee::Module_young_equivalent(...";
     Sortie(1);


    };
	  
// récupération d'un module de compressibilité équivalent à la loi pour un chargement nul
// il s'agit ici de la relation -pression = sigma_trace/3. = module de compressibilité * I_eps
double Loi_ortho2D_C_entrainee::Module_compressibilite_equivalent(Enum_dure temps,const Deformation & def,SaveResul * )
    {/* if (!thermo_dependant)
	       { return E/(3.*(1.-2.*nu));}
	      else
	       { temperature_tdt = def.DonneeInterpoleeScalaire(TEMP,temps);
          return E_temperature->Valeur(temperature_tdt)/(3.*(1.-2.*nu));
        };
*/
     cout << "\n *** attention, methode non implante: "
          << "\n Loi_ortho2D_C_entrainee::Module_compressibilite_equivalent(...";
     Sortie(1);

    };

 // ========== codage des METHODES VIRTUELLES  protegees:================
//  virtual void Calcul_SigmaHH
//     (TenseurHH & sigHH_t,TenseurBB& DepsBB,DdlElement & tab_ddl
//      ,TenseurBB & gijBB_t,TenseurHH & gijHH_t,BaseB& giB,BaseH& gi_H,TenseurBB & epsBB
//      ,TenseurBB & delta_epsBB,TenseurBB & gijBB,TenseurHH & gijHH,Tableau <TenseurBB *>& d_gijBB
//      ,double& jacobien_0,double& jacobien,TenseurHH & sigHH
//      ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
//      ,const Met_abstraite::Expli_t_tdt& ex) = 0;        // calcul des contraintes a t+dt
void Loi_ortho2D_C_entrainee::Calcul_SigmaHH (TenseurHH& sigHH_t,TenseurBB& ,DdlElement & tab_ddl
       ,TenseurBB & ,TenseurHH & ,BaseB& ,BaseH& ,TenseurBB&  epsBB_
       ,TenseurBB&  ,TenseurBB& gijBB_
       ,TenseurHH & gijHH_,Tableau <TenseurBB *>& d_gijBB_,double& ,double&
       ,TenseurHH & sigHH_,EnergieMeca & energ,const EnergieMeca &
       ,double& module_compressibilite,double&  module_cisaillement
       ,const Met_abstraite::Expli_t_tdt& ex)
 {
    #ifdef MISE_AU_POINT
    if (epsBB_.Dimension() != 2)
       { cout << "\nErreur : la dimension devrait etre 2 !\n";
      cout << " Loi_ortho2D_C_entrainee::Calcul_SigmaHH\n";
      Sortie(1);
    };
    #endif

    bool affichage = (Permet_affichage() > 5);
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n  --- loi de comportement orthotrope entrainee --- ";
     };
    #endif
    const Tenseur2BB & epsBB = *((Tenseur2BB*) &epsBB_); // passage en dim 2
    const Tenseur2HH & gijHH = *((Tenseur2HH*) &gijHH_); //   "      "  "  "
    const Tenseur2BB & gijBB = *((Tenseur2BB*) &gijBB_); //   "      "  "  "
    Tenseur2HH & sigHH = *((Tenseur2HH*) &sigHH_);  //   "      "  "  "

    Tenseur2BH  epsBH = epsBB * gijHH;  // deformation en mixte
    int dim = ParaGlob::Dimension(); // pour les affichages de vecteurs
  
    // récup du conteneur spécifique
    SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveResul);
    // on commence par calculer le repère d'orthotropie transporté
    // Op_H_i sont les coordonnées contravariantes de la nouvelle base
    // donc par rapport à g_i,
    BaseH& Op_H = save_resul.Op_H;
    Tableau <double> tab_norme(2);
    if (type_transport == 0)
      // transport de type contravariant
     { // on calcule les coordonnées de la base O' dans la base naturelle
      #ifdef MISE_AU_POINT
      if (save_resul.O_H == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_SigmaHH\n";
         Sortie(1);
        };
      #endif
      BaseH& O_H = (*save_resul.O_H); // coordonnées en absolu de la base d'orthotropie
      // calcul des coordonnées alpha_a^{.i} = O_H(a) * g^i  à t= 0
      for (int a = 1;a < 3; a++)
        {CoordonneeH& inter = alpha_H.CoordoH(a);
         for (int i=1;i < 3;i++)
           inter(i)= O_H(a).ScalHH((*ex.giH_0)(i));
        };

      // calcule des beta_a^{.i} tel que O'_a = beta_a^{.i} \hat{g}_i   donc au temps t+dt
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         // Op_H(a) non normé a les mêmes coordonnées alpha_a^{.j}
         // mais exprimés dans le repère actuel \hat \vec g_j
         CoordonneeH& Op_H_a = Op_H.CoordoH(a);
         Op_H_a = alpha_H(a);
         // calcul de la norme du vecteur Op_H_a
         double norme = sqrt(Op_H_a * gijBB * Op_H_a);
         tab_norme(a) = norme;
         // coordonnées finales
         Op_H_a /= norme;
         #ifdef MISE_AU_POINT
         if (affichage)
           {cout << "\n  Op_H("<<a<<"): ";
            Op_H_a.Affiche();
            cout << "\n  alpha_H("<<a<<"): ";
            alpha_H(a).Affiche();
            cout << "\n giB_tdt"; (*ex.giB_tdt)(a).Affiche();
            // affichage du repère tournée
            CoordonneeB V(dim);
            for (int j=1;j<= 2;j++) V +=  (*ex.giB_tdt)(j) * Op_H_a(j);
            cout << "\n op_H("<<a<<"):  en absolu " << V ;
           };
         #endif
       };
     }
    else
      // transport de type covariant
     { // on calcule les coordonnées de la base O' dans la base duale
      #ifdef MISE_AU_POINT
      if (save_resul.O_B == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_SigmaHH\n";
         Sortie(1);
        };
      #endif
      BaseB& O_B = (*save_resul.O_B); // pour simplifier
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         CoordonneeB& Op_B_a = Op_B.CoordoB(a);
         // calcul de la norme du vecteur Op_B_a
         double norme = sqrt(Op_B_a * gijHH * Op_B_a);
         // coordonnées finales
         Op_B_a /= norme;
       };
      // maintenant on calcule la base Op_H correspondante
      for (int i=1; i<3;i++)
         Op_H.CoordoH(i) = Op_B.CoordoB(i) * gijHH;
     };
    // on calcul la matrice de passage de la base g_i vers la base O'_i
    // O'_i = beta_i^{.j} * g_j
    // et on a également \hat{\vec g}^i = {\beta}_{a}^{.i}~\hat{\vec O'}^a
    // comme O'_i est déjà exprimé dans g_j, ses coordonnées sont directement béta
    for (int i=1; i<3;i++)
      for (int j=1; j<3;j++)
         { beta(i,j) = Op_H(i)(j);};
    // puis on calcul les coordonnées de la base duale
    beta_transpose = beta.Transpose();
    gamma = beta_transpose.Inverse();
    gamma_transpose = gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
      {cout << "\n beta: ";beta.Affiche();
       cout << "\n beta_transpose: ";beta_transpose.Affiche();
       cout << "\n gamma: ";gamma.Affiche();
       cout << "\n gamma_transpose: ";gamma_transpose.Affiche();
      };
    #endif

    // changement de base (cf. théorie) : la matrice beta est telle que:
    // gpB(i) = beta(i,j) * gB(j) <==> gp_i = beta_i^j * g_j

    // calcul des coordonnées de la déformation dans le repère O'^i
    #ifdef MISE_AU_POINT
    if (affichage)
      { TenseurBB*  eps_p_BB = NevezTenseurBB(epsBB);
        cout <<"\n eps_p_BB: "; eps_p_BB->Ecriture(cout);
        delete eps_p_BB;
      };
    #endif
    // c-a-d les coordonnées dans le dual de O'_i
    // il faut passer en 2 fois contravariant
    Tenseur2BB  eps_p_BB(epsBB);
//cout <<"\n eps_p_BB: "; eps_p_BB.Ecriture(cout);
    // il faut passer en 2 fois contravariant
    // on utilise l'opérateur d'affectation, car le résultat doit-être symétrique, or
    // les multiplications intermédiaires vont générer un tenseur systématiquement non symétrique
    Tenseur2HH eps_p_HH  = gijHH * eps_p_BB * gijHH;
    eps_p_HH.ChBase(gamma); // res = (gamma * res) * gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
      { cout <<"\n eps_p_HH: "; eps_p_HH.Ecriture(cout);
        TenseurHH*  toto = NevezTenseurHH(eps_p_HH);
        toto->ChBase(beta_transpose);
        cout << "\n retour dans la base g^i de eps^{ij} :";toto->Ecriture(cout);
        TenseurBB*  titi = NevezTenseurBB(gijBB * (*toto) * gijBB);
        cout << "\n def eps_ij :";titi->Ecriture(cout);
        delete toto; delete titi;
      };
    #endif

    double untiers = 1./3.;

    // dans le cas de fonctions nD récupération des valeurs
    if (!null_fct_para)
//  Tableau <Fonction_nD* > fct_para; // fonction nD éventuelle d'évolution des paramètres
     {// un tableau de travail pour les valeurs sous forme indicée
      Tableau < double * > coef(7);
      coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
      coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
      coef(7) = & G12;
      // opération de transmission de la métrique
      const Met_abstraite::Impli* ex_impli = NULL;
      const Met_abstraite::Expli_t_tdt* ex_expli_tdt = &ex;
      const Met_abstraite::Umat_cont* ex_expli = NULL;

      // on passe en revue les fonctions nD
      for (int i=1;i< 8;i++)
       {if (fct_para(i) != NULL)
         { Fonction_nD* pt_fonct = fct_para(i); // pour simplifier
           
           // on utilise la méthode générique de loi abstraite
           Tableau <double> & tab_val = Loi_comp_abstraite::Loi_comp_Valeur_FnD_Evoluee
               (pt_fonct,1 // une seule valeur attendue en retour
                ,ex_impli,ex_expli_tdt,ex_expli
                ,NULL
                ,NULL
                ,NULL
               );

         
/*           // ici on utilise les variables connues aux pti, ou calculées à partir de
           // on commence par récupérer les conteneurs des grandeurs à fournir
           List_io <Ddl_enum_etendu>& li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
           List_io <TypeQuelconque >& li_quelc = pt_fonct->Li_equi_Quel_evolue();
           bool absolue = true; // on se place systématiquement en absolu
           // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer
           // pour les grandeurs strictement scalaire
            Tableau <double> val_ddl_enum(Valeur_multi_interpoler_ou_calculer
                        (absolue,TEMPS_tdt,li_enu_scal,ex_impli,ex_expli_tdt,ex_expli,NULL)
                                          );
           // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer
           // pour les Coordonnees et Tenseur
           Valeurs_Tensorielles_interpoler_ou_calculer
                         (absolue,TEMPS_tdt,li_quelc,ex_impli,ex_expli_tdt,ex_expli,NULL);
           // calcul de la valeur et retour dans tab_ret
           Tableau <double> & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
           #ifdef MISE_AU_POINT
           if (tab_val.Taille() != 1)
              { cout << "\nErreur : la fonction nD relative au parametre materiau " << i
                     << " doit calculer un scalaire or le tableau de retour est de taille "
                     << tab_val.Taille() << " ce n'est pas normal !\n";
                cout << " Loi_ortho2D_C_entrainee::Calcul_SigmaHH\n";
                Sortie(1);
              };
           #endif
*/
           // on récupère le premier élément du tableau uniquement
           (*coef(i)) = tab_val(1);
         };
       };
     };
    // puis fabrication de la matrice inv_loi
    {// on commence par remplir la matrice
     inv_loi(1,1) = 1./E1;inv_loi(2,2) = 1./E2;
     inv_loi(1,2) = inv_loi(2,1) = -nu12/E1;
     inv_loi = inv_loi.Inverse(); // on inverse la matrice
    };
    // on vérifie éventuellement la convexité
    if (verification_convexite)
        Verif_convexite();

    // calcul des contraintes dans le repère O_p
    Vecteur eps_ii(2);Vecteur sig_ii(2);
    for (int i=1; i<3;i++)
      eps_ii(i) = eps_p_HH(i,i);
    sig_ii = inv_loi * eps_ii;
//    Tenseur2HH sig_HH;
    for (int i=1; i<3;i++)
      {sigHH.Coor(i,i) = sig_ii(i);
      };
    sigHH.Coor(1,2) = 2.* G12 * eps_p_HH(1,2);
  
    // dans le cas où on veut une sortie des grandeurs on sauvegarde
    if (sortie_post)
     { if (save_resul.eps_loc_HH == NULL)
         {save_resul.eps_loc_HH = NevezTenseurHH(2);
          save_resul.sig_loc_HH = NevezTenseurHH(2);
          save_resul.para_loi = new Vecteur (7);
         };
       (*save_resul.eps_loc_HH) = eps_p_HH;
       (*save_resul.sig_loc_HH) = sigHH;
       // paramètres de la loi
       (*save_resul.para_loi)(1) = E1; (*save_resul.para_loi)(2) =  E2;
       (*save_resul.para_loi)(3) = E3;
       (*save_resul.para_loi)(4) =  nu12; (*save_resul.para_loi)(5) =  nu13;
       (*save_resul.para_loi)(6) =  nu23;
       (*save_resul.para_loi)(7) =  G12;
     };
 
    // calcul des contraintes dans le repère g_i
    // l'inverse de gamma c'est beta transposée
    sigHH.ChBase(beta_transpose);
//    beta_inv = beta.Inverse();
//    sig_BB.ChBase(beta_inv);
    // passage dans la bonne variance
    Tenseur2BH sigBH = gijBB * sigHH ;
    switch (cas_calcul)
     { case 0: // calcul normal (tous les termes)
        { // on ne fait rien de spécial
          break;
        }
       case 1: // calcul de la partie déviatorique seule
        { double trace_sig = sigBH.Trace();
          sigBH -= (untiers * trace_sig) * IdBH2;
          sigHH -= (untiers * trace_sig) * gijHH;
          break;
        }
       case 2: // calcul de la partie sphérique seule
        { double trace_sig = sigBH.Trace();
          sigBH = (untiers * trace_sig) * IdBH2;
          sigHH = (untiers * trace_sig) * gijHH;
          break;
        }
       default:
        { cout << "\n erreur l'indicateur cas_calcul= " << cas_calcul << " n'a pas une valeur correcte !! "
               << "\n Loi_ortho2D_C_entrainee::Calcul_SigmaHH (.... ";
          Sortie(1);
        }
     };
    #ifdef MISE_AU_POINT
    if (affichage)
       { cout << "\n epsBB="<<epsBB << " gijBB_tdt= " << gijBB << " gijHH_tdt= " << gijHH<<" ";
         cout << "\n sighh="<<sigHH<<" "<< flush ;
       };
    #endif

    // calcul de la déformation d'épaisseur
    //\varepsilon_{33} = -\frac{1}{1 - \nu_{12}.\nu_{21}}\left[ (\nu_{13} + \nu_{23}.\nu_{12})~\varepsilon_{11} + (\nu_{23} + \nu_{13}.\nu_{21})  ~\varepsilon_{22}\right]

    double nu21 = nu12*E2/E1;
    save_resul.eps33 = -1/(1.-nu12*nu21)*(
                           epsBH(1,1)*(nu12*nu23 + nu13)+epsBH(2,2)*(nu23+nu13*nu21)
                                         );

    // traitement des énergies
    energ.Inita(0.); 
    energ.ChangeEnergieElastique(0.5 * (sigHH && epsBB));
    // -- calcul des modules
    // on n'utilise plus la forme linéaire, mais à la place la variation relative de volume
    // constaté, au sens d'une mesure logarithmique, sauf dans le cas où cette variation est trop petite
    double var_surf = (*(ex.jacobien_tdt))/(*(ex.jacobien_0)); // la variation de surface
    // on cherche à intégrer la variation d'épaisseur calculée avec eps33
    double var_epai = 0.; // init
    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)= 1/2 * (1. - 1./(var_epai)^2), en orthonormee
              var_epai = sqrt(1./(1.-2.* save_resul.eps33));
           };
           break;
      case DEFORMATION_LOGARITHMIQUE : case DEF_CUMUL_CORROTATIONNEL : case DEFORMATION_CUMU_LOGARITHMIQUE :
          // cas d'une def logarithmique ou une approximation
           {  // eps_33 = log(var_epai);
              var_epai = exp(save_resul.eps33);
           };
           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_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (... \n";
        Sortie(1);
     };
    //  calcul de la valeur de la variation relative de volume en log
    double log_var_vol = log((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai);
    // pour le module de compressibilité, choix entre les différents cas
    if ((cas_calcul == 0) || (cas_calcul == 2))
     {if (log_var_vol > ConstMath::petit)
        {module_compressibilite = untiers * sigBH.Trace() / (log_var_vol);}
      else // si la variation de volume est trop faible on passe par la moyenne
           // des compressibilités dans les 2 directions d'orthotropie (cf. théorie)
        {double unsurKs1 = 1./E1 - nu12/E1 -nu13/E1;
         double unsurKs2 = -nu12/E1+1./E2-nu23/E2;
         double unsurKs3 = -nu13/E1-nu23/E2+1./E3;
         module_compressibilite = untiers * untiers * (1./unsurKs1+1./unsurKs2+1./unsurKs3);
        };
     }
    else
     // dans le cas d'une loi purement déviatorique, le module de compressibilité = 0 (approximativement)
     {module_compressibilite = 0.;};
    #ifdef MISE_AU_POINT
    if (Permet_affichage() > 4)
       { cout << "\n var_vol="<<((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai)
              << " log_var_vol= " << log_var_vol
              << " sigBH.Trace()= " << sigBH.Trace()
              << " module_compressibilite= " << module_compressibilite
              << flush ;
        if  (Permet_affichage() > 5) cout << "\n cas_calcul= " << cas_calcul;
       };
    #endif
    // pour la partie cisaillement on garde la forme associée à la loi
    if ((cas_calcul == 0) || (cas_calcul == 1))
      {module_cisaillement = 2. * (G12);}
    else
      // en purement sphérique, le module est supposé nul
      {module_cisaillement = 0.; };

    LibereTenseur();   
 };
        
        // calcul des contraintes a t+dt et de ses variations  
// void 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,Tableau <TenseurHH *>& d_sigHH
//     ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
//     ,const Met_abstraite::Impli& ex);
void Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (TenseurHH& ,TenseurBB& ,DdlElement & tab_ddl
         ,BaseB& ,TenseurBB & ,TenseurHH &
         ,BaseB& ,Tableau <BaseB> & ,BaseH& ,Tableau <BaseH> &
         ,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& ,double&
		  	    ,Vecteur& ,TenseurHH& sigHH_tdt,Tableau <TenseurHH *>& d_sigHH
		  	    ,EnergieMeca & energ,const EnergieMeca &
		  	    ,double& module_compressibilite,double&  module_cisaillement
		  	    ,const Met_abstraite::Impli& ex)
 {
    #ifdef MISE_AU_POINT
    if (epsBB_tdt.Dimension() != 2)
      { cout << "\nErreur : la dimension devrait etre 2 !\n";
        cout << " Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt\n";
        Sortie(1);
      };
    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_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt\n";
        Sortie(1);
      };
    #endif
    
    bool affichage = (Permet_affichage() > 5);
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n  --- loi de comportement orthotrope entrainee --- ";
     };
    #endif
    const Tenseur2BB & epsBB = *((Tenseur2BB*) &epsBB_tdt); // passage en dim 2
    const Tenseur2HH & gijHH = *((Tenseur2HH*) &gijHH_tdt); //   "      "  "  "
    Tenseur2HH & sigHH = *((Tenseur2HH*) &sigHH_tdt);  //   "      "  "  "
    const Tenseur2BB & gijBB = *((Tenseur2BB*) &gijBB_tdt); //   "      "  "  "

    Tenseur2BH  epsBH = epsBB * gijHH;  // deformation en mixte
    Tenseur2HH  epsHH = gijHH * epsBH; // en deuxfois contra
    int dim = ParaGlob::Dimension(); // pour les affichages de vecteurs

    // récup du conteneur spécifique
    SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveResul);
    // on commence par calculer le repère d'orthotropie transporté
    // Op_H_i sont les coordonnées contravariantes de la nouvelle base
    // donc par rapport à g_i,
    BaseH& Op_H = save_resul.Op_H;
    Tableau <double> tab_norme(2);
    if (type_transport == 0)
      // transport de type contravariant
     { // on calcule les coordonnées de la base O' dans la base naturelle
      #ifdef MISE_AU_POINT
      if (save_resul.O_H == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt\n";
         Sortie(1);
        };
      #endif
      BaseH& O_H = (*save_resul.O_H); // coordonnées en absolu de la base d'orthotropie
      // calcul des coordonnées alpha_a^{.i} = O_H(a) * g^i  à t= 0
      for (int a = 1;a < 3; a++)
        {CoordonneeH& inter = alpha_H.CoordoH(a);
         for (int i=1;i < 3;i++)
           inter(i)= O_H(a).ScalHH((*ex.giH_0)(i));
        };

      // calcule des beta_a^{.i} tel que O'_a = beta_a^{.i} \hat{g}_i   donc au temps t+dt
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         // Op_H(a) non normé a les mêmes coordonnées alpha_a^{.j}
         // mais exprimés dans le repère actuel \hat \vec g_j
         CoordonneeH& Op_H_a = Op_H.CoordoH(a); // pour simplifier
         Op_H_a = alpha_H(a);
         // calcul de la norme du vecteur Op_H_a
         double norme = sqrt(Op_H_a * gijBB * Op_H_a);
         tab_norme(a) = norme;
         // coordonnées finales
         Op_H_a /= norme;
         #ifdef MISE_AU_POINT
         if (affichage)
           {cout << "\n  Op_H("<<a<<"): ";
            Op_H_a.Affiche();
            cout << "\n  alpha_H("<<a<<"): ";
            alpha_H(a).Affiche();
            cout << "\n giB_tdt"; (*ex.giB_tdt)(a).Affiche();
            // affichage du repère tournée
            CoordonneeB V(dim);
            for (int j=1;j<= 2;j++) V +=  (*ex.giB_tdt)(j) * Op_H_a(j);
            cout << "\n op_H("<<a<<"):  en absolu " << V ;
           };
         #endif
       };
     }
    else
      // transport de type covariant
     { // on calcule les coordonnées de la base O' dans la base duale
      #ifdef MISE_AU_POINT
      if (save_resul.O_B == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt\n";
         Sortie(1);
        };
      #endif
      BaseB& O_B = (*save_resul.O_B); // pour simplifier
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         CoordonneeB& Op_B_a = Op_B.CoordoB(a);
         // calcul de la norme du vecteur Op_B_a
         double norme = sqrt(Op_B_a * gijHH * Op_B_a);
         tab_norme(a) = norme;
         // coordonnées finales
         Op_B_a /= norme;
       };
      // maintenant on calcule la base Op_H correspondante
      for (int i=1; i<3;i++)
         Op_H.CoordoH(i) = Op_B.CoordoB(i) * gijHH;
     };
    // on calcul la matrice de passage de la base g_i vers la base O'_i
    // O'_i = beta_i^{.j} * g_j
    // et on a également \hat{\vec g}^i = {\beta}_{a}^{.i}~\hat{\vec O'}^a
    // comme O'_i est déjà exprimé dans g_j, ses coordonnées sont directement béta
    for (int i=1; i<3;i++)
      for (int j=1; j<3;j++)
         { beta(i,j) = Op_H(i)(j);};
    // puis on calcul les coordonnées de la base duale
    beta_transpose = beta.Transpose();
    gamma = beta_transpose.Inverse();
    gamma_transpose = gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
      {cout << "\n beta: ";beta.Affiche();
       cout << "\n beta_transpose: ";beta_transpose.Affiche();
       cout << "\n gamma: ";gamma.Affiche();
       cout << "\n gamma_transpose: ";gamma_transpose.Affiche();
      };
    #endif

    // changement de base (cf. théorie) : la matrice beta est telle que:
    // gpB(i) = beta(i,j) * gB(j) <==> gp_i = beta_i^j * g_j

    // calcul des coordonnées de la déformation dans le repère O'_i
    #ifdef MISE_AU_POINT
    if (affichage)
     {//    Tenseur2BB  eps_p_BB(epsBB);
      cout <<"\n eps_p_BB en g^i: "; epsBB.Ecriture(cout);
      Tenseur2BB tiutiu;
      epsBB.BaseAbsolue(tiutiu,*(ex.giH_tdt));
      cout << "\n eps en absolu :";tiutiu.Ecriture(cout);
     };
    #endif
    // il faut passer en 2 fois contravariant
    Tenseur2HH eps_p_HH(epsHH); // init
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout <<"\n eps_p_HH en g_i: "; eps_p_HH.Ecriture(cout);
     };
    #endif
    eps_p_HH.ChBase(gamma); // res = (gamma * res) * gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
      { cout <<"\n eps_p_HH: "; eps_p_HH.Ecriture(cout);
        TenseurHH*  toto = NevezTenseurHH(eps_p_HH);
        toto->ChBase(beta_transpose);
        cout << "\n retour dans la base g^i de eps^{ij} :";toto->Ecriture(cout);
        TenseurBB*  titi = NevezTenseurBB(gijBB * (*toto) * gijBB);
        cout << "\n def eps_ij :";titi->Ecriture(cout);
        delete toto; delete titi;
      };
    #endif

    double untiers = 1./3.;

    // dans le cas de fonctions nD récupération des valeurs
    if (!null_fct_para)
//  Tableau <Fonction_nD* > fct_para; // fonction nD éventuelle d'évolution des paramètres
     {// un tableau de travail pour les valeurs sous forme indicée
      Tableau < double * > coef(7);
      coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
      coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
      coef(7) = & G12;
      // opération de transmission de la métrique
      const Met_abstraite::Impli* ex_impli = &ex;
      const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL;
      const Met_abstraite::Umat_cont* ex_expli = NULL;

      // on passe en revue les fonctions nD
      for (int i=1;i<8;i++)
       {if (fct_para(i) != NULL)
         { Fonction_nD* pt_fonct = fct_para(i); // pour simplifier
           
           // on utilise la méthode générique de loi abstraite
           Tableau <double> & tab_val = Loi_comp_abstraite::Loi_comp_Valeur_FnD_Evoluee
               (pt_fonct,1 // une seule valeur attendue en retour
                ,ex_impli,ex_expli_tdt,ex_expli
                ,NULL
                ,NULL
                ,NULL
               );

         
/*           // ici on utilise les variables connues aux pti, ou calculées à partir de
           // on commence par récupérer les conteneurs des grandeurs à fournir
           List_io <Ddl_enum_etendu>& li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
           List_io <TypeQuelconque >& li_quelc = pt_fonct->Li_equi_Quel_evolue();
           bool absolue = true; // on se place systématiquement en absolu
           // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer
           // pour les grandeurs strictement scalaire
            Tableau <double> val_ddl_enum(Valeur_multi_interpoler_ou_calculer
                        (absolue,TEMPS_tdt,li_enu_scal,ex_impli,ex_expli_tdt,ex_expli,NULL)
                                          );
           // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer
           // pour les Coordonnees et Tenseur
           Valeurs_Tensorielles_interpoler_ou_calculer
                         (absolue,TEMPS_tdt,li_quelc,ex_impli,ex_expli_tdt,ex_expli,NULL);
           // calcul de la valeur et retour dans tab_ret
           Tableau <double> & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
           #ifdef MISE_AU_POINT
           if (tab_val.Taille() != 1)
              { cout << "\nErreur : la fonction nD relative au parametre materiau " << i
                     << " doit calculer un scalaire or le tableau de retour est de taille "
                     << tab_val.Taille() << " ce n'est pas normal !\n";
                cout << " Loi_ortho2D_C_entrainee::Calcul_DsigmaHH\n";
                Sortie(1);
              };
           #endif
*/
           // on récupère le premier élément du tableau uniquement
           (*coef(i)) = tab_val(1);
         };
       };
     };
    // puis fabrication de la matrice inv_loi
    {// on commence par remplir la matrice
     inv_loi(1,1) = 1./E1;inv_loi(2,2) = 1./E2;
     inv_loi(1,2) = inv_loi(2,1) = -nu12/E1;
     inv_loi = inv_loi.Inverse(); // on inverse la matrice
    };
    // on vérifie éventuellement la convexité
    if (verification_convexite)
        Verif_convexite();

    // calcul des contraintes dans le repère O_p
    Vecteur eps_ii(2);Vecteur sig_ii(2);
    for (int i=1; i<3;i++)
      eps_ii(i) = eps_p_HH(i,i);
    sig_ii = inv_loi * eps_ii;

    for (int i=1; i<3;i++)
      {sigHH.Coor(i,i) = sig_ii(i);
      };
    sigHH.Coor(1,2) = 2.* G12 * eps_p_HH(1,2);

    // dans le cas où on veut une sortie des grandeurs on sauvegarde
    if (sortie_post)
     { if (save_resul.eps_loc_HH == NULL)
         {save_resul.eps_loc_HH = NevezTenseurHH(2);
          save_resul.sig_loc_HH = NevezTenseurHH(2);
          save_resul.para_loi = new Vecteur (7);
         };
       (*save_resul.eps_loc_HH) = eps_p_HH;
       (*save_resul.sig_loc_HH) = sigHH;
       // paramètres de la loi
       (*save_resul.para_loi)(1) = E1; (*save_resul.para_loi)(2) =  E2;
       (*save_resul.para_loi)(3) = E3;
       (*save_resul.para_loi)(4) =  nu12; (*save_resul.para_loi)(5) =  nu13;
       (*save_resul.para_loi)(6) =  nu23;
       (*save_resul.para_loi)(7) =  G12;
      };
  
    // calcul des contraintes dans le repère g_i
    // l'inverse de gamma c'est beta transposée
    sigHH.ChBase(beta_transpose);
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n sig_ijHH complet :";sigHH.Ecriture(cout);
      Tenseur2HH tutu;
      sigHH.BaseAbsolue(tutu,*(ex.giB_tdt));
      cout << "\n sig en absolu :";tutu.Ecriture(cout);
     };
    #endif
    // passage dans la bonne variance
    Tenseur2BH sigBH = gijBB * sigHH ;
    switch (cas_calcul)
     { case 0: // calcul normal (tous les termes)
        { // on ne fait rien de spécial
          break;
        }
       case 1: // calcul de la partie déviatorique seule
        { double trace_sig = sigBH.Trace();
          sigBH -= (untiers * trace_sig) * IdBH2;
          sigHH -= (untiers * trace_sig) * gijHH;
          break;
        }
       case 2: // calcul de la partie sphérique seule
        { double trace_sig = sigBH.Trace();
          sigBH = (untiers * trace_sig) * IdBH2;
          sigHH = (untiers * trace_sig) * gijHH;
          break;
        }
       default:
        { cout << "\n erreur l'indicateur cas_calcul= " << cas_calcul << " n'a pas une valeur correcte !! "
               << "\n Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (.... ";
          Sortie(1);
        }
     };
    #ifdef MISE_AU_POINT
    if (affichage)
       { cout << "\n epsBB="<<epsBB << " gijBB_tdt= " << gijBB << " gijHH_tdt= " << gijHH<<" ";
         cout << "\n sighh="<<sigHH<<" "<< flush ;
       };
    #endif

    // calcul de la déformation d'épaisseur
    //\varepsilon_{33} = -\frac{1}{1 - \nu_{12}.\nu_{21}}\left[ (\nu_{13} + \nu_{23}.\nu_{12})~\varepsilon_{11} + (\nu_{23} + \nu_{13}.\nu_{21})  ~\varepsilon_{22}\right]

    double nu21 = nu12*E2/E1;
    save_resul.eps33 = -1/(1.-nu12*nu21)*(
                           epsBH(1,1)*(nu12*nu23 + nu13)+epsBH(2,2)*(nu23+nu13*nu21)
                                         );

    // traitement des énergies
    energ.Inita(0.);
    energ.ChangeEnergieElastique(0.5 * (sigHH && epsBB));
    // -- calcul des modules
    // on n'utilise plus la forme linéaire, mais à la place la variation relative de volume
    // constaté, au sens d'une mesure logarithmique, sauf dans le cas où cette variation est trop petite
    double var_surf = (*(ex.jacobien_tdt))/(*(ex.jacobien_0)); // la variation de surface
    // on cherche à intégrer la variation d'épaisseur calculée avec eps33
    double var_epai = 0.; // init
    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)= 1/2 * (1. - 1./(var_epai)^2), en orthonormee
              var_epai = sqrt(1./(1.-2.* save_resul.eps33));
           };
           break;
      case DEFORMATION_LOGARITHMIQUE : case DEF_CUMUL_CORROTATIONNEL : case DEFORMATION_CUMU_LOGARITHMIQUE :
          // cas d'une def logarithmique ou une approximation
           {  // eps_33 = log(var_epai);
              var_epai = exp(save_resul.eps33);
           };
           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_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (... \n";
        Sortie(1);
     };
    //  calcul de la valeur de la variation relative de volume en log
    double log_var_vol = log((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai);

    // pour le module de compressibilité, choix entre les différents cas
    if ((cas_calcul == 0) || (cas_calcul == 2))
     {
      if (log_var_vol > ConstMath::petit)
        {  module_compressibilite = untiers * sigBH.Trace() / (log_var_vol);
//         module_compressibilite = untiers * sigBH.Trace() /
//            (1.- 1./((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai));
        
        }
      else // si la variation de volume est trop faible on passe par la moyenne
           // des compressibilités dans les 3 directions d'orthotropie (cf. théorie)
        {double unsurKs1 = 1./E1 - nu12/E1 -nu13/E1;
         double unsurKs2 = -nu12/E1+1./E2-nu23/E2;
         double unsurKs3 = -nu13/E1-nu23/E2+1./E3;
         module_compressibilite = untiers * untiers * (1./unsurKs1+1./unsurKs2+1./unsurKs3);
        };
     }
    else
     // dans le cas d'une loi purement déviatorique, le module de compressibilité = 0 (approximativement)
     {module_compressibilite = 0.;};
     
    #ifdef MISE_AU_POINT
    if (Permet_affichage() > 4)
       { cout << "\n eps33= " << save_resul.eps33
              << " var_epai= " << var_epai
              << " var_surf= " << var_surf
              << "\n var_vol="<<((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai)
              << " log_var_vol= " << log_var_vol
              << " sigBH.Trace()= " << sigBH.Trace()
              << " module_compressibilite= " << module_compressibilite
              << flush ;
       };
    #endif
    // pour la partie cisaillement on garde la forme associée à la loi
    // on prend la moyenne des 3
    if ((cas_calcul == 0) || (cas_calcul == 1))
      {module_cisaillement = 2. * (G12);}
    else
      // en purement sphérique, le module est supposé nul
      {module_cisaillement = 0.; };
  
    // cas le la variation du tenseur des contraintes
    int nbddl = d_gijBB_tdt.Taille();
  
    // des tenseurs de travail
    Tenseur2BH d_sigBH; Tenseur2HH d_sig_HH;
    Tenseur2HH  d_epsHH;Mat_pleine mat_d_epsHH(2,2);
    Vecteur d_eps_ii(2);Vecteur d_sig_ii(2);
    Mat_pleine  d_beta(2,2);Mat_pleine  d_beta_inv(2,2);
    Mat_pleine  d_beta_transpose(2,2);
    Mat_pleine d_gamma(2,2);
    Mat_pleine mat_d_eps_p_HH(2,2);
    // on récupère la matrice des composantes de déformation dans O_p_a
    Mat_pleine mat_epsHH(2,2);epsHH.Matrice_composante(mat_epsHH);
//cout << "\n mat_epsHH: ";mat_epsHH.Affiche();
    for (int i = 1; i<= nbddl; i++)
     { // on fait uniquement une égalité d'adresse et de ne pas utiliser
       // le constructeur d'ou la profusion d'* et de ()
       Tenseur2HH & dsigHH = *((Tenseur2HH*) (d_sigHH(i)));  // passage en dim 2
       const Tenseur2HH & dgijHH = *((Tenseur2HH*)(d_gijHH_tdt(i))) ; // pour simplifier l'ecriture
       const Tenseur2BB & dgijBB = *((Tenseur2BB*)(d_gijBB_tdt(i))) ; // pour simplifier l'ecriture
       const Tenseur2BB & depsBB = *((Tenseur2BB *) (d_epsBB(i))); //    "
      
       //Tableau <BaseB> * d_giB_tdt
       BaseB & d_giB = (*ex.d_giB_tdt)(i);
       BaseH & d_giH = (*ex.d_giH_tdt)(i);

       // pour chacun des ddl on calcul les tenseurs derivees
       Tenseur2BH depsBH =  epsBB * dgijHH  + depsBB * gijHH ;
//cout <<"\n depsBH: "; depsBH.Ecriture(cout);
      
/*       // calcul des variations du repère O'_i
       // en fait il s'agit des variations des beta_a^{.j}
       if (type_transport == 0)
         // transport de type contravariant
        { // on calcule les coordonnées de la base O' dans la base naturelle
         BaseH& O_H = (*save_resul.O_H); // pour simplifier
         for (int a=1; a<3;a++)
          { // calcul des variations du vecteur non normé
            CoordonneeH d_pO_H_i(3);
            d_pO_H_i.Zero();
            // on a: Op_H(a) non normé = alpha_a^{.k} * \hat \vec g_k
            // d'où : d_Op_H(a) non normé = alpha_a^{.k} * d(\hat \vec g_k)
            for (int k=1; k<3;k++)
              {const CoordonneeB& d_giB_k = d_giB(k);
               // on change la variance car, celle-ci en fait dépend de la base
               // et non de gi_B, mais ici on utilise la base sous forme d'un scalaire
               // O_H(a)(k) et la variance est donnée par d_inter...
               CoordonneeH d_inter(3);
               d_inter.ConstructionAPartirDe_B(d_giB_k);
               d_pO_H_i += O_H(a)(k) * d_inter;
              };
            // calcul de la variation du vecteur unitaire connaissant la variation du
            // vecteur non unitaire et la norme
//            d_Op_H.CoordoH(a) = Util::VarUnVect_coorH(pO_B.CoordoB(a),d_pO_H_i,tab_norme(a));
          };
        }
       else
         // transport de type covariant
        { // on calcule les coordonnées de la base O' dans la base duale
         BaseB& O_B = (*save_resul.O_B); // pour simplifier
         for (int iloc=1; iloc<3;iloc++)
          { // tout d'abord la base non normalisée
            CoordonneeH& d_pO_H_i = d_Op_H.CoordoH(iloc);
            d_pO_H_i.Zero();
            for (int k=1; k<3;k++)
              {CoordonneeH d_giH_k = d_giH(k);
               d_pO_H_i += O_B(i)(k) * d_giH_k;
              };
            // calcul de la variation du vecteur unitaire connaissant la variation du
            // vecteur non unitaire et la norme
            CoordonneeH interH = Util::VarUnVect_coorH(pO_H.CoordoH(iloc),d_pO_H_i,tab_norme(iloc));
          };
         // maintenant on calcule la base d_Op_B correspondante
         for (int i=1; i<3;i++)
            d_Op_B.CoordoB(i) = d_Op_H.CoordoH(i) * gijBB + Op_H.CoordoH(i) * dgijBB;
        };
*/

       // on calcul la variation de matrice de passage de la base g_i vers la base O'_a
       // O'_a = beta_a^{.i} * g_i
       if (type_transport == 0)
        // transport de type contravariant
         {for (int a=1; a<3;a++)
           {const CoordonneeH& alpha_H_a = alpha_H.CoordoH(a);
            // on calcul d'abord le produit alpha_a^l * alpha_a^m * d_g_ij(l,m)
            double inter = 0.;
            for (int l =1;l<3;l++)
             for (int m =1;m<3;m++)
               inter += alpha_H_a(l) * alpha_H_a(m) * dgijBB(l,m);
            for (int i=1; i<3;i++)
             {double & d_beta_ai = d_beta(a,i); // pour simplifier
              // ajout des termes or boucle
              d_beta_ai *= - 0.5 * alpha_H_a(i) * inter / PUISSN(tab_norme(a), 3);
             };
           };
        // on calcule ensuite la variation de gamma
        d_beta_transpose = d_beta.Transpose();
//cout << "\n gamma: ";gamma.Affiche();
//        d_gamma = (gamma * d_beta_transpose);
        d_gamma = - gamma * d_beta_transpose * gamma;
        #ifdef MISE_AU_POINT
        if (affichage)
         {cout << "\n d_beta: ";d_beta.Affiche();
          cout << "\n d_beta_transpose: ";d_beta_transpose.Affiche();
          cout << "\n d_gamma: ";d_gamma.Affiche();
          d_gamma = -d_gamma;
          cout << "\n d_gamma: ";d_gamma.Affiche();
         };
        #endif
        }
       else
        {cout << "\n **** cas en attente "
              << "\n Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (.... "<< endl;
         Sortie(1);
        };
       // calcul des coordonnées de la variation de déformation dans le repère O'_i
       // -- 1) en coordonnees contravariantes tout d'abord variations dans g_i
       // epsHH =  gijHH * epsBB * gijHH dans g_i
       d_epsHH  = dgijHH * epsBB * gijHH + gijHH * depsBB * gijHH
                     + gijHH * epsBB * dgijHH;
//cout <<"\n d_epsHH: "; d_epsHH.Ecriture(cout);

       // -- maintenant on s'occupe du changement de base
       // les beta et gamma sont des matrices et non des tenseurs ... on transforme localement
       // en matrice
       d_epsHH.Matrice_composante(mat_d_epsHH);
       // -- calcul final de la variation  de déformation dans le repère O'_i
       // rappel du changement de base : res = (gamma * res) * gamma.Transpose();
//cout << "\n d_gamma: ";d_gamma.Affiche();

       mat_d_eps_p_HH = (d_gamma * mat_epsHH * gamma_transpose)
                        + (gamma * mat_d_epsHH * gamma_transpose)
                        + gamma * mat_epsHH * d_gamma.Transpose();
//cout << "\n mat_d_eps_p_HH: ";mat_d_eps_p_HH.Affiche();


       // -- 2) calcul de la variation des contraintes dans le repère O_p
       for (int i=1; i<3;i++)
         d_eps_ii(i) = mat_d_eps_p_HH(i,i); // les def de la diagonale
       d_sig_ii = inv_loi * d_eps_ii; // les contraintes en ii
      
       for (int i=1; i<3;i++)
         {dsigHH.Coor(i,i) = d_sig_ii(i); // affectation des contraintes en ii
         };
       // puis les contraintes en cisaillement
       dsigHH.Coor(1,2) = 2.* G12 * mat_d_eps_p_HH(1,2);
//cout <<"\n dsigHH en O_p : "; dsigHH.Ecriture(cout);

       // -- 3) calcul de la variation des contraintes dans le repère g_i
       // c'est l'opération inverse et beta_transpose joue le rôle de gamma dans l'autre sens
       sigHH.Var_tenseur_dans_nouvelle_base(beta_transpose,dsigHH,d_beta_transpose);
//cout <<"\n dsigHH en gi : "; dsigHH.Ecriture(cout);
       double untiers = 1./3.;
       switch (cas_calcul)
        { case 0: // calcul normal (tous les termes)
           { // on ne fait rien de spécial
             break;
           }
          case 1: // calcul de la partie déviatorique seule
           {// passage en mixte pour le calcul de la trace
             d_sigBH = dgijBB * sigHH + gijBB * dsigHH;
             double d_trace_sig = d_sigBH.Trace();
             d_sigBH -= (untiers * d_trace_sig) * IdBH2;
             // passage en deux fois contravariant
             dsigHH = dgijHH * sigBH + gijHH * d_sigBH;
             break;
           }
          case 2: // calcul de la partie sphérique seule
           {// passage en mixte pour le calcul de la trace
             d_sigBH = dgijBB * sigHH + gijBB * dsigHH;
             double d_trace_sig = d_sigBH.Trace();
             d_sigBH = (untiers * d_trace_sig) * IdBH2;
             // passage en deux fois contravariant
             dsigHH = dgijHH * sigBH + gijHH * d_sigBH;
             break;
           }
          default: break;//l'erreur a déjà été traitée dans le calcul de la contrainte
        };
////----------------- debug
//  if ((i==2) || (i==5))
//    {cout << "\n dsighh("<<i<<")="<<dsigHH<<" "
//	       << " dgijHH= " << dgijHH << " depsBB= " << depsBB ;
//	  };
//----------- fin debug        
      };
////----------------- debug
//cout << "\n\n\n"<<endl;Sortie(1);
//----------- fin debug

////debug
//cout << "\n Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt ";
//cout << "\n sigHH: "; sigHH.Ecriture(cout);
//cout << "\n epsBB: "; epsBB.Ecriture(cout);
//     << " epsBH.Trace()= " << Ieps
//     << " sigBH.Trace()= " << sigBH.Trace() << " module_compressibilite= " << module_compressibilite;
////fin debug

    LibereTenseur();        
 };

// void 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,TenseurHHHH& d_sigma_deps
//     ,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
//     ,const Met_abstraite::Umat_cont& ex) ; //= 0;
// calcul des contraintes et ses variations  par rapport aux déformations a t+dt
// en_base_orthonormee:
//   si true:  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, sinon il s'agit de la base orthonormeee fixe
// ex: contient les éléments de métrique relativement au paramétrage matériel = X_(0)^a
void Loi_ortho2D_C_entrainee::Calcul_dsigma_deps (bool en_base_orthonormee, TenseurHH & ,TenseurBB&
            ,TenseurBB & epsBB_tdt,TenseurBB & ,double& ,double& 
		  	       ,TenseurHH& sigHH_tdt,TenseurHHHH& d_sigma_deps_
		  	       ,EnergieMeca & energ,const EnergieMeca &
		  	       ,double& module_compressibilite,double&  module_cisaillement
		  	       ,const Met_abstraite::Umat_cont& ex)
 {
   #ifdef MISE_AU_POINT	 	 
   if (epsBB_tdt.Dimension() != 2)
      { cout << "\nErreur : la dimension devrait etre 2 !\n";
        cout << " Loi_ortho2D_C_entrainee::Calcul_dsigma_deps\n";
        Sortie(1);
      };
   #endif
   
   bool affichage = (Permet_affichage() > 5);
   #ifdef MISE_AU_POINT
   if (affichage)
    {cout << "\n  --- loi de comportement orthotrope entrainee --- ";
    };
   #endif
   
    const Tenseur2HH & gijHH = *((Tenseur2HH*) ex.gijHH_tdt); //   "      "  "  "
    const Tenseur2BB & gijBB = *((Tenseur2BB*) ex.gijBB_tdt); //   "      "  "  "
    const Tenseur2BB & epsBB = *((Tenseur2BB*) &epsBB_tdt); // passage en dim 2
    Tenseur2HH & sigHH = *((Tenseur2HH*) &sigHH_tdt);  //   "      "  "  "
    Tenseur2HHHH& d_sigma_deps = *((Tenseur2HHHH*) &d_sigma_deps_);

    Tenseur2BH  epsBH = epsBB * gijHH;  // deformation en mixte
    Tenseur2HH  epsHH(gijHH * epsBH); // en deuxfois contra
    int dim = ParaGlob::Dimension(); // pour les affichages de vecteurs

  
    // récup du conteneur spécifique
    SaveResulLoi_ortho2D_C_entrainee & save_resul = *((SaveResulLoi_ortho2D_C_entrainee*) saveResul);
    // on commence par calculer le repère d'orthotropie transporté
    // Op_H_i sont les coordonnées contravariantes de la nouvelle base
    // donc par rapport à g_i,
    BaseH& Op_H = save_resul.Op_H;
    Tableau <double> tab_norme(2);
    if (type_transport == 0)
      // transport de type contravariant
     { // on calcule les coordonnées de la base O' dans la base naturelle
      #ifdef MISE_AU_POINT
      if (save_resul.O_H == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_dsigma_deps\n";
         Sortie(1);
        };
      #endif
      BaseH& O_H = (*save_resul.O_H); // coordonnées en absolu de la base d'orthotropie
      // calcul des coordonnées alpha_a^{.i} = O_H(a) * g^i  à t= 0
      for (int a = 1;a < 3; a++)
        {CoordonneeH& inter = alpha_H.CoordoH(a);
         for (int i=1;i < 3;i++)
           inter(i)= O_H(a).ScalHH((*ex.giH_0)(i));
           #ifdef MISE_AU_POINT
           if (affichage)
            {cout << "\n  O_H("<<a<<"): ";O_H(a).Affiche();
             cout << "\n giH_0("<<a<<"): "; (*ex.giH_0)(a).Affiche();
//if ((*ex.giH_0)(a).Norme() < ConstMath::petit)
//   cout << "\n debug lor_ortho pb ";
//             cout << "\n  alpha_H("<<a<<"): ";alpha_H(a).Affiche();
            };            
           #endif
        };

      // calcule des beta_a^{.i} tel que O'_a = beta_a^{.i} \hat{g}_i   donc au temps t+dt
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         // récup du conteneur et affectation des coordonnées initiales
         // Op_H(a) non normé a les mêmes coordonnées alpha_a^{.j}
         // que O_H(a), mais exprimés dans le repère actuel \hat \vec g_j
         CoordonneeH& Op_H_a = Op_H.CoordoH(a); // pour simplifier
         Op_H_a = alpha_H(a);
         // calcul de la norme du vecteur Op_H_a
         double norme = sqrt(Op_H_a * gijBB * Op_H_a);
         tab_norme(a) = norme;
         // coordonnées finales
         Op_H_a /= norme;
         #ifdef MISE_AU_POINT
         if (affichage)
          { cout << "\n  Op_H("<<a<<"): ";
            Op_H_a.Affiche();
            cout << "\n giB_tdt("<<a<<"): "; (*ex.giB_tdt)(a).Affiche();
            cout << "\n giH_tdt("<<a<<"): "; (*ex.giH_tdt)(a).Affiche();
            // affichage du repère tournée
            CoordonneeB V(dim);
            for (int j=1;j<= 2;j++) V +=  (*ex.giB_tdt)(j) * Op_H_a(j);
            cout << "\n op_H("<<a<<"):  en absolu " << V ;
          };
         #endif
       };
     }
    else
      // transport de type covariant
     { // on calcule les coordonnées de la base O' dans la base duale
      #ifdef MISE_AU_POINT
      if (save_resul.O_B == NULL)
        {cout << "\n  *** erreur, le repere d'anisotropie n'est pas defini "
              <<"on ne peut pas continuer " << flush ;
         cout << " Loi_ortho2D_C_entrainee::Calcul_dsigma_deps\n";
         Sortie(1);
        };
      #endif
      BaseB& O_B = (*save_resul.O_B); // pour simplifier
      for (int a=1; a<3;a++)
       { // tout d'abord la base non normalisée
         CoordonneeB& Op_B_a = Op_B.CoordoB(a);
         // calcul de la norme du vecteur Op_B_a
         double norme = sqrt(Op_B_a * gijHH * Op_B_a);
         // coordonnées finales
         Op_B_a /= norme;
       };
      // maintenant on calcule la base Op_H correspondante
      for (int i=1; i<3;i++)
         Op_H.CoordoH(i) = Op_B.CoordoB(i) * gijHH;
     };
    // on calcul la matrice de passage de la base g_i vers la base O'_i
    // O'_i = beta_i^{.j} * g_j
    // et on a également \hat{\vec g}^i = {\beta}_{a}^{.i}~\hat{\vec O'}^a
    // comme O'_i est déjà exprimé dans g_j, ses coordonnées sont directement béta
    for (int i=1; i<3;i++)
      for (int j=1; j<3;j++)
         { beta(i,j) = Op_H(i)(j);};
    // puis on calcul les coordonnées de la base duale
    beta_transpose = beta.Transpose();
    gamma = beta_transpose.Inverse();
    gamma_transpose = gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n beta: ";beta.Affiche();
      cout << "\n beta_transpose: ";beta_transpose.Affiche();
      cout << "\n gamma: ";gamma.Affiche();
      cout << "\n gamma_transpose: ";gamma_transpose.Affiche();
     };
    #endif

    // changement de base (cf. théorie) : la matrice beta est telle que:
    // gpB(i) = beta(i,j) * gB(j) <==> gp_i = beta_i^j * g_j

    // calcul des coordonnées de la déformation dans le repère O'_i
    #ifdef MISE_AU_POINT
    if (affichage)
     {//    Tenseur2BB  eps_p_BB(epsBB);
      cout <<"\n eps_p_BB en g^i: "; epsBB.Ecriture(cout);
      Tenseur2BB tiutiu;
      epsBB.BaseAbsolue(tiutiu,*(ex.giH_tdt));
      cout << "\n eps en absolu :";tiutiu.Ecriture(cout);
     };
    #endif

    // il faut passer en 2 fois contravariant
    Tenseur2HH eps_p_HH(epsHH); // init
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout <<"\n eps_p_HH en g_i: "; eps_p_HH.Ecriture(cout);
     };
    #endif

    eps_p_HH.ChBase(gamma); // res = (gamma * res) * gamma.Transpose();
    #ifdef MISE_AU_POINT
    if (affichage)
      { cout <<"\n eps_p_HH: "; eps_p_HH.Ecriture(cout);
        TenseurHH*  toto = NevezTenseurHH(eps_p_HH);
        toto->ChBase(beta_transpose);
        cout << "\n retour dans la base g^i de eps^{ij} :";toto->Ecriture(cout);
        TenseurBB*  titi = NevezTenseurBB(gijBB * (*toto) * gijBB);
        cout << "\n def eps_ij :";titi->Ecriture(cout);
        delete toto; delete titi;
      };
    #endif

    double untiers = 1./3.;

    // dans le cas de fonctions nD récupération des valeurs
    if (!null_fct_para)
//rappel:  Tableau <Fonction_nD* > fct_para; // fonction nD éventuelle d'évolution des paramètres
     {// un tableau de travail pour les valeurs sous forme indicée
      Tableau < double * > coef(7);
      coef(1) = &E1; coef(2) = & E2;coef(3) = &E3;
      coef(4) = & nu12; coef(5) = & nu13; coef(6) = & nu23;
      coef(7) = & G12;
      // opération de transmission de la métrique
      const Met_abstraite::Impli* ex_impli = NULL;
      const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL;
      const Met_abstraite::Umat_cont* ex_expli = &ex;

      // on passe en revue les fonctions nD
      for (int i=1;i<8;i++)
       {if (fct_para(i) != NULL)
         { Fonction_nD* pt_fonct = fct_para(i); // pour simplifier
           
           // on utilise la méthode générique de loi abstraite
           Tableau <double> & tab_val = Loi_comp_abstraite::Loi_comp_Valeur_FnD_Evoluee
               (pt_fonct,1 // une seule valeur attendue en retour
                ,ex_impli,ex_expli_tdt,ex_expli
                ,NULL
                ,NULL
                ,NULL
               );

         
/*           // ici on utilise les variables connues aux pti, ou calculées à partir de
           // on commence par récupérer les conteneurs des grandeurs à fournir
           List_io <Ddl_enum_etendu>& li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
           List_io <TypeQuelconque >& li_quelc = pt_fonct->Li_equi_Quel_evolue();
           bool absolue = true; // on se place systématiquement en absolu
           // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer
           // pour les grandeurs strictement scalaire
            Tableau <double> val_ddl_enum(Valeur_multi_interpoler_ou_calculer
                        (absolue,TEMPS_tdt,li_enu_scal,ex_impli,ex_expli_tdt,ex_expli,NULL)
                                          );
           // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer
           // pour les Coordonnees et Tenseur
           Valeurs_Tensorielles_interpoler_ou_calculer
                         (absolue,TEMPS_tdt,li_quelc,ex_impli,ex_expli_tdt,ex_expli,NULL);
           // calcul de la valeur et retour dans tab_ret
           Tableau <double> & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
           #ifdef MISE_AU_POINT
           if (tab_val.Taille() != 1)
              { cout << "\nErreur : la fonction nD relative au parametre materiau " << i
                     << " doit calculer un scalaire or le tableau de retour est de taille "
                     << tab_val.Taille() << " ce n'est pas normal !\n";
                cout << " Loi_ortho2D_C_entrainee::Calcul_SigmaHH\n";
                Sortie(1);
              };
           #endif
*/
           // on récupère le premier élément du tableau uniquement
           (*coef(i)) = tab_val(1);
         };
       };
     };
    // puis fabrication de la matrice inv_loi
    {// on commence par remplir la matrice
     inv_loi(1,1) = 1./E1;inv_loi(2,2) = 1./E2;
     inv_loi(1,2) = inv_loi(2,1) = -nu12/E1;
     inv_loi = inv_loi.Inverse(); // on inverse la matrice
    };
    // on vérifie éventuellement la convexité
    if (verification_convexite)
        Verif_convexite();

    // calcul des contraintes dans le repère O_p
    Vecteur eps_ii(2);Vecteur sig_ii(2);
    for (int i=1; i<3;i++)
      eps_ii(i) = eps_p_HH(i,i);
    sig_ii = inv_loi * eps_ii;

    for (int i=1; i<3;i++)
      {sigHH.Coor(i,i) = sig_ii(i);
      };
    sigHH.Coor(1,2) = 2.* G12 * eps_p_HH(1,2);
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n sig_abHH :";sigHH.Ecriture(cout);
     };
    #endif
    Tenseur2HH sig_ab_HH(sigHH);

    // dans le cas où on veut une sortie des grandeurs on sauvegarde
    if (sortie_post)
     { if (save_resul.eps_loc_HH == NULL)
         {save_resul.eps_loc_HH = NevezTenseurHH(2);
          save_resul.sig_loc_HH = NevezTenseurHH(2);
          save_resul.para_loi = new Vecteur (7);
         };
       (*save_resul.eps_loc_HH) = eps_p_HH;
       (*save_resul.sig_loc_HH) = sig_ab_HH;
       // paramètres de la loi
       (*save_resul.para_loi)(1) = E1; (*save_resul.para_loi)(2) =  E2;
       (*save_resul.para_loi)(3) = E3;
       (*save_resul.para_loi)(4) =  nu12; (*save_resul.para_loi)(5) =  nu13;
       (*save_resul.para_loi)(6) =  nu23;
       (*save_resul.para_loi)(7) =  G12;
      };
  
    // calcul des contraintes dans le repère g_i
    // l'inverse de gamma c'est beta transposée
    sigHH.ChBase(beta_transpose);
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n sig_ijHH complet :";sigHH.Ecriture(cout);
      Tenseur2HH tutu;
      sigHH.BaseAbsolue(tutu,*(ex.giB_tdt));
      cout << "\n sig en absolu :";tutu.Ecriture(cout);
     };
    #endif


    // passage dans la variance mixte
    Tenseur2BH sigBH = gijBB * sigHH ;
    switch (cas_calcul)
     { case 0: // calcul normal (tous les termes)
        { // on ne fait rien de spécial
          break;
        }
       case 1: // calcul de la partie déviatorique seule
        { double trace_sig = sigBH.Trace();
          sigBH -= (untiers * trace_sig) * IdBH2;
          sigHH -= (untiers * trace_sig) * gijHH;
          break;
        }
       case 2: // calcul de la partie sphérique seule
        { double trace_sig = sigBH.Trace();
          sigBH = (untiers * trace_sig) * IdBH2;
          sigHH = (untiers * trace_sig) * gijHH;
          break;
        }
       default:
        { cout << "\n erreur l'indicateur cas_calcul= " << cas_calcul << " n'a pas une valeur correcte !! "
               << "\n Loi_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (.... ";
          Sortie(1);
        }
     };
    #ifdef MISE_AU_POINT
    if (affichage)
       { cout << "\n epsBB="<<epsBB << " gijBB_tdt= " << gijBB << " gijHH_tdt= " << gijHH<<" ";
         cout << "\n sighh="<<sigHH<<" "<< flush ;
       };
    #endif

    // calcul de la déformation d'épaisseur
    //\varepsilon_{33} = -\frac{1}{1 - \nu_{12}.\nu_{21}}\left[ (\nu_{13} + \nu_{23}.\nu_{12})~\varepsilon_{11} + (\nu_{23} + \nu_{13}.\nu_{21})  ~\varepsilon_{22}\right]

    double nu21 = nu12*E2/E1;
    save_resul.eps33 = -1/(1.-nu12*nu21)*(
                           epsBH(1,1)*(nu12*nu23 + nu13)+epsBH(2,2)*(nu23+nu13*nu21)
                                         );

    // traitement des énergies
    energ.Inita(0.);
    energ.ChangeEnergieElastique(0.5 * (sigHH && epsBB));
    // -- calcul des modules
    // on n'utilise plus la forme linéaire, mais à la place la variation relative de volume
    // constaté, au sens d'une mesure logarithmique, sauf dans le cas où cette variation est trop petite
    double var_surf = (*(ex.jacobien_tdt))/(*(ex.jacobien_0)); // la variation de surface
    // on cherche à intégrer la variation d'épaisseur calculée avec eps33
    double var_epai = 0.; // init
    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)= 1/2 * (1. - 1./(var_epai)^2), en orthonormee
              var_epai = sqrt(1./(1.-2.* save_resul.eps33));
           };
           break;
      case DEFORMATION_LOGARITHMIQUE : case DEF_CUMUL_CORROTATIONNEL : case DEFORMATION_CUMU_LOGARITHMIQUE :
          // cas d'une def logarithmique ou une approximation
           {  // eps_33 = log(var_epai);
              var_epai = exp(save_resul.eps33);
           };
           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_ortho2D_C_entrainee::Calcul_DsigmaHH_tdt (... \n";
        Sortie(1);
     };
    //  calcul de la valeur de la variation relative de volume en log
    double log_var_vol = log((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai);
    // pour le module de compressibilité, choix entre les différents cas
    if ((cas_calcul == 0) || (cas_calcul == 2))
     {if (log_var_vol > ConstMath::petit)
        {module_compressibilite = untiers * sigBH.Trace() / (log_var_vol);}
      else // si la variation de volume est trop faible on passe par la moyenne
           // des compressibilités dans les 3 directions d'orthotropie (cf. théorie)
        {double unsurKs1 = 1./E1 - nu12/E1 -nu13/E1;
         double unsurKs2 = -nu12/E1+1./E2-nu23/E2;
         double unsurKs3 = -nu13/E1-nu23/E2+1./E3;
         module_compressibilite = untiers * untiers * (1./unsurKs1+1./unsurKs2+1./unsurKs3);
        };
     }
    else
     // dans le cas d'une loi purement déviatorique, le module de compressibilité = 0 (approximativement)
     {module_compressibilite = 0.;
     };
    #ifdef MISE_AU_POINT
    if (Permet_affichage() > 4)
       { cout << "\n var_vol="<<((*(ex.jacobien_tdt))/(*(ex.jacobien_0))*var_epai)
              << " log_var_vol= " << log_var_vol
              << " sigBH.Trace()= " << sigBH.Trace()
              << " module_compressibilite= " << module_compressibilite
              << flush ;
        if  (Permet_affichage() > 5) cout << "\n cas_calcul= " << cas_calcul;
       };
    #endif
    // pour la partie cisaillement on garde la forme associée à la loi
    // on prend la moyenne des 3
    if ((cas_calcul == 0) || (cas_calcul == 1))
      {module_cisaillement = 2. * (G12);}
    else
      // en purement sphérique, le module est supposé nul
      {module_cisaillement = 0.; };
  
    // ----- calcul de l'opérateur tangent -----------
  
    // calcul des variations de sigma / eps dans le repère transporté
    Tenseur2HHBB var_sig_ab_cd_HHBB;
    for (int i=1; i<3;i++)
     for (int j=1; j<3;j++)
       var_sig_ab_cd_HHBB.Change(i,i,j,j,inv_loi(i,j));
    var_sig_ab_cd_HHBB.Change(1,2,1,2,G12); // du coup = (1,2,2,1) = (2,1,1,2) = (2,1,2,1)
  
    #ifdef MISE_AU_POINT
    if (affichage)
     {cout << "\n var_sig_ab_cd_HHBB= ";
      var_sig_ab_cd_HHBB.Affiche_bidim(cout);
     };
    #endif

    // cas de la variation des beta_a^{.i} par rapport aux eps_kl
    // on va les stocker dans un tableau d_beta(a,i) de tenseur HH
    Tableau2 <Tenseur2HH> d_beta_HH(2,2);
    Tableau2 <Tenseur2HH> d_beta_transpose_HH(2,2);
    if (type_transport == 0)
      // transport de type contravariant
     { // on calcule les coordonnées de la base O' dans la base naturelle
      BaseH& O_H = (*save_resul.O_H); // pour simplifier
      for (int a=1;a<3;a++)
       {// calcul de la norme  du vecteur O'_a
        CoordonneeH alpha_H_a = alpha_H(a);
        double n_O_a = tab_norme(a);
        for (int i=1;i<3;i++)
          {d_beta_transpose_HH(i,a)
                     = d_beta_HH(a,i)
                     = -(alpha_H_a(i)
                       /(n_O_a*n_O_a*n_O_a))*Tenseur2HH::Prod_tensoriel(alpha_H_a,alpha_H_a);
          };
       };
     }; // fin du transport 0
     //**** à faire le second transport
  
// vérif d_beta OK
/*{// vérif en différence finie de d_beta
for (int a=1;a<3;a++)
 { CoordonneeH alpha_H_a = alpha_H(a);
//Tenseur2HH toto(Tenseur2HH::Prod_tensoriel(alpha_H_a,alpha_H_a));
//cout << "\n Prod_tensoriel(alpha_H_a,alpha_H_a)= ";
//toto.Ecriture(cout);
//Tenseur2HH titi;
//for (int j=1;j<3;j++)
//  for (int i=1;i<3;i++)
//    titi.Coor(i,j) = alpha_H_a(i) * alpha_H_a(j);
//cout << "\n Prod_tensoriel(alpha_H_a,alpha_H_a) numerique = ";
//titi.Ecriture(cout);
  // calcul de la norme  du vecteur O'_a
  double d_beta_num=0.;
  double n_O_a = tab_norme(a);
  for (int i=1;i<3;i++)
   {d_beta_num = d_beta_HH(a,i) && epsBB;
    cout << "\n delta_beta("<<a<<","<<i<<")= "
         << (beta(a,i)-alpha_H_a(i))<< " num: "<<d_beta_num
         << " beta(a,i)= " << beta(a,i) << " alpha_H_a(i)= " << alpha_H_a(i) ;
   }
}
};
Sortie(1);
*/
  
    // on calcule maintenant la variation de gamma
    Tableau2 <Tenseur2HH> d_gamma_HH(2,2);
    for (int b=1;b<3;b++)
      for (int j=1;j<3;j++)
       {for (int a=1;a<3;a++)
         for (int i=1;i<3;i++)
           d_gamma_HH(b,j) -= (gamma(a,j) * gamma(b,i)) * d_beta_HH(a,i);
       };
  
/*
// vérification numérique de d_gamma
// on a \hat{\vec g}_j =  {\gamma}_{.j}^{b}~\hat{\vec O'}_b
{Mat_pleine gamma_0(2,2);
 Mat_pleine O_p_0_ij(2,2);Mat_pleine O_p_tdt_ij(2,2);
 
for (int a=1;a<3;a++)
 {
 
 CoordonneeH alpha_H_a = alpha_H(a);
//Tenseur2HH toto(Tenseur2HH::Prod_tensoriel(alpha_H_a,alpha_H_a));
//cout << "\n Prod_tensoriel(alpha_H_a,alpha_H_a)= ";
//toto.Ecriture(cout);
//Tenseur2HH titi;
//for (int j=1;j<3;j++)
//  for (int i=1;i<3;i++)
//    titi.Coor(i,j) = alpha_H_a(i) * alpha_H_a(j);
//cout << "\n Prod_tensoriel(alpha_H_a,alpha_H_a) numerique = ";
//titi.Ecriture(cout);
  // calcul de la norme  du vecteur O'_a
  double d_beta_num=0.;
  double n_O_a = tab_norme(a);
  for (int i=1;i<3;i++)
   {d_beta_num = d_beta_HH(a,i) && epsBB;
    cout << "\n delta_beta("<<a<<","<<i<<")= "
         << (beta(a,i)-alpha_H_a(i))<< " num: "<<d_beta_num
         << " beta(a,i)= " << beta(a,i) << " alpha_H_a(i)= " << alpha_H_a(i) ;
   }
}
};
*/

  
    //variation des déformations epsHH / eps_ij dans le repère initial gi
//    Tenseur2HHHH var_eps_nm_kl_HHHH(Tenseur2HHHH::Prod_tensoriel_barre(gijHH,gijHH));
//--//    Tenseur2HHHH var_eps_nm_kl_HHHH(Tenseur2HHHH::Prod_tensoriel_croise(gijHH,gijHH));
//cout << "\n (1) var_eps_nm_kl_HHHH= ";
//var_eps_nm_kl_HHHH.Affiche_bidim(cout);
//{// pour vérification on va calculer par composante
// Tenseur2HHHH deps_nmkl;
// for (int n=1;n<3;n++) for (int m=1;m<3;m++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
//  { double inter=  gijHH(n,k) * gijHH(l,m);
//    deps_nmkl.Change(n,m,k,l,inter);
//  };
// cout << "\n (1) deps_nmkl= calcul en composantes";
// deps_nmkl.Affiche_bidim(cout);
//}
//    Tenseur2HHHH interHHHH1(Tenseur2HHHH::Prod_tensoriel_barre(gijHH,eps_p_HH));
//    Tenseur2HHHH interHHHH2(Tenseur2HHHH::Prod_tensoriel_barre(eps_p_HH,gijHH));
//--//    Tenseur2HHHH interHHHH1(Tenseur2HHHH::Prod_tensoriel_croise(gijHH,eps_HH));
//--//    Tenseur2HHHH interHHHH2(Tenseur2HHHH::Prod_tensoriel_croise(eps_HH,gijHH));
//Tenseur2HHHH interHHHH2(interHHHH1+interHHHH2);
//cout << "\n interHHHH2= ";
//interHHHH2.Affiche_bidim(cout);
//cout << "\n interHHHH1= ";
//interHHHH1.Affiche_bidim(cout);
//cout << "\n interHHHH2= ";
//interHHHH2.Affiche_bidim(cout);
//{Tenseur2HHHH A(interHHHH2);
//A += interHHHH2;
//cout << "\n A= ";A.Affiche_bidim(cout);
//Tenseur2HHHH B(var_eps_nm_kl_HHHH);
//cout << "\n (1) B= ";B.Affiche_bidim(cout);
//B -= 2. * interHHHH2;
//cout << "\n B= ";B.Affiche_bidim(cout);
//
//}
//--//    var_eps_nm_kl_HHHH -= 2. * (interHHHH1+interHHHH2);
    //Tenseur2HHHH::Prod_tensoriel_barre(gijHH,eps_p_HH);
    //(interHHHH1+interHHHH2);
//--//cout << "\n var_eps_nm_kl_HHHH: ";
//--//var_eps_nm_kl_HHHH.Affiche_bidim(cout);

/*
// vérif numérique de la variation
{Tenseur2HH delta_eps = var_eps_nm_kl_HHHH && epsBB;
 cout << "\n delta_eps= "; delta_eps.Ecriture(cout);
Tenseur2HH eps_p_HH(gijHH * epsBB * gijHH);
cout <<"\n eps_p_HH en g_i: "; eps_p_HH.Ecriture(cout);
// vérif var de g^ij
Tenseur2HHHH d_gijHH(Tenseur2HHHH::Prod_tensoriel_croise(gijHH,gijHH));
d_gijHH *= -2.;
Tenseur2HH delta_gijHH(gijHH-(*ex.gijHH_0));
Tenseur2HH delta_gijHH_num = d_gijHH && epsBB;
cout << "\n delta_gijHH= "; delta_gijHH.Ecriture(cout);
cout << "\n delta_gijHH_num (1) "; delta_gijHH_num.Ecriture(cout);
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_gijHH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_gijHH_num.Coor(n,m) += d_gijHH(n,m,i,j)  * epsBB(i,j);
 }
cout << "\n delta_gijHH_num (2)) = "; delta_gijHH_num.Ecriture(cout);
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_gijHH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_gijHH_num.Coor(n,m) += -2.* gijHH(n,i) * gijHH(j,m)  * epsBB(i,j);
 }
cout << "\n delta_gijHH_num (2)) = "; delta_gijHH_num.Ecriture(cout);

Tenseur2HHHH d_gijHH_num;
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 for (int i=1;i<3;i++) for (int j=1;j<3;j++)
     d_gijHH_num.Change(n,m,i,j,(-2.* gijHH(n,i) * gijHH(j,m))) ;


for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 for (int i=1;i<3;i++) for (int j=1;j<3;j++)
   { cout << "\n d_gijHH("<<n <<","<<m<<","<<i<<","<<j<<") et "
          << " -2.* gijHH("<<n<<","<<i<<") * gijHH("<<j<<","<<m<<")= et d_gijHH_num "
          << d_gijHH(n,m,i,j) << " "
          << (-2.* gijHH(n,i) * gijHH(j,m))<< " "
          << d_gijHH_num(n,m,i,j) ;
    }

}
*/

//{Tenseur2HH A(1,2,2,0.,0.,0.);
// Tenseur2HH B(4,5,6,0.,0.,0.);
// Tenseur2HHHH C(Tenseur2HHHH::Prod_tensoriel(A,B));
//cout << "\n C= ";C.Affiche_bidim(cout);
// Tenseur2HHHH C1(Tenseur2HHHH::Prod_tensoriel_barre(A,B));
//cout << "\n Prod_tensoriel_barre(A,B)= ";C1.Affiche_bidim(cout);
// Tenseur2HHHH C2(Tenseur2HHHH::Prod_tensoriel_croise(A,B));
//cout << "\n Prod_tensoriel_croise(A,B)= ";C2.Affiche_bidim(cout);
// Tenseur2HHHH C2(Tenseur2HHHH::Prod_tensoriel_croise_croise(A,B));
//cout << "\n Prod_tensoriel_croise_croise(A,B)= ";C2.Affiche_bidim(cout);
//}

//--//    var_eps_nm_kl_HHHH -= 2. * (interHHHH1+interHHHH2);
  
    // on calcul par composante car il y a des pb de symétrie qui sont difficiles à maîtriser
    // en tensoriel avec un stockage symétrique (il faudra peut-être essayer d'améliorer via les tenseurs
    // généraux) mais cela doit-être cependant assez efficace !
    TenseurQ2geneHHHH deps_nmkl_HHHH;
    {for (int n=1;n<3;n++) for (int m=1;m<3;m++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
       { double inter=  gijHH(n,k) * gijHH(l,m)
                             -2.*(gijHH(n,k) * epsHH(l,m) + epsHH(n,l) * gijHH(m,k));
         deps_nmkl_HHHH.Change(n,m,k,l,inter);
       };
////  vérification du stockage
//cout << "\n deps_nmkl= calcul en composantes";
//for (int n=1;n<3;n++) for (int m=1;m<3;m++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
//   { double inter=  gijHH(n,k) * gijHH(l,m)
//                             -2.*(gijHH(n,k) * epsHH(l,m) + epsHH(n,l) * gijHH(m,k));
//     cout << "\n deps_nmkl("<<n <<","<<m<<","<<k<<","<<l<<") =  et formule directe "
//          << inter <<" " << deps_nmkl_HHHH(n,m,k,l);
//  };
    };

// OK  vérif variation deps_nmkl_HHHH
/*{
Tenseur2HH delta_epsHH_num;
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_epsHH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_epsHH_num.Coor(n,m) += deps_nmkl_HHHH(n,m,i,j)  * epsBB(i,j);
 }
cout << "\n delta_epsHH_num = "; delta_epsHH_num.Ecriture(cout);
cout << "\n epsHH = "; epsHH.Ecriture(cout);
}
Sortie(1);
*/
    //variation des déformations epsHH / eps_ij dans le repère transporté / au eps_kl
    // c'est à dire la variation de eps^ab / eps_kl
//--//    Tenseur2HHHH var_eps_ab_kl_HHHH = Tenseur2HHHH::Var_tenseur_dans_nouvelle_base
//--//                                         (gamma,var_eps_nm_kl_HHHH,d_gamma_HH,eps_p_HH);
//--//cout << "\n var_eps_ab_kl_HHHH= ";
//--//var_eps_ab_kl_HHHH.Affiche_bidim(cout);

    // on calcul par composante car il y a des pb de symétrie qui sont difficiles à maîtriser
    // en tensoriel avec un stockage symétrique (il faudra peut-être essayer d'améliorer via les tenseurs
    // généraux) mais cela doit-être cependant assez efficace !
    TenseurQ2geneHHHH deps_abkl_HHHH;
    {for (int a=1;a<3;a++) for (int b=1;b<3;b++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
      { double inter= 0.;
        for (int n=1;n<3;n++) for (int m=1;m<3;m++)
          inter += d_gamma_HH(a,n)(k,l) *  epsHH(n,m) * gamma(b,m)
                   + gamma(a,n) * deps_nmkl_HHHH(n,m,k,l) * gamma(b,m)
                   + gamma(a,n) * epsHH(n,m) * d_gamma_HH(b,m)(k,l);
        deps_abkl_HHHH.Change(a,b,k,l,inter);
      };
//cout << "\n deps_abkl= calcul en composantes";
//deps_abkl.Affiche_bidim(cout);
    };

// OK  vérif numérique de la variation
/*{
Tenseur2HH delta_eps_ab_HH_num;
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_eps_ab_HH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_eps_ab_HH_num.Coor(n,m) += deps_abkl_HHHH(n,m,i,j)  * epsBB(i,j);
 }
cout << "\n delta_eps_ab_HH_num = "; delta_eps_ab_HH_num.Ecriture(cout);
cout << "\n eps_p_HH = "; eps_p_HH.Ecriture(cout);
Sortie(1);
}
*/
    // variation des contraintes (composantes dans le repère transporté) / au eps_kl
//--//    Tenseur2HHHH var_sig_ab_kl_HHHH = var_sig_ab_cd_HHBB && var_eps_ab_kl_HHHH;
  
    TenseurQ2geneHHHH dsig_abkl_HHHH;
    {// pour vérification on va calculer par composante
     for (int a=1;a<3;a++) for (int b=1;b<3;b++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
      { double inter= 0.;
        for (int n=1;n<3;n++) for (int m=1;m<3;m++)
           inter += var_sig_ab_cd_HHBB(a,b,n,m) * deps_abkl_HHHH(m,n,k,l);
        dsig_abkl_HHHH.Change(a,b,k,l,inter);
      };
//    cout << "\n dsig_abkl= calcul en composantes";
//    dsig_abkl.Affiche_bidim(cout);
    };

//cout << "\n var_sig_ab_kl_HHHH= ";
//var_sig_ab_kl_HHHH.Affiche_bidim(cout);

// OK  vérif numérique de la variation
/*{
Tenseur2HH delta_sigma_ab_HH_num;
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_sigma_ab_HH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_sigma_ab_HH_num.Coor(n,m) += dsig_abkl_HHHH(n,m,i,j)  * epsBB(i,j);
 }
cout << "\n delta_sigma_ab_HH_num = "; delta_sigma_ab_HH_num.Ecriture(cout);
cout << "\n sigma_ab_HH = "; sig_sauveHH.Ecriture(cout);
Sortie(1);
}
*/

    // variation des contraintes (composantes dans le repère g_i ) / au eps_kl
    // on peut maintenant calculer la variation de sig_ij / eps_kl
//--//    d_sigma_deps  = Tenseur2HHHH::Var_tenseur_dans_nouvelle_base
//--//                                  (beta_transpose,var_sig_ab_kl_HHHH,d_beta_transpose_HH,sigHH);
    // on calcul par composante car il y a des pb de symétrie qui sont difficiles à maîtriser
    // en tensoriel avec un stockage symétrique (il faudra peut-être essayer d'améliorer via les tenseurs
    // généraux) mais cela doit-être cependant assez efficace !
    TenseurQ2geneHHHH dsig_ijkl_HHHH;
    {for (int i=1;i<3;i++) for (int j=1;j<3;j++) for (int k=1;k<3;k++) for (int l=1;l<3;l++)
      { double inter= 0.;
        for (int a=1;a<3;a++) for (int b=1;b<3;b++)
          inter += d_beta_HH(a,i)(k,l) *  sig_ab_HH(a,b) * beta(b,j)
                   + beta(a,i) * dsig_abkl_HHHH(a,b,k,l) * beta(b,j)
                   + beta(a,i) * sig_ab_HH(a,b) * d_beta_HH(b,j)(k,l);
        dsig_ijkl_HHHH.Change(i,j,k,l,inter);
      };
//cout << "\n deps_abkl= calcul en composantes";
//deps_abkl.Affiche_bidim(cout);
    };

// vérif numérique de la variation
/*{
Tenseur2HH delta_sigma_ij_HH_num;
for (int n=1;n<3;n++) for (int m=1;m<3;m++)
 {delta_sigma_ij_HH_num.Coor(n,m)=0;
  for (int i=1;i<3;i++) for (int j=1;j<3;j++)
    delta_sigma_ij_HH_num.Coor(n,m) += dsig_ijkl_HHHH(n,m,i,j)  * epsBB(i,j);
 }
cout << "\n delta_sigma_ij_HH_num = "; delta_sigma_ij_HH_num.Ecriture(cout);
cout << "\n sigma_ij_HH = "; sigHH.Ecriture(cout);
Sortie(1);
}
*/


    // on passe au tenseur de retour
    d_sigma_deps.TransfertDunTenseurGeneral(dsig_ijkl_HHHH.Symetrise1et2_3et4());

//cout << "\n d_sigma_deps= ";
//d_sigma_deps.Affiche_bidim(cout);
//
//    d_sigma_deps  = Tenseur2HHHH::Var_tenseur_dans_nouvelle_base
//                                  (beta,var_sig_ab_kl_HHHH,d_beta_HH,sigHH);
//
//cout << "\n (2) d_sigma_deps= ";
//d_sigma_deps.Affiche_bidim(cout);

// Sortie(1);

/*    // 1) la variation de d eps_ij / d eps_kl (dans le repère natuelle
    // ici on utilise le fait que IdBB2(i,j) représente le kronecker et idem pour IdHH2(i,j)
    // donc on met la variance qui va bien mais elle n'est pas utilisée
    // var_eps_ab_BBHH(i,j,k,l) = delta_i^k * delta_j^l : puis avec les symétries
    // car on peut changer i et j d'une part et k et l d'autre part
    Tenseur2BBHH var_eps_ij_kl_BBHH(Tenseur2BBHH::Prod_tensoriel_barre(IdBB2,IdHH2));
  
    // 2) la variation d eps_ab / d eps_ij
    Tenseur2BBHH var_eps_ab_kl_BBHH = Tenseur2BBHH::Var_tenseur_dans_nouvelle_base
                                         (beta,var_eps_ij_kl_BBHH,d_beta_HH,eps_p_BB);
  
    // maintenant on calcul la variation de sigma_ab / d epsilon_kl
    Tenseur2BBHH var_sig_ab_kl_BBHH =  var_sig_ab_cd_BBHH && var_eps_ab_kl_BBHH;
  
 
    // calcul de la variation de l'inverse de beta
//    beta_inv = beta.Inverse();
    Tableau2 <Tenseur2HH> d_beta_inv_HH(2,2);
    for (int b=1;b<3;b++)
     for (int j=1;j<3;j++)
       {Tenseur2HH& resHH = d_beta_inv_HH(j,b);
        for (int a=1;a<3;a++)
         for (int i=1;i<3;i++)
           resHH -= (beta_inv(j,a) * beta_inv(i,b)) * d_beta_HH(a,i);
       };

    // on peut maintenant calculer la variation de sig_ij / eps_kl
    Tenseur2BBHH var_sig_ij_kl_BBHH = Tenseur2BBHH::Var_tenseur_dans_nouvelle_base
                                         (beta_inv,var_sig_ab_kl_BBHH,d_beta_inv_HH,sig_BB);
  
    // calcul de la variation de \hat g^ij
    Tenseur2HHHH gijkl_HHHH(Tenseur2HHHH::Prod_tensoriel_barre(gijHH,gijHH));
    Tenseur2HHHH d_gij_kl_HHHH(-2.*Tenseur2HHHH::Prod_tensoriel_barre(gijHH,gijHH));
    Tenseur2HHBB interHHBB(Tenseur2HHBB::Prod_tensoriel_barre(gijHH,sig_BB));
  
    // puis on calcul  l'opérateur tangent dans la la bonne variance
    d_sigma_deps =  (gijkl_HHHH && var_sig_ij_kl_BBHH)
                   + (d_gij_kl_HHHH && (Tenseur2BBHH::Prod_tensoriel_barre(sig_BB,gijHH)))
                   + (interHHBB && d_gij_kl_HHHH);
  
*/

 
    LibereTenseur();
    LibereTenseurQ();       
 };


//vérification de la convexité du potentiel
bool Loi_ortho2D_C_entrainee::Verif_convexite()
 { //   double E1,E2,E3,nu12,nu13,nu23,G12,G13,G23; // paramètres de la loi
//1. - \nu_{12} . \nu_{13} . \nu_{23}. \left ( \frac{E_3}{E_1}  -  \frac{E_2}{E_1}. \frac{E_3}{E_2} \right ) - \nu_{12}^2 . \frac{E_2}{E_1}-\nu_{13}^2 . \frac{E_3}{E_1}-\nu_{23}^2 . \frac{E_3}{E_2} > 0
   bool convexe = true; // vrai a priori
   bool affichage = (Permet_affichage() > 0);

   if (1. <= nu12*nu12*E2/E1)
     {if (affichage)
       cout << "\n attention nu12*nu12*E2/E1 = "<<(nu12*nu12*E2/E1) << ", etant superieur a 1. "
            << " le potentiel n'est pas strictement convexe! ";
      convexe = false;
     };
   if (1. <= nu23*nu23*E3/E2)
     {if (affichage)
       cout << "\n attention nu23*nu23*E3/E2 = "<<(nu23*nu23*E3/E2) << ", etant superieur a 1. "
            << " le potentiel n'est pas strictement convexe! ";
      convexe = false;
     };
   if (1. <= nu13*nu13*E3/E1)
     {if (affichage)
       cout << "\n attention nu13*nu13*E3/E1 = "<<(nu13*nu13*E3/E1) << ", etant superieur a 1. "
            << " le potentiel n'est pas strictement convexe! ";
      convexe = false;
     };
   double x = 1. - nu12 * nu13 * nu23 * (E3/E1   -  E2/E1 * E3/E2)
            - nu12*nu12 * E2/E1 - nu13*nu13 * E3/E1 - nu23*nu23 * E3/E2 ;
   if (x <= 0)
     {if (affichage)
       cout << "\n attention:  1. - nu12*nu13*nu23*(E3/E1-E2/E1*E3/E2)"
            << " - nu12*nu12 * E2/E1 - nu13*nu13 * E3/E1 - nu23*nu23 * E3/E2 = "
            << x << ", etant inferieur ou egal a 0 "
            << " le potentiel n'est pas strictement convexe! ";
      convexe = false;
     };
   // retour
   return convexe;

  };


