

// 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 "CompFrotCoulomb.h"
#include "Util.h"
#include "CharUtil.h"

		// CONSTRUCTEURS :
CompFrotCoulomb::CompFrotCoulomb () :  // Constructeur par defaut
    CompFrotAbstraite(LOI_COULOMB,CAT_FROTTEMENT,4) // 4 pour dire que c'est valable quelque 
                                                    // soit la dimension
    ,mu_statique(-ConstMath::tresgrand),mu_cine(NULL),x_c(NULL),regularisation(0)
    ,epsil(-ConstMath::tresgrand),fonc_regul(NULL)                                               
		 { };
		
// Constructeur de copie
CompFrotCoulomb::CompFrotCoulomb (const CompFrotCoulomb & a ) :
		 CompFrotAbstraite(a)
    ,mu_statique(a.mu_statique),mu_cine(NULL),x_c(NULL),regularisation(a.regularisation)
    ,epsil(a.epsil),fonc_regul(NULL)                                               
	{ if (a.mu_cine != NULL) {mu_cine = new double; *mu_cine = *(a.mu_cine);};
	  if (a.x_c != NULL) {x_c = new double; *x_c = *(a.x_c);};
	  // on regarde s'il s'agit de courbes locales ou de courbes globales
	  if (fonc_regul != NULL)
	   if (fonc_regul->NomCourbe() == "_")
        {// comme il s'agit d'une courbe locale on la redéfinie (sinon pb lors du destructeur de loi)
         string non_courbe("_");   
         fonc_regul = Courbe1D::New_Courbe1D(*a.fonc_regul);
        };
	};
		
// DESTRUCTEUR VIRTUEL :
CompFrotCoulomb::~CompFrotCoulomb ()
{ if (mu_cine != NULL) delete mu_cine;
  if (x_c != NULL) delete x_c;
  if (fonc_regul != NULL)
      if (fonc_regul->NomCourbe() == "_") delete fonc_regul;
  };
		
	
// =============== methodes  ======================
// Lecture des donnees de la classe sur fichier
void CompFrotCoulomb::LectureDonneesParticulieres 
                (UtilLecture * entreePrinc,LesCourbes1D& lesCourbes1D,LesFonctions_nD& lesFonctionsnD)
  { string toto,nom;
    *(entreePrinc->entree) >> nom; // init de la lecture
    do
      { if(nom == "mu_statique=")
         { // -- lecture du coefficient mu_statique 
           *(entreePrinc->entree) >> mu_statique;
         }
        else if(nom == "fin_loi_frottement_coulomb_")
         { // -- fin de la lecture 
           break;
         }
        else if(nom == "regularisation=")
         { // -- lecture du coefficient regularisation 
           *(entreePrinc->entree) >> regularisation;
           if (regularisation == 0) 
           	{ // on passe les infos concernants qui ici ne servent pas car pas de régularisation
           	  if(strstr(entreePrinc->tablcar,"epsil=")!=0) // passage de "epsil=" et de la valeur
           	      *(entreePrinc->entree) >> nom >> nom;
           	  if(strstr(entreePrinc->tablcar,"fonction_regul_")!=0) // passage de "fonction_regul_" 
           	      *(entreePrinc->entree) >> nom >> nom;             // et du nom de courbe
           	}
           else if ((regularisation > 0) && (regularisation < 4))
           	{ if(strstr(entreePrinc->tablcar,"epsil=")!=0) 
           	     {*(entreePrinc->entree) >> nom >> epsil;}
              else
                { *(entreePrinc->entree) >> nom;
                  cout << "\n erreur en lecture du coefficient de pilotage de la regularisation, on attendait "
                       << " la chaine epsil= et on a lu: " << nom << endl ;
                  entreePrinc->MessageBuffer("erreur 1   ");
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie(1);
                 };
           	}
           else if (regularisation == 4)
           	{ if(strstr(entreePrinc->tablcar,"fonction_regul_")!=0) 
           	     {*(entreePrinc->entree) >> nom >> nom;
                  // on regarde si la courbe existe, si oui on récupère la référence 
                  if (lesCourbes1D.Existe(nom)) 
                     { fonc_regul = lesCourbes1D.Trouve(nom);}
                  else
                     { // sinon il faut la lire maintenant
                       string non_courbe("_");   
                       fonc_regul = Courbe1D::New_Courbe1D(non_courbe,Id_Nom_Courbe1D (nom.c_str()));
                       // lecture de la courbe
                       fonc_regul->LectDonnParticulieres_courbes (non_courbe,entreePrinc);
                      }; 
           	     }
              else
                { *(entreePrinc->entree) >> nom;
                  cout << "\n erreur en lecture du coefficient de pilotage de la regularisation, on attendait "
                       << " la chaine epsil= et on a lu: " << nom << endl ;
                  entreePrinc->MessageBuffer("erreur 1   ");
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie(1);
                 };
           	}
           else
             { cout << "\n erreur en lecture  de la regularisation, cas:  " << regularisation
                    << " non prevu  ";
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie(1);
             };
         } //-- fin de la lecture de la régularisation
        else if (nom != "fin_loi_frottement_coulomb_")
          { cout << "\n erreur en lecture le mot cle lu  " << nom << " est errone ou mal place " << endl ;
            entreePrinc->MessageBuffer("erreur 1   ");
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);
           };
        // -- lecture avec contrôle d'un nouveau mot clé ---  
        *(entreePrinc->entree) >> nom; 
        if (!((entreePrinc->entree)->rdstate() == 0)) // cas pb
          // pour mémoire ici on a 
           //       enum io_state
           //         {  badbit   = 1<<0, // -> 1 dans rdstate()
           //            eofbit   = 1<<1, // -> 2 
           //            failbit  = 1<<2, // -> 4 
           //            goodbit  = 0     // -> O 
           //          };
          {
          #ifdef ENLINUX 
            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;  // et on remplace le nom qui était erroné 
              }
          #else
            if ((entreePrinc->entree)->eof())
              // on a atteind la fin de la ligne
              {  // si ce n'est pas la fin de la lecture on appelle un nouvel enregistrement 
                 if (nom != "fin_loi_frottement_coulomb_")
                     entreePrinc->NouvelleDonnee();  // lecture d'un nouvelle enregistrement
                 *(entreePrinc->entree) >> nom; // il semble que finalement la lecture n'était pas bonne    
               }
          #endif  
            else // cas d'une erreur de lecture
             { cout << "\n erreur de lecture inconnue  ";
               entreePrinc->MessageBuffer("** lecture des données particulières CompFrotCoulomb **");
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie(1);
             };
         };
        // -- din lecture avec contrôle d'un nouveau mot clé ---  
      }while (nom != "fin_loi_frottement_coulomb_") ; 
    // prepa du flot de lecture pour la suite
    entreePrinc->NouvelleDonnee(); 
   }; 
   
// affichage de la loi
void CompFrotCoulomb::Affiche()  const 
  { cout << " \n loi de comportement de frottement de coulomb "; 
	 cout << "\n  mu_statique= " << mu_statique << "  ";
	 if (mu_cine != NULL)  { cout << " mu_cine= " <<  *mu_cine << " ";};
	 if (x_c != NULL)  { cout << " x_c= " <<  *x_c << " ";};
	 if (regularisation != 0)
	  { cout << "\n regularisation= " << regularisation ;
	    if (regularisation != 4)
	     {cout << " epsil= " << epsil << " ";}
	    else 
	     { cout << " fonction= " << fonc_regul->NomCourbe() <<" ";};
	  };
  };
                        
// affichage et definition interactive des commandes particulières à chaques lois
void CompFrotCoulomb::Info_commande_LoisDeComp(UtilLecture& entreePrinc)
 {  ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
	   cout << "\n definition standart (rep o) ou exemples exhaustifs (rep n'importe quoi) ? ";
	   string rep = "_";
    // procédure de lecture avec prise en charge d'un retour chariot
    rep = lect_return_defaut(true,"o");

    sort << "\n# ----------------------------------------------------------------------------------"
         << "\n# |......  loi de comportement de frottement de coulomb                 .......    |"
         << "\n# ----------------------------------------------------------------------------------"
         << "\n\n#           exemple de definition de loi"
         << "\n    mu_statique= 0.3                    "
         << "\n    fin_loi_frottement_coulomb_    \n" ;
  
    	 if ((rep != "o") && (rep != "O" ) && (rep != "0") )
      { sort << "\n#------------------------------------------------------------------------------------"
         << "\n#  mu_statique= le coefficient de frottement statique "
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  il est possible de definir une regularisation de la courbe de frottement    "
         << "\n#  exemple:  "
         << "\n#    mu_statique= 0.3                    "
         << "\n#    regularisation= 3   epsil= 1.  \n" 
         << "\n#    fin_loi_frottement_coulomb_    \n" 
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  regularisation= donne le type de regularisation que l'on desire:  en fonction de la vitesse"
         << "\n#  = 1: régularisation par morceau de droite fonction de la vitesse "
         << "\n#  = 2: régularisation quadratique; = 3: régularisation en tangente hyperbolique "
         << "\n#  = 4: régularisation par une fonction donnée par l'utilisateur f(norme(vitesse))" 
         << "\n#  epsil=  est le parametre de reglage de la regularisation " 
         << "\n#  exemple d'une regularisation de type 4:  "
         << "\n#    mu_statique= 0.3                   "
         << "\n#    regularisation= 4   fonction_regul_  courbe4 \n" 
         << "\n#    fin_loi_frottement_coulomb_    \n" 
         << "\n#------------------------------------------------------------------------------------"
         << "\n#    comme pour toutes les autres courbes dans les lois de comportement il est possible "
         << "\n#    de declarer directement la courbe au lieu de donner une reference   "
         << "\n#    a la fin de la description de la courbe, on doit revenir a la ligne    \n" 
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  on peut egalement introduire la notion de coefficient de frottement cinematique "
         << "\n#  exemple: "
         << "\n#    mu_statique= 0.3     mu_cine= 0.2  x_c= 2.               "
         << "\n#    regularisation= 4   fonction_regul_  courbe4 \n" 
         << "\n#    fin_loi_frottement_coulomb_    \n" 
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  mu_cine= est le coefficient de frottement cinematique  "
         << "\n#  x_c= regle le passage du frottement statique au frottement cinematique  "
         << "\n#        selon mu = mu_statique + (mu_statique-mu_cine)* exp(-x_c*V), V etant la vitesse tangente  "
         << "\n#------------------------------------------------------------------------------------";
       };
    sort << endl;
    // appel de la classe mère
    CompFrotAbstraite::Info_commande_don_LoisDeComp(entreePrinc);     
  };  		  	  

// test si la loi est complete
int CompFrotCoulomb::TestComplet()
    { int ret = LoiAbstraiteGeneral::TestComplet();
      if (mu_statique == -ConstMath::tresgrand) 
    	{ cout << "\n mu_statique n'est pas defini dans la loi de coulomb ";
    	  ret = 0;
    	};
      if (regularisation != 0)
       if (epsil == -ConstMath::tresgrand)
    	{ cout << "\n le parametre de reglage de la regularisation n'est pas defini dans la loi de coulomb ";
    	  ret = 0;
    	}
       else if (Dabs(epsil) < ConstMath::pasmalpetit)	
    	{ cout << "\n le parametre de reglage de la regularisation = " << epsil << " dans la loi de coulomb "
    	       << "est trop petit ! pour fonctionner correctement ";
    	  ret = 0;
    	}
       else if (epsil < 0.)	
    	{ cout << "\n le parametre de reglage de la regularisation = " << epsil << " dans la loi de coulomb "
    	       << "est negatif, ce qui n'est pas possible ";
    	  ret = 0;
    	};
       return ret; 
    }; 
    
	   //----- 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 CompFrotCoulomb::Lecture_base_info_loi(ifstream& ent,const int cas,LesReferences& lesRef,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  { string nom; 
	if (cas == 1)
	  { ent >> nom; 
	    if (nom != "LOI_COULOMB")
	     { cout << "\n erreur en lecture de la loi : LOI_COULOMB, on attendait le mot cle : LOI_COULOMB "
	            << "\n CompFrotCoulomb::Lecture_base_info_loi(...";
	       Sortie(1);
	      }
	    // ensuite normalement il n'y a pas de pb de lecture puisque c'est écrit automatiquement (sauf en debug)        
	    ent >> nom >> mu_statique; // mu_statique
	    // -- mu_cine --
	    bool test; ent >> nom >> test; 
	    if (!test)
	     // on efface le mu_cine s'il existe
	     { if (mu_cine != NULL) {delete mu_cine;mu_cine = NULL;};}
	    else
	     { // on crée éventuellement puis on lit 
	       if (mu_cine == NULL) mu_cine = new double ;
	       ent >> (*mu_cine);
	     };
	    // -- x_c --
	    ent >> nom >> test; 
	    if (!test)
	     // on efface le x_c s'il existe
	     { if (x_c != NULL) {delete x_c;x_c = NULL;};}
	    else
	     { // on crée éventuellement puis on lit 
	       if (x_c == NULL) x_c = new double ;
	       ent >> (*x_c);
	     };
        // -- regularisation --
        ent >> nom >> regularisation >> nom >> test;
	    if (!test)
	     { if (fonc_regul != NULL) 
	          {if (fonc_regul->NomCourbe() == "_") delete fonc_regul; fonc_regul = NULL;};
	      }
	    else
	     { ent >> nom; fonc_regul = lesCourbes1D.Lecture_pour_base_info(ent,cas,fonc_regul); };
	    // -- epsil --
	    ent >> nom >> test;
	    if (test)
	     { ent >> epsil;};
	  }
	 CompFrotAbstraite::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 CompFrotCoulomb::Ecriture_base_info_loi(ofstream& sort,const int cas)
{ if (cas == 1)
   { sort << " LOI_COULOMB " ;
	 sort << "\n  mu_statique= " << mu_statique << " mu_cine= ";
	 if (mu_cine == NULL) {sort << " 0 " ;} else { sort << " 1 " << *mu_cine << " ";};
	 sort << " x_c= " ;
	 if (x_c == 0) {sort << " 0 " ;} else { sort << " 1 " << *x_c << " ";};
	 sort << "\n regularisation= " << regularisation << " fonction= ";
     if (fonc_regul == NULL)
      { sort << false << " " ;}
     else 
      { sort << true << "  ";
        LesCourbes1D::Ecriture_pour_base_info(sort,cas,fonc_regul);
       }; 
	 sort << "\n  epsil= ";             
     if (epsil == -ConstMath::tresgrand)
      { sort << false << " ";}
     else 
      { sort << true << " " << epsil << " ";}; 
   };
  // appel de la classe mère
  CompFrotAbstraite::Ecriture_don_base_info(sort,cas);
  };
  
// ------------ METHODES VIRTUELLES PURES protegees -----------

    // calcul des efforts de frottement à un instant  t+deltat
    // les indices t se rapporte au pas précédent, sans indice au temps actuel
    // vit_T : vitesse, force_normale: force normale (à la cible) agissant sur le noeud projectile
    // force_tangente: force tangente (à la cible) agissant sur le noeud projectile
    // normale: la normale de contact  normée
    // energie_frottement: l'énergie échangée: élas=la totalité, viqueux et plas= uniquement le pas de temps 
    // delta_t : le pas de temps
    // F_frot: force de frottement calculé,
    // retour glisse: indique si oui ou non le noeud glisse
bool CompFrotCoulomb::Calcul_Frottement(const Coordonnee& vit_T, const Coordonnee& 
                                  ,const Coordonnee& force_normale,const Coordonnee& force_tangente
                                  ,EnergieMeca& energie_frottement,const double delta_t
                                  ,Coordonnee& F_frot)
	{ // on regarde si l'on doit tenir compte du frottement cinématique
	  double mu_frot = mu_statique; // init du frottement que l'on utilisera effectivement
	  double n_vit_T = vit_T.Norme();
	  bool glisse = false; // par défaut
	  if (mu_cine != NULL)
	  	{// le frottement dépend de la norme de la vitesse
	  	 mu_frot += (mu_statique - *mu_cine) * exp(-(*x_c)*n_vit_T);
	  	};
	  // on regarde si le frottement est régularisé ou pas
	  double n_f_tangente = force_tangente.Norme();
	  double n_f_normale = force_normale.Norme();
	  switch (regularisation)
	  { case 0:  // -- pas de régularisation ---
	  	{//  on regarde si le noeud glisse ou pas
	  	 if (n_f_tangente < Dabs(mu_frot)*n_f_normale)
	  	 	{// la force est correcte, il n'y a pas de glissement
	  	 	 glisse = false;
	  	 	 F_frot = force_tangente;
	  	 	}
	  	 else
	  	 	{// on est en dehors du cône de frottement, il faut donc modifier
	  	 	 // la force tangentielle
	  	 	 glisse = true; 
	  	     if (n_vit_T < ConstMath::pasmalpetit) // le déplacement est quasi_nulle
	  	     // on est obligé de considérer des cas particuliers car on ne peut pas
	  	     // utiliser la direction du déplacement, on va donc voir du coté 
	  	     // de la force tangentielle initiale
	  	       { if (n_f_tangente < ConstMath::pasmalpetit) // force également quasi-nulle
	  	       	   // on la laisse comme elle est mais en signalant le glissement
	  	       	   { F_frot = force_tangente;}
	  	         else // sinon on utilise la direction de la force
	  	       	   { F_frot = force_tangente *(mu_frot*n_f_normale/n_f_tangente);};	
	  	       }
	  	     else // cas normale, la vitesse est non nulle on l'utilise
	  	       	{ F_frot = vit_T * (-mu_frot*n_f_normale/n_vit_T);};
	  	     // mise à jour des énergies qui ici est uniquement plastique
	  	     // si le déplacement est nulle -> énergie nulle 
	  	     energie_frottement.ChangeDissipationPlastique((F_frot * vit_T)*delta_t);
	  	 	};
	  	 break;	
	  	}//-- fin du cas sans régularisation
	  	case 1: case 2: case 3: case  4: // -- régularisation avec une fonction de la vitesse ---
	  	{double fonct_phi = 0.;
	  	 switch (regularisation)
	  	  {case 1 :{ if      (n_vit_T < -epsil) {fonct_phi = -1.;}
	  	             else if (n_vit_T <  epsil) {fonct_phi = n_vit_T /(2.*epsil);}
	  	             else                     {fonct_phi = 1.;}
	  	             break;
	  	            }
	  	   case 2 :{fonct_phi = n_vit_T/sqrt(n_vit_T*n_vit_T + epsil*epsil); break;}
	  	   case 3 :{fonct_phi = tanh (n_vit_T/epsil); break;}
	  	   case 4 :{fonct_phi = fonc_regul->Valeur(n_vit_T); break;}
	  	  };
	  	 glisse = true; // systématiquement 
	  	 // on recherche une direction de mouvement
	  	 if (n_vit_T < ConstMath::pasmalpetit) // le déplacement est quasi_nulle
	  	 // on est obligé de considérer des cas particuliers car on ne peut pas
	  	 // utiliser la direction du déplacement, on va donc voir du coté 
	  	 // de la force tangentielle initiale
	  	   	{ if (n_f_tangente < ConstMath::pasmalpetit) // force également quasi-nulle
	  	   	  // on la laisse comme elle est mais en signalant le glissement
	  	   	  	{ F_frot = force_tangente;}
	  	   	  else // sinon on utilise la direction de la force
	  	   	    { F_frot = force_tangente * (mu_frot*n_f_normale*fonct_phi/n_f_tangente);};	
	  	   	}
	  	 else // cas normale: la vitesse est non nulle on l'utilise
	  	   	{ F_frot = vit_T * (-mu_frot*n_f_normale*fonct_phi/n_vit_T);};
	  	 // mise à jour des énergies qui ici est uniquement plastique 
	  	 // si le déplacement est nulle -> énergie nulle 
	  	 energie_frottement.ChangeDissipationPlastique((F_frot * vit_T)*delta_t);
	  	 break;	
	  	}//-- fin du cas régularisation avec une fonction de la vitesse ---
	  }; //--- fin du switch sur regularisation
	  // retour
	  return glisse;  
	};
        
    // calcul des efforts de frottement à un instant  t+deltat 
    // et ses variations  par rapport aux ddl de vitesse 
    // vit_T : vitesse, force_normale: force normale (à la cible) agissant sur le noeud projectile
    // force_tangente: force tangente (à la cible) agissant sur le noeud projectile
    // energie_frottement: l'énergie échangée: élas=la totalité, viqueux et plas= uniquement le pas de temps 
    // delta_t : le pas de temps
    // F_frot: force de frottement calculé, 
    // d_F_frot_vit: variation de la force de frottement par rapport aux coordonnées de vitesse
    // retour glisse: indique si oui ou non le noeud glisse
    bool CompFrotCoulomb::Calcul_DFrottement_tdt 
                   (const Coordonnee& vit_T, const Coordonnee& 
                   ,const Coordonnee& force_normale,const Coordonnee& force_tangente
                   ,EnergieMeca& energie_frottement,const double delta_t
                   ,Coordonnee& F_frot,Tableau <Coordonnee>& d_F_frot_vit)
	{ // on regarde si l'on doit tenir compte du frottement cinématique
	  double mu_frot = mu_statique; // init du frottement que l'on utilisera effectivement
	  double n_vit_T = vit_T.Norme();
	  bool glisse = false; // par défaut
	  int dima = vit_T.Dimension();
	  energie_frottement.Inita(0.); // init
	  Coordonnee d_mu_frot(dima);
	  if (mu_cine != NULL)
	  	{// le frottement dépend de la norme de la vitesse
	  	 double coef = (mu_statique - *mu_cine) * exp(-(*x_c)*n_vit_T);
	  	 mu_frot += coef;
	  	 d_mu_frot = vit_T * ((-(*x_c)/n_vit_T)*coef); 
	  	};
	  // init du tableau de variation
	  d_F_frot_vit.Change_taille(dima); // changement de taille éventuel
	  for (int i=1;i<=dima;i++) d_F_frot_vit(i).Zero();
	  // on regarde si le frottement est régularisé ou pas
	  double n_f_tangente = force_tangente.Norme();
	  double n_f_normale = force_normale.Norme();
	  switch (regularisation)
	  { case 0:  // -- pas de régularisation ---
	  	{//  on regarde si le noeud glisse ou pas
	  	 if (n_f_tangente < Dabs(mu_frot)*n_f_normale)
	  	 	{// la force est correcte, il n'y a pas de glissement
	  	 	 glisse = false;
	  	 	 F_frot = force_tangente;
	  	 	 // et la dépendance à la vitesse n'est pas due à la loi de contact
	  	 	}
	  	 else
	  	 	{// on est en dehors du cône de frottement, il faut donc modifier
	  	 	 // la force tangentielle
	  	 	 glisse = true; 
	  	     if (n_vit_T < ConstMath::pasmalpetit) // le déplacement est quasi_nulle
	  	     // on est obligé de considérer des cas particuliers car on ne peut pas
	  	     // utiliser la direction du déplacement, on va donc voir du coté 
	  	     // de la force tangentielle initiale, on laisse à zero la dépendance à la vitesse
	  	       { if (n_f_tangente < ConstMath::pasmalpetit) // force également quasi-nulle
	  	       	   // on la laisse comme elle est mais en signalant le glissement
	  	       	   { F_frot = force_tangente;}
	  	         else // sinon on utilise la direction de la force
	  	       	   { F_frot = force_tangente * (mu_frot*n_f_normale/n_f_tangente);};	
	  	       }
	  	     else // cas normale, la vitesse est non nulle on l'utilise
	  	       	{ F_frot = vit_T * (-mu_frot*n_f_normale/n_vit_T);
	  	          for (int i=1; i<= dima; i++)
	  	          	{ Coordonnee d_V(dima); d_V(dima)=1.; // var de V par rapport à V -> identité
	  	          	  d_F_frot_vit(i)= (Util::VarUnVect_coor(vit_T,d_V,n_vit_T) * mu_frot
	  	          	                    + vit_T/n_vit_T * d_mu_frot(i)) * (-n_f_normale);
	  	          	};
	  	         };
	  	     // mise à jour des énergies qui ici est uniquement plastique 
	  	     // si le déplacement est nulle -> énergie nulle 
	  	     energie_frottement.ChangeDissipationPlastique((F_frot * vit_T)*delta_t);
	  	 	};
	  	 break;	
	  	}//-- fin du cas sans régularisation
	  	case 1: case 2: case 3: case  4: // -- régularisation avec une fonction de la vitesse ---
	  	{double fonct_phi = 0.; double d_fonct_phi;
	  	 switch (regularisation)
	  	  {case 1 :{ if      (n_vit_T < -epsil) {fonct_phi = -1.;d_fonct_phi=0.;}
	  	             else if (n_vit_T <  epsil) {fonct_phi = n_vit_T /(2.*epsil);d_fonct_phi=1./(2.*epsil);}
	  	             else                     {fonct_phi = 1.;d_fonct_phi=0.;}
	  	             break;
	  	            }
	  	   case 2 :{ double w1=sqrt(n_vit_T*n_vit_T + epsil*epsil);  
	  	             fonct_phi = n_vit_T/w1; d_fonct_phi = 1./w1 * (1.- n_vit_T*n_vit_T / (w1*w1)); 
	  	             break;
	  	            }
	  	   case 3 :{fonct_phi = tanh (n_vit_T/epsil); 
	  	            d_fonct_phi = (1.-fonct_phi*fonct_phi);
	  	            break;
	  	            }
	  	   case 4 :{Courbe1D::ValDer valder=fonc_regul->Valeur_Et_derivee(n_vit_T);
	  	            fonct_phi = valder.valeur; d_fonct_phi = valder.derivee;
	  	            break;
	  	            }
	  	  };
	  	 glisse = true; // systématiquement 
	  	 // on recherche une direction de mouvement
	  	 if (n_vit_T < ConstMath::pasmalpetit) // le déplacement est quasi_nulle
	  	 // on est obligé de considérer des cas particuliers car on ne peut pas
	  	 // utiliser la direction du déplacement, on va donc voir du coté 
	  	 // de la force tangentielle initiale, on laisse à zero la dépendance à la vitesse
	  	   	{ if (n_f_tangente < ConstMath::pasmalpetit) // force également quasi-nulle
	  	   	  // on la laisse comme elle est mais en signalant le glissement
	  	   	  	{ F_frot = force_tangente;}
	  	   	  else // sinon on utilise la direction de la force
	  	   	    { F_frot = force_tangente * (mu_frot*n_f_normale*fonct_phi/n_f_tangente);};	
	  	   	}
	  	 else // cas normale: la vitesse est non nulle on l'utilise
	  	   	{ F_frot = vit_T * (-mu_frot*n_f_normale*fonct_phi/n_vit_T);
	  	 
	  	      for (int i=1; i<= dima; i++)
	  	        { Coordonnee d_V(dima); d_V(dima)=1.; // var de V par rapport à V -> identité
	  	          d_F_frot_vit(i)= (Util::VarUnVect_coor(vit_T,d_V,n_vit_T) * (mu_frot * fonct_phi)
	  	          	                + vit_T/n_vit_T * (d_mu_frot(i) * fonct_phi)
	  	          	                + vit_T/n_vit_T * (mu_frot * d_fonct_phi * vit_T(i)/n_vit_T)
	  	          	                ) * (-n_f_normale);
	  	        };
	  	    };
	  	 // mise à jour des énergies qui ici est  plastique et un peu élastique
	  	 // si le déplacement est nulle -> énergie nulle 
	  	 energie_frottement.ChangeDissipationPlastique((F_frot * vit_T)*delta_t);
	  	 double n_frot = F_frot.Norme();
	  	 // énergie élastique = 1/2 k x^2 = 1/2 F x
         energie_frottement.ChangeEnergieElastique(0.5 * n_frot * n_vit_T * delta_t);
	  	 break;	
	  	}//-- fin du cas régularisation avec une fonction de la vitesse ---
	  }; //--- fin du switch sur regularisation
	  // retour
	  return glisse;  
	};
  
  
  
  
  
