// FICHIER : Loi_iso_elas.cp
// CLASSE : Loi_iso_elas


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


//#include "Debug.h"

# include <iostream>
using namespace std;  //introduces namespace std
#include <math.h>
#include <stdlib.h>
#include "Sortie.h"
#include "ConstMath.h"
#include "TenseurQ3gene.h"

#include "Prandtl_Reuss.h"

// ========== fonctions pour la classe de sauvegarde des résultats =========
  
// affectation
Loi_comp_abstraite::SaveResul &
     Prandtl_Reuss::SaveResulPrandtl_Reuss::operator = ( const Loi_comp_abstraite::SaveResul & a)
  { Prandtl_Reuss::SaveResulPrandtl_Reuss& sav
                      = *((Prandtl_Reuss::SaveResulPrandtl_Reuss*) &a);
   
	   // données protégées
	   epsilon_barre = sav.epsilon_barre;
	   def_plasBB = sav.def_plasBB;
	   epsilon_barre_t = sav.epsilon_barre_t;
	   def_plasBB_t = sav.def_plasBB_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 Prandtl_Reuss::SaveResulPrandtl_Reuss::Lecture_base_info 
    (ifstream& ent,const int )
  {  // ici toutes les données sont toujours a priori variables
     string toto; 
	 ent >> toto >> epsilon_barre_t;
     ent >> toto >> def_plasBB_t ;
   };
   
// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables 
//(supposées comme telles)
void Prandtl_Reuss::SaveResulPrandtl_Reuss::Ecriture_base_info
   (ofstream& sort,const int )
  { // ici toutes les données sont toujours a priori variables
    sort << "  epsb_t " << epsilon_barre_t << " " ;
    sort << " def_plasBB_t " << def_plasBB_t << " ";
   }; 
			  
// affichage à l'écran des infos
void Prandtl_Reuss::SaveResulPrandtl_Reuss::Affiche() const 
{ cout << "\n SaveResulPrandtl_Reuss: " ; 
  cout << "\n epsilon_barre= " << epsilon_barre << " def_plasBB= " << def_plasBB
       << " epsilon_barre_t= " << epsilon_barre_t << " def_plasBB_t= " << def_plasBB_t;		 
  cout  << " ";		 
};

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




Prandtl_Reuss::Prandtl_Reuss ()  : // Constructeur par defaut
  Loi_comp_abstraite(PRANDTL_REUSS,CAT_MECANIQUE,3),E(0.),nu(-2.)
  ,f_ecrouissage(NULL)
   ,tolerance_plas(1.e-9),nb_boucle_maxi(100)
    {};
	
// Constructeur de copie
Prandtl_Reuss::Prandtl_Reuss (const Prandtl_Reuss& loi) :
   Loi_comp_abstraite(loi),E(loi.E),nu(loi.nu)
   ,f_ecrouissage(Courbe1D::New_Courbe1D(*(loi.f_ecrouissage)))
   ,tolerance_plas(loi.tolerance_plas),nb_boucle_maxi(loi.nb_boucle_maxi)
	{  };

Prandtl_Reuss::~Prandtl_Reuss ()
// Destructeur 
{ if (f_ecrouissage != NULL)
    if (f_ecrouissage->NomCourbe() == "_")  delete f_ecrouissage;
  };

// Lecture des donnees de la classe sur fichier
 void Prandtl_Reuss::LectureDonneesParticulieres (UtilLecture * entreePrinc,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  { // lecture du module d'young et du coefficient de poisson
    if(strstr(entreePrinc->tablcar,"E=")== NULL)
         { cout << "\n erreur en lecture du module d'young "
                << " on attendait la chaine : E= ";
           cout << "\n Prandtl_Reuss::LectureDonneesParticulieres  "
                << "(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          }
    if(strstr(entreePrinc->tablcar,"nu=")== NULL)
         { cout << "\n erreur en lecture du coefficient de poisson "
                << " on attendait la chaine : nu= ";
           cout << "\n Prandtl_Reuss::LectureDonneesParticulieres  "
                << "(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          }
    string nom,toto;      
    *(entreePrinc->entree) >> nom >> E >> nom >> nu;
    
    // lecture de la loi d'écrouissage
    entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
    if(strstr(entreePrinc->tablcar,"loi_ecrouissage")== NULL)
         { cout << "\n erreur en lecture de la loi d'écrouissage "
                << " on attendait la chaine : loi_ecrouissage";
           cout << "\n Prandtl_Reuss::LectureDonneesParticulieres  "
                << "(UtilLecture * entreePrinc) " << endl ;
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);          
          }
    *(entreePrinc->entree) >> toto >> nom;    
    // on regarde si la courbe existe, si oui on récupère la référence 
    if (lesCourbes1D.Existe(nom)) 
      { f_ecrouissage = lesCourbes1D.Trouve(nom);
        }
    else
     { // sinon il faut la lire maintenant   
       string non_courbe("_");   
       f_ecrouissage = Courbe1D::New_Courbe1D(non_courbe,Id_Nom_Courbe1D (nom.c_str()));
       // lecture de la courbe
       f_ecrouissage->LectDonnParticulieres_courbes (non_courbe,entreePrinc);
      } 
    // appel au niveau de la classe mère
    Loi_comp_abstraite::Lecture_type_deformation_et_niveau_commentaire
                 (*entreePrinc,lesFonctionsnD);

   };
    
 // affichage de la loi
void Prandtl_Reuss::Affiche() const 
  { cout << " \n loi_de_comportement PRANDTL_REUSS 3D" 
         << " \n E= " << E << " nu= " << nu ;
    cout << " \n loi_ecrouissage " ;
    f_ecrouissage->Affiche();    
    // appel de la classe mère
    Loi_comp_abstraite::Affiche_don_classe_abstraite();
  };
            
// affichage et definition interactive des commandes particulières à chaques lois
void Prandtl_Reuss::Info_commande_LoisDeComp(UtilLecture& entreePrinc)
 {  ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
    sort << "\n# .......  loi_de_comportement PRANDTL_REUSS 3D ........"
         << "\n#    module d'young :   coefficient de poisson "
         << "\n E= " << setprecision(6) << E << " nu= " << setprecision(6) << nu 
         << "\n# on doit maintenant definir le nom d'une courbe 1D deja defini au debut du fichier .info,"
         << "\n#  qui donnera  la courbe d'ecrouissabe sigmabarre = f(epsilonbarre): par exemple "
         << "\n# fonction1 ou alors a la suite definir directement la courbe (cf. def de courbe) "
         << "\n# sans un nom de reference " <<  endl;
    // appel de la classe mère
    Loi_comp_abstraite::Info_commande_don_LoisDeComp(entreePrinc);     
  };  		  	  

 // test si la loi est complete
int Prandtl_Reuss::TestComplet()
    { int ret = LoiAbstraiteGeneral::TestComplet();
      if (E == 0.) 
       { cout << " \n le module d'young n'est pas défini pour  la loi " << Nom_comp(id_comp)
              << '\n';
         ret = 0;
       }
      if (nu == -2.) 
       { cout << " \n le coefficient de poisson n'est pas défini pour  la loi " << Nom_comp(id_comp)
              << '\n';
         ret = 0;
       }
      if ( f_ecrouissage == NULL)
       { cout << " \n la fonction d'écrouissage n'est pas défini pour  la loi " 
              << Nom_comp(id_comp)
              << '\n';
         ret = 0;
       }
       return ret; 
    }; 


 // ========== codage des METHODES VIRTUELLES  protegees:================
        // calcul des contraintes 
void Prandtl_Reuss::Calcul_SigmaHH (TenseurHH & sigHH_t,TenseurBB& ,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& ,double& ,TenseurHH & sigHH_
		  	,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
		  	,const Met_abstraite::Expli_t_tdt& )
 {   
   #ifdef MISE_AU_POINT	 	 
	 if (epsBB_.Dimension() != 3)
	    { cout << "\nErreur : la dimension devrait etre 3 !\n";
		  cout << " Prandtl_Reuss::Calcul_SigmaHH\n";
		  Sortie(1);
		};
	 if (tab_ddl.NbDdl() != d_gijBB_.Taille())
	    { cout << "\nErreur : le nb de ddl est != de la taille de d_gijBB_  !\n";
		  cout << " Prandtl_Reuss::Calcul_SigmaHH\n";
		  Sortie(1);
		};		
    #endif

    const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_); // passage en dim 3
    const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
    const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_); //   "      "  "  "
    const Tenseur3BB & gijBB = *((Tenseur3BB*) &gijBB_); //   "      "  "  "
    Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_);  //   "      "  "  "
    Tenseur3HH & sigHH_i = *((Tenseur3HH*) &sigHH_t);  //   "      "  "  "
    SaveResulPrandtl_Reuss & save_resul = *((SaveResulPrandtl_Reuss*) saveResul);
    
    // le tenseur des contraintes initiale en mixte
    Tenseur3BH sigBH_i = gijBB * sigHH_i ; 
    // tout d'abord on considère que l'incrément est purement élastique et on 
    // regarde si la surface de plasticité n'a pas augmenté
       // a) calcul du tenseur élastique résiduel
    Tenseur3BH  eps_elasBH = epsBB * gijHH - save_resul.def_plasBB_t * gijHH;  // deformation en mixte
    Tenseur3BB eps_elas_nBB = eps_elasBH * gijBB; //def car utile pour la plasticité  
    
    // calcul des coefficients 
    double coef1 = (E*nu)/((1.-2.*nu)*(1.+nu));
    double coef2 = E/(1.+ nu);
    // calcul du deviateur des deformations élastiques
    double Ieps = eps_elasBH.Trace();
    Tenseur3BH  sigBH = (Ieps * coef1) * IdBH3 + coef2 * eps_elasBH ; // contrainte en mixte
       // b) calcul de la nouvelle contrainte équivalente
    double Isig = sigBH.Trace();
    Tenseur3BH S_BH = sigBH - Isig * IdBH3/3.; // le déviateur
    double sig_equi=sqrt(3./2. * S_BH && S_BH);
       // c) test et orientation ad hoc

    if ((f_ecrouissage->Valeur(save_resul.epsilon_barre_t) >= sig_equi) ||
         comp_tangent_simplifie)
       // cas ou l'élasticité est confirmée
      { // passage en 2fois contravariants
        sigHH = gijHH * sigBH;
       }
    else
       // cas ou l'on est en élastoplasticité
      { // la procédure de calcul est de type newton
        
        const int nbddl_def = 6; // le nombre de ddl de déformation
        Tenseur3BB deps_plasBB; // def de l'incrément de la déformation plastique en BB
        Tenseur3BH deps_plasBH; // def de l'incrément de la déformation plastique en BH
        // delta de lambda d'une itération à l'autre en BB
        double delta_lambda; // initialisation à zéro
        double lambda = 0.; // le lambda résultant
        double res_plas;  // résidu de l'équation sur la surface plastique
        Tenseur3BB S_BB; // déviateur en BB
        Tenseur3BB sigBB; // contrainte en BB
        double & epsilon_barre = save_resul.epsilon_barre; // pour simplifier l'écriture
        double & epsilon_barre_t = save_resul.epsilon_barre_t; // pour simplifier l'écriture
        Tenseur3BB& def_plasBB_t = save_resul.def_plasBB_t; // """
        Tenseur3BB& def_plasBB = save_resul.def_plasBB; // """
        const double deux_tiers = 2./3.;
        const double un_tiers = 1./3.;
        const double un_demi = 1./2.;
        const double coef2_carre = coef2 * coef2;
        const double coef2_cube = coef2 * coef2_carre;
        const double racine_deux_tiers = sqrt(deux_tiers);
        
        // la métrique initiale
        Tenseur3BB gij_0_BB = gijBB - 2. * epsBB;
        // le déviateur de la déformation élastique
        Tenseur3BH eps_elas_barre_BH = eps_elasBH - (un_tiers * Ieps) *IdBH3;
        // puis en deux fois covariant
        Tenseur3BB eps_elas_barre_BB = eps_elas_barre_BH * gijBB; 
        epsilon_barre = epsilon_barre_t; // init
        // def du sigma équivalent initial
        double sig_equi_i = f_ecrouissage->Valeur(epsilon_barre_t);
        sigBH = sigBH_i;     // init
        Tableau2 <int> IJK = OrdreContrainte(nbddl_def); // pour la transformation 6 -> (i,j)
        // ijk(n,1) correspond au premier indice i, et ijk(n,2) correspond au deuxième indice j
        // acroissement de la déformation équivalente plastique
        double delta_eps_equi = 0;
        // constante c
        double c_c = eps_elas_barre_BH && eps_elas_barre_BH;                           
        // pour le calcul de la variation de f c-a-d le résidu
        double Df_Dlambda ;
        // variables qui sont utilisées après la boucle
        double un_sur_1_plus_2_G_lambda
              ,un_sur_1_plus_2_G_lambda2,un_sur_1_plus_2_G_lambda3; 
        Courbe1D::ValDer valder;               
          
        int nb_iter = 1;
        bool fin_plastique = false; // pour la fin de la boucle suivante
        while ((!fin_plastique) && (nb_iter <= nb_boucle_maxi))
         {  
          un_sur_1_plus_2_G_lambda = 1. / (1. + coef2*lambda);
          un_sur_1_plus_2_G_lambda2 = 
                    un_sur_1_plus_2_G_lambda * un_sur_1_plus_2_G_lambda;
          un_sur_1_plus_2_G_lambda3 =
                    un_sur_1_plus_2_G_lambda * un_sur_1_plus_2_G_lambda2;          
          // nouveau déviateur de contrainte en mixte     
          S_BH = (coef2 * un_sur_1_plus_2_G_lambda) * eps_elas_barre_BH;
          // en deux fois covariant     
          S_BB = S_BH * gijBB;
          // calcul de l'incrément de déformation plastique
          deps_plasBB = lambda * S_BB;
          deps_plasBH = deps_plasBB * gijHH;// delta def plastique en BH 
          def_plasBB = def_plasBB_t + deps_plasBH * gijBB; // deformation plastique
          delta_eps_equi = sqrt(deux_tiers * (deps_plasBH && deps_plasBH));
          epsilon_barre = epsilon_barre_t +  // def plastique cumulée
                            delta_eps_equi; 
          // nouvelle valeur de la variation de sigma_barre
          // et valeur de la tangente de la courbe d'écrouissage
          valder = f_ecrouissage->Valeur_Et_derivee(epsilon_barre);
          sig_equi = valder.valeur;
                                      
          // calcul du résidu
          res_plas = coef2_carre * c_c * un_sur_1_plus_2_G_lambda2 * un_demi 
                     - sig_equi * sig_equi * un_tiers; 
          // test d'arrêt, pas pour la première itération car il faut 
          // le calcul de pas mal de grandeur pour le calcul de variation qui
          // suit la boucle plastique
          if (( Dabs(res_plas) < tolerance_plas) && (nb_iter!= 1))
            {fin_plastique = true;
             if (lambda < 0)
              cout << "\n *** erreur : lambda plastique négatif "
                   << "\n Prandtl_Reuss::Calcul_DsigmaHH_tdt (.. ";
             break;
             }
          // cas où l'on doit faire une itération supplémentaire
          // calcul de la variation du résidu par rapport à lamda
          // 1 - calcul de la variation du premier terme
          double D1_Dlambda = - un_sur_1_plus_2_G_lambda3 * c_c * coef2_cube;
          // 2 - calcul de la variation de la déformation plastique cumulée
          double der_eps_plas_lambda = racine_deux_tiers * coef2
                          * sqrt(c_c) * un_sur_1_plus_2_G_lambda2;
          // 3 - calcul de la variation du second terme de f 
          double D2_Dlambda = - deux_tiers * sig_equi * valder.derivee * der_eps_plas_lambda;
          // 4 - calcul de la variation de f
          Df_Dlambda = D1_Dlambda + D2_Dlambda;
          // calcul de l'incrément de lambda
          delta_lambda = - res_plas / Df_Dlambda;
          // nouvelle valeur de lambda
          lambda += delta_lambda;
          // incrémentation de la boucle
          nb_iter++;  
          }      
         // sortie de la boucle on vérifie que la convergence est ok sinon message
         if (!fin_plastique)
          { cout << "\n attention non convergence sur la plasticité " << endl;
           }
         // calcul du tenseur des contraintes
         sigBH = S_BH + (un_tiers*Ieps * E/(1.-2.*nu)) * IdBH3;
         // passage en 2 fois contravariants
         sigHH = gijHH * sigBH;
         // passage aussi en 2 fois covariants (utilisé pour les variations)
         sigBB = sigBH * gijBB;
         } 
                  
    LibereTenseur();        
 };
        
        // calcul des contraintes a t+dt et de ses variations  
void Prandtl_Reuss::Calcul_DsigmaHH_tdt (TenseurHH & sigHH_t,TenseurBB& ,DdlElement & tab_ddl
            ,BaseB& ,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& ,double& ,
		  	Vecteur& ,TenseurHH& sigHH_tdt,Tableau <TenseurHH *>& d_sigHH
		  	,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double&  module_cisaillement
		  	,const Met_abstraite::Impli& )
 {
   #ifdef MISE_AU_POINT	 	 
	 if (epsBB_tdt.Dimension() != 3)
	    { cout << "\nErreur : la dimension devrait etre 3 !\n";
		  cout << " Prandtl_Reuss::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 << " Prandtl_Reuss::Calcul_DsigmaHH_tdt\n";
		  Sortie(1);
		};
    #endif
    

    const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
    const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
    const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_tdt); //   "      "  "  "
    const Tenseur3BB & gijBB = *((Tenseur3BB*) &gijBB_tdt); //   "      "  "  "
    Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_tdt);  //   "      "  "  "
    Tenseur3HH & sigHH_i = *((Tenseur3HH*) &sigHH_t);  //   "      "  "  "
    SaveResulPrandtl_Reuss & save_resul = *((SaveResulPrandtl_Reuss*) saveResul);
    
    // pour la variation du tenseur des contraintes
    int nbddl = d_gijBB_tdt.Taille();
    
    // le tenseur des contraintes initiale en mixte
    Tenseur3BH sigBH_i = gijBB * sigHH_i ; 
    // tout d'abord on considère que l'incrément est purement élastique et on 
    // regarde si la surface de plasticité n'a pas augmenté
       // a) calcul du tenseur élastique résiduel
    Tenseur3BB eps_plas_n_BB=save_resul.def_plasBB_t; // recup du tenseur de déformation plastique
      // convecté deux fois covariants (donc la trace n'est pas nulle) 
    // on passe en coordonnées locales le tenseur de la déformation plastique sauvegardé
//    (save_resul.def_plasBB_t).Baselocale(eps_plas_n_BB,giB_tdt);

    Tenseur3BB eps_elas_nBB = epsBB -  eps_plas_n_BB; // def élastique initiale en deux fois covariants 
    Tenseur3BH  eps_elasBH = eps_elas_nBB * gijHH ;  // deformation en mixte
    // calcul des coefficients 
    double coef1 = (E*nu)/((1.-2.*nu)*(1.+nu));
    double coef2 = E/(1.+ nu);
    // calcul de la trace  des deformations élastiques
    double Ieps = eps_elasBH.Trace();
    Tenseur3BH  sigBH = (Ieps * coef1) * IdBH3 + coef2 * eps_elasBH ; // contrainte en mixte
       // b) calcul de la nouvelle contrainte équivalente
    double Isig = sigBH.Trace();
    Tenseur3BH S_BH = sigBH - Isig * IdBH3/3.; // le déviateur
    double sig_equi=sqrt(3./2. * S_BH && S_BH);
       // c) test et orientation ad hoc
       
    if ((f_ecrouissage->Valeur(save_resul.epsilon_barre_t) >= sig_equi) ||
        comp_tangent_simplifie)
//    bool toto = true;
//    if (toto)
       // cas ou l'élasticité est confirmée
      { // passage en 2foi contravariants
        sigHH = gijHH * sigBH;
        // la variation de la contrainte c'est en fait la variation du delta contrainte
        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 ()
           Tenseur3HH & dsigHH = *((Tenseur3HH*) (d_sigHH(i)));  // passage en dim 3
           const Tenseur3BB & d_gijBB =  *((Tenseur3BB*)(d_gijBB_tdt(i)));  // passage en dim 3
           const Tenseur3HH & dgijHH = *((Tenseur3HH*)(d_gijHH_tdt(i))) ; // pour simplifier l'ecriture
           const BaseB& d_giB = d_giB_tdt(i); // simplification
           const BaseH& d_giH = d_giH_tdt(i); //    "
           // pour chacun des ddl on calcul les tenseurs derivees
           Tenseur3BB d_eps_BB = 0.5 * d_gijBB;
           // variation de la partie plastique qui est utilisé en coordonnées  locale
           //  a- calcul de la matrice de passage de la variation de la base
           //     giH par rapport au ddl, exprimée dans la base giH 
           Mat_pleine e_ij(3,3) ;
           for (int i1=1;i1<=3;i1++)
             for (int j1=1;j1<=3;j1++)
               e_ij(i1,j1) = d_giH_tdt(i)(i1) * giB_tdt(j1); 
           //  b- calcul des coordonnées de la variations des composantes deux fois covariantes
           //     de la déformation plastique
           Tenseur3BB d_eps_plas_n_BB;
           for (int i2=1;i2<=3;i2++) for (int j2=1;j2<=i2;j2++) for (int k=1; k<= 3; k++)
             d_eps_plas_n_BB.Coor(i2,j2) += -(eps_plas_n_BB(k,j2)*e_ij(k,i2)
                                              + eps_plas_n_BB(i2,k)*e_ij(k,j2));
           //                                    
           Tenseur3BH d_eps_elasBH =  eps_elas_nBB * dgijHH  + (d_eps_BB - d_eps_plas_n_BB)* gijHH;
           
           //  variation de la trace
    //       double dIeps = (d_eps_BB && gijHH) + (epsBB && dgijHH);
           
           
           
           double dIeps = d_eps_elasBH.Trace();
           dsigHH = dgijHH * sigBH + gijHH *  
                ((dIeps * coef1) * IdBH3 + coef2 * d_eps_elasBH);
                
           // On calcul les coefficients de variation des vecteurs de base
           Mat_pleine ee(3,3);
           for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
              ee(i,j)= d_giB(i) * giH_tdt(j);
           // calcul de la dérivée totale non objective(c-a-d y compris les vecteurs de base)
           for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
             for (int k=1;k<=3;k++)
               dsigHH.Coor(i,j) += sigHH(k,j) * ee(k,i) + sigHH(i,k) * ee(k,j) ;
          }          
       }
    else
       // cas ou l'on est en élastoplasticité
      { // la procédure de calcul est de type newton
        
        const int nbddl_def = 9; // le nombre de ddl de déformation en mixte
        Tenseur3BB deps_plasBB; // def de l'incrément de la déformation plastique en BB
        Tenseur3BH deps_plasBH; // def de l'incrément de la déformation plastique en BH
        // delta de lambda d'une itération à l'autre en BB
        double delta_lambda=0.; // initialisation à zéro
        double lambda = 0.; // le lambda résultant
        double res_plas;  // résidu de l'équation sur la surface plastique
        Tenseur3BB sigBB; // contrainte en BB
        Tenseur3BB S_BB; // déviateur des contraintes en BB        
        double & epsilon_barre = save_resul.epsilon_barre; // pour simplifier l'écriture
        double & epsilon_barre_t = save_resul.epsilon_barre_t; // pour simplifier l'écriture
 //       Tenseur3BH& def_plasBH_t = save_resul.def_plasBH_t; // """
        Tenseur3BB& def_plasBB = save_resul.def_plasBB; // """
        const double deux_tiers = 2./3.;
        const double un_tiers = 1./3.;
        const double un_demi = 1./2.;
        const double coef2_carre = coef2 * coef2;
        const double coef2_cube = coef2 * coef2_carre;
        const double racine_deux_tiers = sqrt(deux_tiers);
        
        // la métrique initiale
        Tenseur3BB gij_0_BB = gijBB - 2. * epsBB;
        // le déviateur de la déformation élastique initiale au début des itérations
        Tenseur3BH c_BH = eps_elasBH - (un_tiers * Ieps) *IdBH3;
        // et en deux fois covariants
        Tenseur3BB c_BB = c_BH * gijBB;
        
//        Tenseur3BH eps_elas_barre_BH = eps_elasBH - (un_tiers * Ieps) *IdBH3;
        // puis en deux fois covariant
//        Tenseur3BB eps_elas_barre_BB = eps_elas_barre_BH * gijBB;
        epsilon_barre = epsilon_barre_t; // init
        // def du sigma équivalent initial
        double sig_equi_i = f_ecrouissage->Valeur(epsilon_barre_t);
        sigBH = sigBH_i;     // init
        Tableau2 <int> IJK = OrdreContrainte(nbddl_def); // pour la transformation 9 -> (i,j)
        // ijk(n,1) correspond au premier indice i, et ijk(n,2) correspond au deuxième indice j
        // acroissement de la déformation équivalente plastique
        double delta_eps_equi = 0;
        // constante c
        double c_c = c_BH && c_BH;                           
        // pour le calcul de la variation de f c-a-d le résidu
        double Df_Dlambda ;
        // variables qui sont utilisées après la boucle
        double un_sur_1_plus_2_G_lambda
              ,un_sur_1_plus_2_G_lambda2,un_sur_1_plus_2_G_lambda3;
        double alphaa,alphaa2,alphaa3;       
        Courbe1D::ValDer valder; 
          
        int nb_iter = 1;
        bool fin_plastique = false; // pour la fin de la boucle suivante
        while ((!fin_plastique) && (nb_iter <= nb_boucle_maxi))
         {  
          un_sur_1_plus_2_G_lambda = 1. / (1. + coef2*lambda);
          un_sur_1_plus_2_G_lambda2 = 
                    un_sur_1_plus_2_G_lambda * un_sur_1_plus_2_G_lambda;
          un_sur_1_plus_2_G_lambda3 =
                    un_sur_1_plus_2_G_lambda * un_sur_1_plus_2_G_lambda2;
          alphaa = un_sur_1_plus_2_G_lambda*coef2;
          alphaa2 = un_sur_1_plus_2_G_lambda2 * coef2_carre;
          alphaa3 = un_sur_1_plus_2_G_lambda3 * coef2_cube;                    
          // nouveau déviateur de contrainte en deux fois covariants    
          S_BB = alphaa * c_BB;
          // calcul de l'incrément de déformation plastique
          deps_plasBB = lambda * S_BB;// delta def plastique en BB
          deps_plasBH = deps_plasBB * gijHH;
          delta_eps_equi = sqrt(deux_tiers * (deps_plasBH && deps_plasBH));
          epsilon_barre = epsilon_barre_t +  // def plastique cumulée
                            delta_eps_equi; 
          // nouvelle valeur de la variation de sigma_barre
          // et valeur de la tangente de la courbe d'écrouissage
          valder = f_ecrouissage->Valeur_Et_derivee(epsilon_barre);
          sig_equi = valder.valeur;
                                      
          // calcul du résidu
          res_plas = alphaa2 * c_c * un_demi 
                     - sig_equi * sig_equi * un_tiers; 
          // test d'arrêt, pas pour la première itération car il faut 
          // le calcul de pas mal de grandeur pour le calcul de variation qui
          // suit la boucle plastique
          if (( Dabs(res_plas) < tolerance_plas) && (nb_iter!= 1))
            {fin_plastique = true;
             if (lambda < 0)
              cout << "\n *** erreur : lambda plastique négatif "
                   << "\n Prandtl_Reuss::Calcul_DsigmaHH_tdt (.. ";
             break;
             }
          // cas où l'on doit faire une itération supplémentaire
          // calcul de la variation du résidu par rapport à lamda
          // 1 - calcul de la variation du premier terme
          double D1_Dlambda = - alphaa3 * c_c ;
          // 2 - calcul de la variation de la déformation plastique cumulée
          double der_eps_plas_lambda = 2.*racine_deux_tiers * coef2
                          * sqrt(c_c) * un_sur_1_plus_2_G_lambda2;
          // 3 - calcul de la variation du second terme de f 
          double D2_Dlambda = - deux_tiers * sig_equi * valder.derivee * der_eps_plas_lambda;
          // 4 - calcul de la variation de f
          Df_Dlambda = D1_Dlambda + D2_Dlambda;
          // calcul de l'incrément de lambda
          delta_lambda = - res_plas / Df_Dlambda;
          // nouvelle valeur de lambda
          lambda += delta_lambda;
          // incrémentation de la boucle
          nb_iter++;  
          }      
         // sortie de la boucle on vérifie que la convergence est ok sinon message
         if (!fin_plastique)
          { cout << "\n attention non convergence sur la plasticité " << endl;
           }
         // calcul du tenseur des contraintes
         sigBB = S_BB + (un_tiers*Ieps *E/(1.-2.*nu)) * gijBB;
         // passage en 2 fois contravariants
         sigHH = (gijHH * sigBB) * gijHH;
         // accumulation et sauvegarde de la déformation plastique 
         // qui est stockée en deux fois covariants
         def_plasBB = save_resul.def_plasBB_t + deps_plasBB;
         
         
         // ------  maintenant on s'occupe de la raideur tangente
/*          
         // variation des tenseurs métriques par rapport aux déformations
         // tenseur identité normal du 4 ième ordre
         TenseurQ3geneBBBB dIBB_epsBB_dBBBB(true,gijBB,gijBB);
         // tenseur identité barre du 4 ième ordre
         TenseurQ3geneBBBB dIBB_epsBB_dBBBB(false,gijBB,gijBB);
         // calcul de la variation du déviateur des déformations par rapport à la déformation
         TenseurQ3geneBBBB depsB_epsBB_BBBB=(1.+ un_tiers *Ieps)*IdIdbarreBBBB  
                 + un_tiers * TenseurQ3geneBBBB::Prod_tensoriel(gij_0_BB,gijBB); 
         // variation du tenseur C par rapport aux déformations
         TenseurQ3geneBBBB dC_BBBB=( 1 + un_tiers * (Ieps + Ieps_plas))*IdIdbarreBBBB 
                 - un_tiers * TenseurQ3geneBBBB::Prod_tensoriel(gij_0_BB,gijBB);          
                 + deux_tiers * TenseurQ3geneBBBB::Prod_tensoriel(eps_plas_n_BB,gijBB);          
         // variation du tenseur c par rapport aux déformations
         Tenseur3HH c_HH = gijHH * c_BH ;
         Tenseur3BB d_cBB = dC_BBBB && c_HH + c_HH && dC_BBBB;
         // variation de la fonction de charge par rapport aux déformations
         Tenseur3BB D_f_BB = (un_demi * alphaa2 + racine_deux_tiers * lambda * alphaa
                              * sig_equi /(3. * sqrt(c_c) )  * valder.derivee) 
                             * D_cBB; 
         // variation du multiplicateur plastique par rapport aux déformations
         Tenseur3BB D_lambdaBB = (-1./Df_Dlambda) * D_f_BB;
         // variation du déviateur des contraintes par rapport aux déformations
         TenseurQ3geneBBBB D_S_BBBB = alphaa * (dC_BBBB - alphaa * 
                     TenseurQ3geneBBBB::Prod_tensoriel( D_lambdaBB,c_BB));
         // variation du tenseur des contraintes par rapport aux déformations
         double Ksur3= E/(1-2.*nu)/3.;
         TenseurQ3geneBBBB D_sig_BBBB = D_S_BBBB + Ksur3 * 


 D_S_BB_DepsBB(ij) 
  ////                               + Ksur3 (gijBB * gij_0_BB(IJK(ij,1),IJK(ij),2)
  ////                                       + Ieps * D_gij_BB_DepsBB(ij));
         // variation du tenseur des contraintes par rapport aux ddl                                
         for (int iddl = 1; iddl<= nbddl; iddl++)
         { // on fait uniquement une égalité d'adresse pour ne pas utiliser
           // le constructeur d'ou la profusion d'* et de ()
           Tenseur_ns3HH & dsigHH = *((Tenseur_ns3HH*) (d_sigHH(iddl)));  // passage en dim 3
           const Tenseur3BB & d_gijBB =  *((Tenseur3BB*)(d_gijBB_tdt(iddl)));  // passage en dim 3
           const Tenseur3HH & dgijHH = *((Tenseur3HH*)(d_gijHH_tdt(iddl))) ; // pour simplifier l'ecriture
           const BaseB& d_giB = d_giB_tdt(iddl); // simplification
           const BaseH& d_giH = d_giH_tdt(iddl); //    "
           // pour chacun des ddl on calcul les tenseurs derivees
           // def de la variation de la déformation
           Tenseur3BB d_eps_BB = 0.5 * d_gijBB;
           // calcul de la variation de sig_BB par rapport au ddl
           Tenseur3BB dsig_BB;
           for (int e1=1;e1<= nbddl_def; e1++) 
             dsig_BB += D_sig_BB_DepsBB(e1) * d_eps_BB(IJK(e1,1),IJK(e1,2));
           // passage en deux fois contravariants: sigHH = gijHH * sigBB * gijHH
           dsigHH= (dgijHH * sigBB) * gijHH 
                   + (gijHH * dsig_BB) * gijHH
                   + (gijHH * sigBB) * dgijHH;
           }          */
         
//=========== fin new =========================================  
         
         
         
          
              
           
 /*        // le module de compressibilité            
         double a3 = E/(3.*(1.-2.*nu));
         // le tenseur de déformation plastique total actuel en local
         Tenseur3BB eps_plas_np1_BB = eps_plas_n_BB + deps_plasBH * gijBB; 
         // le tenseur de déformation élastique actuel en deux fois covariants
         Tenseur3BB eps_elas_np1BB = eps_elas_np1BH * gijBB;
         // 7- calcul de la variation de sigmaHH par rapport au ddl
         for (int iddl = 1; iddl<= nbddl; iddl++)
         { // on fait uniquement une égalité d'adresse pour ne pas utiliser
           // le constructeur d'ou la profusion d'* et de ()
           Tenseur_ns3HH & dsigHH = *((Tenseur_ns3HH*) (d_sigHH(iddl)));  // passage en dim 3
           const Tenseur3BB & d_gijBB =  *((Tenseur3BB*)(d_gijBB_tdt(iddl)));  // passage en dim 3
           const Tenseur3HH & dgijHH = *((Tenseur3HH*)(d_gijHH_tdt(iddl))) ; // pour simplifier l'ecriture
           const BaseB& d_giB = d_giB_tdt(iddl); // simplification
           const BaseH& d_giH = d_giH_tdt(iddl); //    "
           // pour chacun des ddl on calcul les tenseurs derivees
           // def de la variation de la déformation
           Tenseur3BB d_eps_BB = 0.5 * d_gijBB;
           
           //  variation de la trace
           double dIeps = (d_eps_BB && gijHH) + (epsBB && dgijHH);
           // variation du déviateur de la déformation totale
           Tenseur3BH d_eps_totale_B_BH = d_eps_BB * gijHH + epsBB * dgijHH
                  - (un_tiers * dIeps) * IdBH3; 
           
           // variation de la partie plastique qui est utilisé en coordonnées  locale
           //  a- calcul de la matrice de passage de la variation de la base
           //     giH par rapport au ddl, exprimée dans la base giH 
           Mat_pleine e_ij(3,3) ;
           for (int i1=1;i1<=3;i1++)
             for (int j1=1;j1<=3;j1++)
               e_ij(i1,j1) = d_giH_tdt(iddl)(i1) * giB_tdt(j1); 
           //  b- calcul des coordonnées de la variations des composantes deux fois covariantes
           //     de la déformation plastique
           Tenseur3BB d_eps_plas_np1_BB;
           for (int i2=1;i2<=3;i2++) for (int j2=1;j2<=i2;j2++) for (int k=1; k<= 3; k++)
             d_eps_plas_np1_BB(i2,j2) += -(eps_plas_np1_BB(k,j2)*e_ij(k,i2)
                                              + eps_plas_np1_BB(i2,k)*e_ij(k,j2));
           // 7.1.1 calcul de la variation de eps_elas_BH                                  
           Tenseur3BH d_eps_elasBH =  eps_elas_np1BB * dgijHH  + (d_eps_BB - d_eps_plas_np1_BB)* gijHH;
           double dIeps = d_eps_elasBH.Trace();
           // 7.1.2 calcul de la variation de eps_elas_barre_BH
           Tenseur3BH deps_elas_barre_BH = d_eps_elasBH - (un_tiers * dIeps) * IdBH3; */
           // 7.2- calcul de la variation de S_BH par rapport au ddl
 /*          Tenseur3BH dS_BH;
           for (int e1=1;e1<= nbddl_def; e1++) 
             dS_BH += D_S_BH_DepsBijBH_BH(e1) * d_eps_totale_B_BH(IJK(e1,1),IJK(e1,2));
 //            dS_BH += D_S_BH_DepsBijBH_BH(e1) * deps_elas_barre_BH(IJK(e1,1),IJK(e1,2));
           // On calcul les coefficients de variation des vecteurs de base
           Mat_pleine ee(3,3);
           for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
              ee(i,j)= d_giB(i) * giH_tdt(j);
           // calcul de la variation des composantes deux fois contravariantes
           Tenseur_ns3HH d_sig_HH =  gijHH * dS_BH +  dgijHH * S_BH 
                                 + gijHH * ((a3 * dIeps ) * IdBH3) 
                                 + dgijHH * ((a3 * Ieps ) * IdBH3);
           Tenseur3HH trouc =   gijHH * ((a3 * dIeps ) * IdBH3) 
                                 + dgijHH * ((a3 * Ieps ) * IdBH3);                     
           // calcul de la dérivée totale non objective(c-a-d y compris les vecteurs de base)
           Tenseur_ns3HH delta_sig_HH(d_sig_HH);
           for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
             for (int k=1;k<=3;k++)
               delta_sig_HH(i,j) += S_HH(k,j) * ee(k,i) + S_HH(i,k) * ee(k,j) ;
           // mise à jour du tenseur dérivée
    //       dsigHH = delta_sig_HH;
           dsigHH = un_demi * (delta_sig_HH + delta_sig_HH.Transpose());  */
             

  /*         Tenseur3BH dS__BH;
           for (int i=1;i<=3;i++)
            for (int j=1;j<=3;j++)
             for (int e=1;e<= 3;e++)
               for (int f=1;f<=3;f++) 
                 dS__BH(i,j)  +=   coef2 * (IdBH3(i,e) * IdBH3(f,j) 
                                     ) * d_eps_totale_B_BH(e,f);
           dS__BH =  d_eps_totale_B_BH;                          
//                 dS__BH(i,j)  +=   coef2 * (IdBH3(i,e) * IdBH3(f,j) 
//                                     - Gamma * S_BH(f,e) * S_BH(i,j)) * d_eps_totale_B_BH(e,f); 
           Tenseur3HH  dS__HH = gijHH * dS__BH + dgijHH * S_BH; */                     
  /*    // essai bidouille
           // on veut symétriser la variation de S_BH
           Tenseur_ns3BB inteBB =  dS_BH * gijBB;
           Tenseur3BB totiBB = un_demi * (inteBB + inteBB.Transpose());
           dS_BH = totiBB * gijHH;
           Tenseur3HH trucHH = gijHH * dS_BH;
           Tenseur3HH tricHH = gijHH * ((a3 * dIeps ) * IdBH3);           
      // fin essai bidouille */
       //    Tenseur3HH varSHH = gijHH * d_eps_totale_B_BH;
           
                            
           // 7.3- calcul de la variation de sigmaBH par rapport au ddl
  ///         Tenseur3BH dsigBH = dS_BH + (a3 * dIeps ) * IdBH3; 
           // 7.4- calcul maintenant en deux fois contravariants
           
///           dsigHH = gijHH * dsigBH + dgijHH * sigBH;
           
//           dsigHH = gijHH * dsigBH + dgijHH * sigBH; 
           // info de vérification
  /*         Tenseur3HH ddSHH = dgijHH * S_BH + gijHH * dS_BH;
           double dIsig = E/(1-2.*nu) * dIeps;
           double Isig = E/(1-2.*nu) * Ieps;
           Tenseur3HH dspheriqueHH = un_tiers*(dgijHH * (Isig * IdBH3)  + gijHH * (dIsig * IdBH3));
           Tenseur3HH ddsigHH = ddSHH + dspheriqueHH; */
           // fin info de vérification
  /*         Tenseur3BH aeps_elas_barre_BH = eps_elasBH - (1./3. * Ieps) *IdBH3;
           Tenseur3BH adeps_elasBH = d_eps_BB * gijHH + eps_elas_nBB * dgijHH;
           Tenseur3BH adeps_elas_barre_BH = adeps_elasBH - (1./3.*dIeps)*IdBH3;
           Tenseur3BH aSBH = coef2 * eps_elas_barre_BH;
           Tenseur3BH addSBH = coef2 * adeps_elas_barre_BH;
           Tenseur3HH addSHH = dgijHH * aSBH + gijHH * addSBH;
           double adIsig = E/(1-2.*nu) * dIeps;
           Tenseur3HH adspheriqueHH = 1./3.*(dgijHH * (Isig * IdBH3)  + gijHH * (adIsig * IdBH3));
           Tenseur3HH addsigHH = addSHH + adspheriqueHH; */
           }          
         
          
                  
  ////  LibereTenseur();        
 };
	 
	   //----- 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 Prandtl_Reuss::Lecture_base_info_loi(ifstream& ent,const int cas,LesReferences& lesRef,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  { string toto; 
	if (cas == 1) 
	 { ent >> toto >> E >> toto >> nu;
       // la courbe d'écrouissage
       ent >> toto;
       if (toto != "f_ecrouissage")
        { cout << "\n erreur en lecture de la fonction d'ecrouissage, on attendait f_ecrouissage et on a lue " << toto
               << "\n Prandtl_Reuss::Lecture_base_info_loi(...";
          Sortie(1);
         }; 
       f_ecrouissage = lesCourbes1D.Lecture_pour_base_info(ent,cas,f_ecrouissage);
       // lecture des tol  
       ent >>  toto >> tolerance_plas
            >> toto >> nb_boucle_maxi ;
	  }
	// appel class 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 Prandtl_Reuss::Ecriture_base_info_loi(ofstream& sort,const int cas)
  { if (cas == 1) 
     { sort << "  module_d'young " << E << " nu " << nu ;
       // la courbe d'écrouissage
       sort << " \n f_ecrouissage ";
       LesCourbes1D::Ecriture_pour_base_info(sort,cas,f_ecrouissage);
       sort << "\n tolerance_algorithme " << tolerance_plas
            << " nb_boucle_maxi " << nb_boucle_maxi << " ";
      }
	// appel de la classe mère
    Loi_comp_abstraite::Ecriture_don_base_info(sort,cas);  
   }; 
     
