

// 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 "IsoHyper3DFavier3.h"
#include "ComLoi_comp_abstraite.h"

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


//================== initialisation des variables static ======================
// indicateur utilisé par Verif_Potentiel_et_var  
int IsoHyper3DFavier3::indic_Verif_PoGrenoble_et_var = 0;
double IsoHyper3DFavier3::limite_co2=700.; // limite à partir de laquelle on considère que cosh(co2) = infini
                                           // ici cosh(700.) = 5.0712e+303 !!

//================== fin d'initialisation des variables static ================

IsoHyper3DFavier3::IsoHyper3DFavier3 ()  : // Constructeur par defaut
 Hyper3D(ISOHYPER3DFAVIER3,CAT_MECANIQUE,false),K(ConstMath::trespetit),Qor(ConstMath::trespetit)
 ,mur(ConstMath::trespetit),mu_inf(ConstMath::trespetit)
 ,nQor(ConstMath::trespetit),gammaQor(ConstMath::trespetit)
 ,n_mu_inf(ConstMath::trespetit),gamma_mu_inf(ConstMath::trespetit)
    {};
// Constructeur de copie
IsoHyper3DFavier3::IsoHyper3DFavier3 (const IsoHyper3DFavier3& loi) :
  Hyper3D (loi),K(loi.K),Qor(loi.Qor),mur(loi.mur),mu_inf(loi.mu_inf)
  ,nQor(loi.nQor),gammaQor(loi.gammaQor)
  ,n_mu_inf(loi.n_mu_inf),gamma_mu_inf(loi.gamma_mu_inf)
	{};
  

// Lecture des donnees de la classe sur fichier
void IsoHyper3DFavier3::LectureDonneesParticulieres (UtilLecture * entreePrinc,LesCourbes1D&
             ,LesFonctions_nD& lesFonctionsnD)
  { // lecture des quatres coefficients de la loi
    *(entreePrinc->entree) >> K >> Qor >> mur >> mu_inf ;
    // on regarde ensuite s'il y a la phase
    if (strstr(entreePrinc->tablcar,"avec_phase")!=NULL)
     { // lecture des 4 paramètres de phase
       entreePrinc->NouvelleDonnee();  // passage d'une ligne
       *(entreePrinc->entree) >> nQor >> gammaQor >> n_mu_inf >> gamma_mu_inf ;
       avec_phase=true;
     };
    // cas avec régularisation (variable stockée dans Hyper3D.h)
    string nom1;
    if (strstr(entreePrinc->tablcar,"avec_regularisation_")!=NULL)
     { *(entreePrinc->entree) >> nom1 ;
       if (nom1 != "avec_regularisation_")
         { cout << "\n erreur en lecture du drapeau de regularisation, on attendait le mot cles "
             << " avec_regularisation_ on a lue: " << nom1 ;
           entreePrinc->MessageBuffer("**9--IsoHyper3DOrgeas1::LectureDonneesParticulieres(.....**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         };
       *(entreePrinc->entree) >> fact_regularisation;
       avec_regularisation=true;
     };
     // lecture de l'indication du post traitement
     string nom_class_methode = "IsoHyper3DFavier3";string le_mot_cle = "sortie_post_";
     entreePrinc->Lecture_un_parametre_int(0,nom_class_methode,0,1,le_mot_cle,sortie_post);
    // appel au niveau de la classe mère
    Loi_comp_abstraite::Lecture_type_deformation_et_niveau_commentaire
                 (*entreePrinc,lesFonctionsnD);

    };
// affichage de la loi
void IsoHyper3DFavier3::Affiche() const 
  { cout << " \n loi de comportement 3D hyperelastique isotrope favier3 : " << Nom_comp(id_comp)
         << " paramètres : \n"; 
    cout << " K= " << K << " ; Qor = " << Qor << " ; mur = " << mur << " ; mu_inf = " << mu_inf ; 
    if (avec_phase)
     { cout << "\n cas de la loi avec phase, parametre de la phase: "
            << " nQor= " << nQor << " gammaQor= " << gammaQor << " n_mu_inf= " 
            << n_mu_inf << " gamma_mu_inf= " << gamma_mu_inf;
      }
    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 IsoHyper3DFavier3::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# .......  loi de comportement 3D hyperelastique isotrope favier3  ........";
    if ((rep != "o") && (rep != "O" ) && (rep != "0") )
      { sort
         << "\n# **** exemple de cas AVEC la phase :"
         << "\n#------------------------------------------------------------------------------------"
         << "\n#     K         |     Qor     |       mur     |   mu_inf  | avec_phase(falculatif) |"
         << "\n#------------------------------------------------------------------------------------"
         << "\n     160000           150             17000       220           avec_phase"
         << "\n#-------------------------------------------------"
         << "\n#    n_Q    |    gamma_Q  |  n_mu  |   gamma_mu  |"
         << "\n#-------------------------------------------------"
         << "\n      0.25          0.4        0.25        0.4  "
         << "\n# **** exemple de cas SANS la phase :"
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  il est possible d'indiquer un facteur de regularisation qui permet d'eviter "
         << "\n#  de potentiels  problemes de NaN, de type division par 0 par exemple "
         << "\n#  1/a est remplace par 1/(a+fact_regularisation), par defaut fact_regularisation = 1.e-12 "
         << "\n#  pour indiquer un facteur de regulation non nul on indique en dernier parametre "
         << "\n#  le mot cle avec_regularisation_ suivi du facteur voulu "
         << "\n#  ex: "
         << "\n#    avec_regularisation_  1.e-12 "
         << "\n#  ce mot cle doit se situer avant le mot cle sortie_post_ "
         << "\n#------------------------------------------------------------------------------------"
         << "\n#  il est possible de recuperer differentes grandeurs de travail par exemple "
         << "\n#  l'intensite du potentiel, comme ces grandeurs sont calculees au moment de la resolution "
         << "\n#  et ne sont pas stockees, il faut indiquer le mot cle sortie_post_ suivi de 1 (par defaut = 0) "
         << "\n#  ensuite au moment de la constitution du .CVisu on aura acces aux grandeurs de travail "
         << "\n#  ex: "
         << "\n#    sortie_post_  1 "
         << "\n#  ce mot cle est le dernier des parametres specifiques de la loi il doit se situe "
         << "\n#  a la fin de la derniere ligne de donnees "
         << "\n#"
         << "\n#------------------------------------------------------------------------------------";         
      };
    sort << "\n#------------------------------------------------------------------------------------"
         << "\n#     K         |     Qor     |       mur     |   mu_inf  | avec_phase(falculatif) |"
         << "\n#------------------------------------------------------------------------------------"
         << "\n    160000           150             17000       220           "
         << endl;
    // appel de la classe Hyper3D
    Hyper3D::Info_commande_LoisDeComp_hyper3D(entreePrinc);
    // appel de la classe mère
    Loi_comp_abstraite::Info_commande_don_LoisDeComp(entreePrinc);     
  };  		  	  

// test si la loi est complete
int IsoHyper3DFavier3::TestComplet()
    { int ret = LoiAbstraiteGeneral::TestComplet();
      if ((K == ConstMath::trespetit) || (Qor == ConstMath::trespetit)  
      ||  (mur == ConstMath::trespetit)  ||  (mu_inf == ConstMath::trespetit))
       { cout << " \n Les paramètres ne sont pas défini pour  la loi " << Nom_comp(id_comp)
              << '\n';
         Affiche();     
         ret = 0;
       }
      if (avec_phase)
        if ((nQor == ConstMath::trespetit) || (gammaQor == ConstMath::trespetit)  
        ||  (n_mu_inf == ConstMath::trespetit)  ||  (gamma_mu_inf == ConstMath::trespetit))
         { cout << " \n Les paramètres de la phase ne sont pas défini pour  la loi " << Nom_comp(id_comp)
              << '\n';
         Affiche();     
         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 IsoHyper3DFavier3::Lecture_base_info_loi(ifstream& ent,const int cas,LesReferences& lesRef
                              ,LesCourbes1D& lesCourbe1D,LesFonctions_nD& lesFonctionsnD)
  { string toto; 
	if (cas == 1) 
	 { ent >> toto >> K >> toto >> Qor >> toto >> mur >> toto >> mu_inf >> avec_phase;
    if (avec_phase)
     { ent >> toto >> nQor >> toto >> gammaQor >> toto 
           >> n_mu_inf >> toto >> gamma_mu_inf;
     };
    // gestion du post-traitement
    ent >> toto >> sortie_post ;
  };
	// appel class mère  
	Loi_comp_abstraite::Lecture_don_base_info(ent,cas,lesRef,lesCourbe1D,lesFonctionsnD);
   };
       // cas donne le niveau de sauvegarde
       // = 1 : on sauvegarde tout
       // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void IsoHyper3DFavier3::Ecriture_base_info_loi(ofstream& sort,const int cas)
  { if (cas == 1) 
     { sort << "  module_dilatation " << K << " seuil " << Qor 
            << "  pente_origine " << mur << " pente_infini " << mu_inf << " avec_phase " << avec_phase;
       if (avec_phase)
        { sort << "\n nQor= " << nQor << " gammaQor= " << gammaQor << " n_mu_inf= " 
               << n_mu_inf << " gamma_mu_inf= " << gamma_mu_inf;
        };
       // gestion du post-traitement
       sort << " sortie_post= "<< sortie_post << " ";
     };
    // appel de la classe mère
    Loi_comp_abstraite::Ecriture_don_base_info(sort,cas);  
   }; 

// ===========  METHODES Protégées dérivant de virtuelles : ==============

//  METHODES internes spécifiques à l'hyperélasticité isotrope découlant de 
//  méthodes virtuelles de Hyper3D

    // calcul du potentiel tout seul sans la phase car Qeps est  nul
    // ou très proche de 0
double IsoHyper3DFavier3::PoGrenoble
             (const double & Qeps,const Invariant & inv)
 { // des variables intermédiaires
   double a = Qor/2./mur;
   double co1 = Qor*a;
   double co2 = Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder
   {// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   double E = K/6. * (logV)*(logV) 
       + co1*log_A + mu_inf * Qeps * Qeps;
   // retour
   return E;
   };

    // calcul du potentiel tout seul avec la phase donc dans le cas où Qeps est non nul
double IsoHyper3DFavier3::PoGrenoble
             (const Invariant0QepsCosphi & inv_spec,const Invariant & inv)
 { // dans le cas de l'existence de la phase, on modifie Qr et muinf
   double bmuinf,bQr,muinfF,Qr;
   if (avec_phase)
     {bmuinf = (1.+gamma_mu_inf*inv_spec.cos3phi);
      bQr = (1.+gammaQor*inv_spec.cos3phi);
      muinfF = mu_inf/ pow(bmuinf,n_mu_inf);
      Qr = Qor/pow(bQr,nQor);
      }
   else
     {bmuinf = 1.;
      bQr = 1.;
      muinfF = mu_inf;
      Qr = Qor;
      }
   // des variables intermédiaires
   double a = Qr/2./mur;
   double co1 = Qr*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   double E = K/6. * (logV)*(logV) 
       + co1*log_A + muinfF * inv_spec.Qeps * inv_spec.Qeps;
   // retour
   return E;
   };

    // calcul du potentiel tout seul sans la phase car Qeps est  nul
    // ou très proche de 0, et de sa variation suivant V uniquement
Hyper3D::PoGrenoble_V IsoHyper3DFavier3::PoGrenoble_et_V
             (const double & Qeps,const Invariant & inv)
 { PoGrenoble_V ret;
   // des variables intermédiaires
   double a = Qor/2./mur;
   double co1 = Qor*a;
   double co2 = Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + mu_inf * Qeps * Qeps;
   ret.EV = K/3.*logV/inv.V;
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };

    // calcul du potentiel et de sa variation suivant V uniquement
Hyper3D::PoGrenoble_V IsoHyper3DFavier3::PoGrenoble_et_V
             (const Invariant0QepsCosphi & inv_spec,const Invariant & inv)
 { Hyper3D::PoGrenoble_V ret;
   // dans le cas de l'existence de la phase, on modifie Qr et muinf
   double bmuinf,bQr,muinfF,Qr;
   if (avec_phase)
     {bmuinf = (1.+gamma_mu_inf*inv_spec.cos3phi);
      bQr = (1.+gammaQor*inv_spec.cos3phi);
      muinfF = mu_inf/ pow(bmuinf,n_mu_inf);
      Qr = Qor/pow(bQr,nQor);
      }
   else
     {bmuinf = 1.;
      bQr = 1.;
      muinfF = mu_inf;
      Qr = Qor;
      }
   //  des variables intermédiaires
   double a = Qr/2./mur;
   double co1 = Qr*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + muinfF * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };

    // calcul du potentiel tout seul sans la phase car Qeps est  nul
    // ou très proche de 0, et de ses variations première et seconde suivant V uniquement
Hyper3D::PoGrenoble_VV IsoHyper3DFavier3::PoGrenoble_et_VV
             (const double & Qeps,const Invariant & inv)
 { PoGrenoble_VV ret;
   // des variables intermédiaires
   double a = Qor/2./mur;
   double co1 = Qor*a;
   double co2 = Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées premières
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + mu_inf * Qeps * Qeps;
   ret.EV = K/3.*logV/inv.V;
   // dérivées secondes
   ret.EVV = K/3. * (1.-logV) / (inv.V * inv.V);
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };

    // calcul du potentiel et de sa variation première et seconde suivant V uniquement
Hyper3D::PoGrenoble_VV IsoHyper3DFavier3::PoGrenoble_et_VV
             (const Invariant0QepsCosphi & inv_spec,const Invariant & inv)
 { Hyper3D::PoGrenoble_VV ret;
   // dans le cas de l'existence de la phase, on modifie Qr et muinf
   double bmuinf,bQr,muinfF,Qr;
   if (avec_phase)
     {bmuinf = (1.+gamma_mu_inf*inv_spec.cos3phi);
      bQr = (1.+gammaQor*inv_spec.cos3phi);
      muinfF = mu_inf/ pow(bmuinf,n_mu_inf);
      Qr = Qor/pow(bQr,nQor);
      }
   else
     {bmuinf = 1.;
      bQr = 1.;
      muinfF = mu_inf;
      Qr = Qor;
      }
   // des variables intermédiaires
   double a = Qr/2./mur;
   double co1 = Qr*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées premières
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + muinfF * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
   // dérivées secondes
   ret.EVV = K/3. * (1.-logV) / (inv.V * inv.V);
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };

 // calcul du potentiel et de ses dérivées non compris la phase
Hyper3D::PoGrenobleSansPhaseSansVar IsoHyper3DFavier3::PoGrenoble
            (const InvariantQeps & inv_spec,const Invariant & inv)
 { PoGrenobleSansPhaseSansVar ret;
   // des variables intermédiaires
   double a = Qor/2./mur;
   double co1 = Qor*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + mu_inf * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
//   // dans le cas où l'on est très près de l'origine (voir nul)
//   // il faut un traitement particulier
//   if (co2 > ConstMath::unpeupetit)
    // cas normal
     ret.EQ = Qor * tanh(co2) + 2.* mu_inf * inv_spec.Qeps;
/*   else
    // cas ou  Qeps est très proche de zéro, on utilise un développement
    // limité  
     ret.EQ = (Qor/a + mu_inf)* inv_spec.Qeps 
              - 1./3. * Qor/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps; */ 
       
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };
   
   // calcul du potentiel et de ses dérivées avec la phase
Hyper3D::PoGrenobleAvecPhaseSansVar IsoHyper3DFavier3::PoGrenoblePhase
             (const InvariantQepsCosphi& inv_spec,const Invariant & inv) 
 { PoGrenobleAvecPhaseSansVar ret;
   // dans le cas de l'existence de la phase, on modifie Qr et muinf
   double bmuinf,bQr,muinfF,Qr;
   if (avec_phase)
     {bmuinf = (1.+gamma_mu_inf*inv_spec.cos3phi);
      bQr = (1.+gammaQor*inv_spec.cos3phi);
      muinfF = mu_inf/ pow(bmuinf,n_mu_inf);
      Qr = Qor/pow(bQr,nQor);
      }
   else
     {bmuinf = 1.;
      bQr = 1.;
      muinfF = mu_inf;
      Qr = Qor;
      }
   // des variables intermédiaires
   double a = Qr/2./mur;
   double co1 = Qr*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
   	 // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	}
   else
   	{ log_A = log(A);};
   double logV = log(inv.V);
   // le potentiel et ses dérivées
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + muinfF * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
//   // dans le cas où l'on est très près de l'origine (voir nul)
//   // il faut un traitement particulier
//   if (co2 > ConstMath::unpeupetit)
    // cas normal
     ret.EQ = Qr * tanh(co2) + 2.* muinfF * inv_spec.Qeps;
/*   else
    // cas ou  Qeps est très proche de zéro, on utilise un développement
    // limité  
     ret.EQ = (Qor/a + mu_inf)* inv_spec.Qeps 
              - 1./3. * Qor/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps; */ 
       
   // cas de la variation faisant intervenir  la phase
   double dEdmuinf= inv_spec.Qeps * inv_spec.Qeps;
   double dmuinf_dcos3phi = (- n_mu_inf * gamma_mu_inf * muinfF/bmuinf);
   double dQdcos3phi = (- nQor * gammaQor * Qr / bQr);
   ret.Ecos3phi = dEdmuinf * dmuinf_dcos3phi + ret.EQ * dQdcos3phi;
   ret.Ks = K / 3. *(logV/2. + 1.);
   
   // retour
   return ret;
   };
      

// calcul  du potentiel sans phase et dérivées avec  ses variations par rapport aux invariants
Hyper3D::PoGrenobleSansPhaseAvecVar IsoHyper3DFavier3::PoGrenoble_et_var
             (const Invariant2Qeps& inv_spec,const Invariant & inv)
 { PoGrenobleSansPhaseAvecVar ret;
   // des variables intermédiaires
   double a = Qor/2./mur;
   double co1 = Qor*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2); 
   double log_A=0.;
   double tanhco2 = 1.; // init par défaut
   if ((Abs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est //   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
     // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	 tanhco2 = 1.; // et dans ce cas on est à la limite : th(A) =(environ)= exp(co2)/exp(co2) = 1
   	}
   else
   	{ log_A = log(A);
      tanhco2 = tanh(co2);
    };
   double logV = log(inv.V);
   // le potentiel et ses dérivées premières
   ret.E = K/6. * (logV)*(logV) 
       + co1*log_A + mu_inf * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
   // dérivées secondes
   ret.EVV = K/3. * (1.-logV) / (inv.V * inv.V);
   ret.EQV = 0.;
   // dans le cas où l'on est très près de l'origine (voir nul)
   // il faut un traitement particulier
//   if (co2 > ConstMath::unpeupetit)
    // cas normal
    { ret.EQ = Qor * tanhco2 + 2.* mu_inf * inv_spec.Qeps;
      // dérivée seconde
      ret.EQQ = 2.*mur*(1. - tanhco2 * tanhco2) + 2.* mu_inf;
     }
/*   else
    // cas ou  Qeps est très proche de zéro, on utilise un développement
    // limité  
    { ret.EQ = (Qor/a + mu_inf)* inv_spec.Qeps 
              - 1./3. * Qor/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps;  
      // dérivée seconde
      ret.EQQ = (Qor/a + mu_inf) 
                - Qor/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps;  
     }*/
    // vérif des dérivées du potentiels par rapport aux invariants, ceci par différences finies
// ---      Verif_PoGrenoble_et_var(inv_spec.Qeps,inv,ret );

//--- débug: autre vérification à décommenter si on veut vérifier un nan événtuel !! --------------------
//   if ((Dabs(ret.E) > ConstMath::tresgrand) || (Dabs(ret.EV) > ConstMath::tresgrand)
//       || (Dabs(ret.EVV) > ConstMath::tresgrand) || (Dabs(ret.EQV) > ConstMath::tresgrand)
//       || (Dabs(ret.EQQ) > ConstMath::tresgrand) || (Dabs(ret.EQ) > ConstMath::tresgrand) )
//   	{ cout << "\n attention *** on a detecter un comportement bizarre sur le potentiel de la loi Favier3D "
//   	      << " potentiel= " << ret.E << " var/V= " << ret.EV << " var/Q= " << ret.EQ
//   	      << " var/VV= " << ret.EVV << " var/QQ= " << ret.EQQ  << " var/QV= " << ret.EQV << endl;
//   	};
//---- fin débug -----------------------------------------------------------------------------------------   	
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };
    
    // calcul  du potentiel avec phase et dérivées avec  ses variations par rapport aux invariants
Hyper3D::PoGrenobleAvecPhaseAvecVar IsoHyper3DFavier3::PoGrenoblePhase_et_var
             (const Invariant2QepsCosphi& inv_spec,const Invariant & inv)
 { Hyper3D::PoGrenobleAvecPhaseAvecVar ret;
   // dans le cas de l'existence de la phase, on modifie Qr et muinf
   double bmuinf,bQr,muinfF,Qr;
   if (avec_phase)
     {bmuinf = (1.+gamma_mu_inf*inv_spec.cos3phi);
      bQr = (1.+gammaQor*inv_spec.cos3phi);
      muinfF = mu_inf/ pow(bmuinf,n_mu_inf);
      Qr = Qor/pow(bQr,nQor);
      }
   else
     {bmuinf = 1.;
      bQr = 1.;
      muinfF = mu_inf;
      Qr = Qor;
      }
//debug
//cout << "\n debug: IsoHyper3DFavier3::PoGrenoblePhase_et_var "
//     << " Qr="<<Qr << "  Qor=" << Qor << " muinfF="<<muinfF <<"  mu_inf="<<mu_inf<<endl;
//fin debug
   // des variables intermédiaires
   double a = Qr/2./mur;
   double co1 = Qr*a;
   double co2 = inv_spec.Qeps/a ;
   double A = cosh(co2);
   double log_A=0.;
   double tanhco2 = 1.; // init par défaut
   if ((Dabs(co2) > limite_co2) || (!isfinite(A))) // en fait A est "toujours" très grand, donc c'est normal, et il vaut mieux regarder s'il est infini
//   if ((Dabs(A)>ConstMath::pasmalgrand)||(!isfinite(A)))
//   if (Dabs(A)>ConstMath::tresgrand)
   	{// si co2 est  grand (par exemple > 800 uniquement !!) ou très petit, comme cosh(co2) = (exp(co2) + exp(-co2))/2, on a exp(co2) = inf
   	 // ou exp(-co2) = inf
   	 // mais en fait on n'utilise que le log(A) donc on peut faire une approximation
   	 // soit co2 est grand 
     // on fait l'approximation que expo(-co2) est pratiquement nulle d'où cosh(co2) =(environ)= exp(co2)/2
   	 // d'où log(A) =(environ)= co2-log(2)
   	 log_A = MaX(0.,Dabs(co2)-log(2.));       
   	 tanhco2 = 1.; // et dans ce cas on est à la limite : th(A) =(environ)= exp(co2)/exp(co2) = 1
   	}
   else
   	{ log_A = log(A);
      tanhco2 = tanh(co2);
    };
//debug
//cout << "\n debug: 3DFavier3::Po..ePhase_et_var "
//     << " A="<< A << " co2="<< co2<< " log_A="<<log_A << "  log(A)=" << log(A) << " tanhco2="<<tanhco2 <<"  tanh(co2)="<<tanh(co2) <<endl;
//fin debug
   double logV = log(inv.V);
   double logCosh = log_A;
   double unsurmur=1./mur;
   // le potentiel et ses dérivées premières
   ret.E = K/6. * (logV)*(logV) 
       + co1*logCosh + muinfF * inv_spec.Qeps * inv_spec.Qeps;
   ret.EV = K/3.*logV/inv.V;
   // dérivées secondes
   ret.EVV = K/3. * (1.-logV) / (inv.V * inv.V);
   ret.EQV = 0.;
   // dans le cas où l'on est très près de l'origine (voir nul)
   // il faut un traitement particulier
//   if (co2 > ConstMath::unpeupetit)
    // cas normal
    { ret.EQ = Qr * tanhco2 + 2.* muinfF * inv_spec.Qeps;
      // dérivée seconde
      ret.EQQ = 2.*mur*(1. - tanhco2 * tanhco2) + 2.* muinfF;
     }
/*   else
    // cas ou  Qeps est très proche de zéro, on utilise un développement
    // limité  
    { ret.EQ = (Qr/a + muinfF)* inv_spec.Qeps 
              - 1./3. * Qr/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps;  
      // dérivée seconde
      ret.EQQ = (Qr/a + muinfF) 
                - Qr/(a*a*a) 
                      * inv_spec.Qeps * inv_spec.Qeps * inv_spec.Qeps;  
     }*/

   // cas de la variation première par rapport à la phase
   double dEdQr= Qr*unsurmur * logCosh - inv_spec.Qeps * tanhco2;
   double QepsSurQr = inv_spec.Qeps/Qr;
   double tanhco2_2=tanhco2*tanhco2;
   double dEdmuinf= inv_spec.Qeps * inv_spec.Qeps;
   double dmuinf_dcos3phi = (- n_mu_inf * gamma_mu_inf * muinfF/bmuinf);
   double dQdcos3phi = (- nQor * gammaQor * Qr / bQr);
   ret.Ecos3phi = dEdmuinf * dmuinf_dcos3phi + dEdQr * dQdcos3phi;
   // cas des variations seconde faisant intervenir la phase la phase
   double d2EdQr2=unsurmur*logCosh-2.* QepsSurQr * tanhco2 + co2*QepsSurQr*(1.-tanhco2_2);
   double d2muinf_dcos3phi_2 = n_mu_inf*(1.+n_mu_inf)* muinfF*gamma_mu_inf*gamma_mu_inf/bmuinf/bmuinf;
   double d2Qr_dcos3phi_2  = nQor*(1.+nQor)*Qr*gammaQor*gammaQor/bQr/bQr;
   double d2E_dQ_dmuinf = 2. * inv_spec.Qeps ;
   double d2E_dQ_dQr = tanhco2 - co2 * (1.-tanhco2_2);
   
   ret.EVcos3phi= 0.;
   ret.EQcos3phi= d2E_dQ_dmuinf * dmuinf_dcos3phi + d2E_dQ_dQr * dQdcos3phi;
   ret.Ecos3phi2= d2EdQr2 * ret.Ecos3phi * ret.Ecos3phi + dEdmuinf * d2muinf_dcos3phi_2 
                  + dEdQr * d2Qr_dcos3phi_2;
/*   ret.EVcos3phi= 0.;
   ret.EQcos3phi= 0.;
   ret.Ecos3phi2= 0.;
   ret.Ecos3phi = 0.;*/

   // vérif des dérivées du potentiels par rapport aux invariants, ceci par différences finies
// ---   Verif_PoGrenoble_et_var(inv_spec.Qeps,inv,inv_spec.cos3phi,ret );
// ---   Invariant2Qeps toto(inv_spec.Qeps,inv_spec.dQepsdbIIb,inv_spec.dQepsdbIIb2);
// ---   Hyper3D::PoGrenobleSansPhaseAvecVar truc = PoGrenoble_et_var(toto,inv);
   ret.Ks = K / 3. *(logV/2. + 1.);
   // retour
   return ret;
   };
 
              
///=============== fonctions pour la vérification et la mise au point ===============
    
    // vérif des dérivées du potentiels par rapport aux invariants, ceci par différences finies
void IsoHyper3DFavier3::Verif_PoGrenoble_et_var
            (const double & Qeps,const Invariant & inv
               ,const PoGrenobleSansPhaseAvecVar& potret )
  { // dans le cas du premier passage on indique qu'il y a vérification
    if (indic_Verif_PoGrenoble_et_var == 0)
     { cout << "\n ****vérification des dérivées du potentiels par rapport aux invariants****";
       cout << "\n IsoHyper3DFavier3::Verif_PoGrenoble_et_var \n";
      } 
    indic_Verif_PoGrenoble_et_var++;
    // potret contiend le potentiel et ses variations première et seconde
    // on va calculer ces mêmes variations par différences finies et comparer les deux résultats
    // calcul des invariants sous la nouvelle forme
    
    double toto = potret.E; // pour que le débugger affiche potret
    
    Invariant inv_n0(inv.Ieps,inv.V,inv.bIIb,inv.bIIIb); // recopie des invariants sans les varddl 
    double E_n = PoGrenoble(Qeps,inv_n0);  // la valeur du potentiel de référence
    // ici on est sans phase donc deux invariants indépendant V et Qeps,
    // pour calculer les variations on définit des points distants d'un incrément puis de deux incréments
    // pour les dérivées premières et secondes
    double delta = ConstMath::unpeupetit;
    double Qeps_et_dQeps = Qeps+delta;
    double E_et_dQeps = PoGrenoble(Qeps_et_dQeps,inv_n0);
    
    double Qeps_et_dQeps2 = Qeps + 2.*delta;
    double E_et_dQeps2 = PoGrenoble(Qeps_et_dQeps2,inv_n0);
    
    Invariant inv_et_dV = inv_n0;inv_et_dV.V += delta;
    double E_et_dV = PoGrenoble(Qeps,inv_et_dV);
    
    Invariant inv_et_dV2 = inv_n0;inv_et_dV2.V += 2. * delta;
    double E_et_dV2 = PoGrenoble(Qeps,inv_et_dV2);
    
    Invariant inv_et_dVdQeps = inv_n0;
    inv_et_dVdQeps.V += delta;
    double Qeps_et_dVdQeps = Qeps+delta;
    double E_et_dVdQeps = PoGrenoble(Qeps_et_dVdQeps,inv_et_dVdQeps);
    // calcul des dérivées premières
    double E_V = (E_et_dV  - E_n)/delta;
    double E_Qeps = (E_et_dQeps - E_n)/delta;
    // calcul des dérivées secondes
    double E_V2 = (E_et_dV2 - 2.*E_et_dV  + E_n ) /(delta * delta);
    double E_Qeps2 = (E_et_dQeps2 - 2.*E_et_dQeps + E_n)/(delta * delta);
    double E_V_a_dQeps = (E_et_dVdQeps  - E_et_dQeps )/delta;
    double E_VQeps = ( E_V_a_dQeps - E_V)/delta;
    // comparaison avec les valeurs de dérivées analytiques
    bool erreur = false;
    if (diffpourcent(potret.EV,E_V,MaX(Dabs(E_V),Dabs(potret.EV)),0.05))
     {if (MiN(Dabs(E_V),Dabs(potret.EV)) == 0.)
        {if ( MaX(Dabs(E_V),Dabs(potret.EV)) > 50.*delta) erreur = true;}
      else 
        erreur = true;}  
    if (diffpourcent(potret.EQ,E_Qeps,MaX(Dabs(E_Qeps),Dabs(potret.EQ)),0.05)) 
     {if (MiN(Dabs(E_Qeps),Dabs(potret.EQ)) == 0.)
        {if ( MaX(Dabs(E_Qeps),Dabs(potret.EQ)) > 50.*delta) erreur = true;}
      else 
        erreur = true;}  
    if (diffpourcent(potret.EQQ,E_Qeps2,MaX(Dabs(E_Qeps2),Dabs(potret.EQQ)),0.05)) 
     {if (MiN(Dabs(E_Qeps2),Dabs(potret.EQQ)) == 0.)
        {if ( MaX(Dabs(E_Qeps2),Dabs(potret.EQQ)) > 50.*delta) erreur = true;}
      else 
        erreur = true;}  
    if (diffpourcent(potret.EVV,E_V2,MaX(Dabs(E_V2),Dabs(potret.EVV)),0.05)) 
     {if (MiN(Dabs(E_V2),Dabs(potret.EVV)) == 0.)
        {if ( MaX(Dabs(E_V2),Dabs(potret.EVV)) > 50.*delta) erreur = true;}
      else 
        erreur = true;}
    if (diffpourcent(potret.EQV,E_VQeps,MaX(Dabs(E_VQeps),Dabs(potret.EQV)),0.05)) 
     {if (MiN(Dabs(E_VQeps),Dabs(potret.EQV)) == 0.)
      {if (Dabs(potret.EQV) == 0.)
         // si la valeur de la dérivée numérique est nulle cela signifie peut-être
         // que l'on est à un extréma, la seule chose que le l'on peut faire est de
         // vérifier que l'on tend numériquement vers cette extréma ici un minima
         {
           Invariant inv_et_ddVddQeps = inv_n0;
           inv_et_ddVddQeps.V += delta/10.;
           double Qeps_et_ddVddQeps = Qeps+delta/10.;
           double E_et_ddVddQeps = PoGrenoble(Qeps_et_ddVddQeps,inv_et_ddVddQeps);
           double Qeps_et_ddQeps = Qeps+delta/10.;
           double E_et_ddQeps = PoGrenoble(Qeps_et_ddQeps,inv_n0);
           double E_V_a_ddQeps = (E_et_ddVddQeps  - E_et_ddQeps )/(delta*10.);
           if (10.* Dabs(E_V_a_ddQeps) > Dabs(E_V_a_dQeps)) erreur = true;
          }
       else 
         if ( MaX(Dabs(E_VQeps),Dabs(potret.EQV)) > 150.*delta) erreur = true;
       }  
      else 
        erreur = true;
      }  
    if (erreur)
     { cout << "\n erreur dans le calcul analytique des derivees du potentiel";
       cout << "\n IsoHyper3DFavier3::Verif_PoGrenoble_et_var(.."
            << " , numero d'increment = " << indic_Verif_PoGrenoble_et_var;
       Sortie(1);
      } 
 };
    // vérif des dérivées du potentiels par rapport aux invariants, ceci par différences finies
void IsoHyper3DFavier3::Verif_PoGrenoble_et_var
            (const double & Qeps,const Invariant & inv,const double& cos3phi
               ,const PoGrenobleAvecPhaseAvecVar& potret )
  { // dans le cas du premier passage on indique qu'il y a vérification
    if (indic_Verif_PoGrenoble_et_var == 0)
     { cout << "\n ****vérification des dérivées du potentiels par rapport aux invariants****";
       cout << "\n IsoHyper3DFavier3::Verif_PoGrenoble_et_var \n";
      } 
    indic_Verif_PoGrenoble_et_var++;
    // potret contiend le potentiel et ses variations première et seconde
    // on va calculer ces mêmes variations par différences finies et comparer les deux résultats
    // calcul des invariants sous la nouvelle forme
    
    double toto = potret.E; // pour que le débugger affiche potret
    
    Invariant inv_n0(inv.Ieps,inv.V,inv.bIIb,inv.bIIIb); // recopie des invariants sans les varddl 
    Invariant0QepsCosphi invcos3phi(Qeps,cos3phi);
    double E_n = PoGrenoble(invcos3phi,inv_n0);  // la valeur du potentiel de référence
    // ici on est sans phase donc deux invariants indépendant V et Qeps,
    // pour calculer les variations on définit des points distants d'un incrément puis de deux incréments
    // pour les dérivées premières et secondes
    double delta = 10.*ConstMath::unpeupetit;
    double Qeps_et_dQeps = Qeps+delta;
    Invariant0QepsCosphi invcos3phi1(Qeps_et_dQeps,cos3phi);
    double E_et_dQeps = PoGrenoble(invcos3phi1,inv_n0);
    
    double Qeps_moins_dQeps = Qeps - delta;
    Invariant0QepsCosphi invcos3phi2(Qeps_moins_dQeps,cos3phi);
    double E_moins_dQeps = PoGrenoble(invcos3phi2,inv_n0);
    
    Invariant inv_et_dV = inv_n0;inv_et_dV.V += delta;
    double E_et_dV = PoGrenoble(invcos3phi,inv_et_dV);
    
    Invariant inv_moins_dV = inv_n0;inv_moins_dV.V -=  delta;
    double E_moins_dV = PoGrenoble(invcos3phi,inv_moins_dV);
    
    Invariant inv_et_dVdQeps = inv_n0;
    inv_et_dVdQeps.V += delta;
    double Qeps_et_dVdQeps = Qeps+delta;
    Invariant0QepsCosphi invcos3phi3(Qeps_et_dVdQeps,cos3phi);
    double E_et_dVdQeps = PoGrenoble(invcos3phi3,inv_et_dVdQeps);
    
    // cas des variations avec cos3phi    
    double cos3phi_et_dcos3phi = cos3phi+delta;
    Invariant0QepsCosphi invcos3phi_et_dcos3phi(Qeps,cos3phi_et_dcos3phi);
    double E_et_dcos3phi = PoGrenoble(invcos3phi_et_dcos3phi,inv_n0);
    
    double cos3phi_moins_dcos3phi = cos3phi-delta;
    Invariant0QepsCosphi invcos3phi_moins_dcos3phi(Qeps,cos3phi_moins_dcos3phi);
    double E_moins_dcos3phi = PoGrenoble(invcos3phi_moins_dcos3phi,inv_n0);
    
    Invariant0QepsCosphi invcos3phi_et_dcos3phi_a_dQeps(Qeps_et_dQeps,cos3phi_et_dcos3phi);
    double E_et_dcos3phi_a_dQeps = PoGrenoble(invcos3phi_et_dcos3phi_a_dQeps,inv_n0);
    
    double E_et_dcos3phi_a_dV = PoGrenoble(invcos3phi_et_dcos3phi,inv_et_dV);
    
    
    // calcul des dérivées premières
    double E_V = (E_et_dV  - E_n)/delta;
    double E_Qeps = (E_et_dQeps - E_n)/delta;
    double E_cos3phi = (E_et_dcos3phi -E_n)/delta;
    // calcul des dérivées secondes
    double E_V2 = (E_et_dV - 2.*E_n  + E_moins_dV ) /(delta * delta);
    double E_Qeps2 = (E_et_dQeps - 2.*E_n + E_moins_dQeps)/(delta * delta);
    double E_V_a_dQeps = (E_et_dVdQeps  - E_et_dQeps )/delta;
    double E_VQeps = ( E_V_a_dQeps - E_V)/delta;
    double E_cos3phi_2 = (E_et_dcos3phi - 2.*E_n  + E_moins_dcos3phi ) /(delta * delta);
    double E_dQeps_a_dcos3phi = (E_et_dcos3phi_a_dQeps  - E_et_dcos3phi )/delta;
    double E_dcos3phi_dQeps = (E_dQeps_a_dcos3phi  - E_Qeps )/delta;
    double E_dV_a_dcos3phi = (E_et_dcos3phi_a_dV  - E_et_dcos3phi )/delta;
    double E_dcos3phi_dV = (E_dV_a_dcos3phi  - E_V )/delta;

 // dans les dérivées secondes par rapport à cos3phi on a des erreurs, sans doute à cause des petites valeurs ??
  
    // comparaison avec les valeurs de dérivées analytiques
    int erreur = 0;
    if (diffpourcent(potret.EV,E_V,MaX(Dabs(E_V),Dabs(potret.EV)),0.05))
     {if (MiN(Dabs(E_V),Dabs(potret.EV)) == 0.)
        {if ( MaX(Dabs(E_V),Dabs(potret.EV)) > 50.*delta) erreur = 1;}
      else 
       erreur = 2; } 
    if (diffpourcent(potret.EQ,E_Qeps,MaX(Dabs(E_Qeps),Dabs(potret.EQ)),0.05)) 
     {if (MiN(Dabs(E_Qeps),Dabs(potret.EQ)) == 0.)
        {if ( MaX(Dabs(E_Qeps),Dabs(potret.EQ)) > 50.*delta) erreur = 3;}
      else 
        erreur = 4;}        
    if (diffpourcent(potret.Ecos3phi,E_cos3phi,MaX(Dabs(E_cos3phi),Dabs(potret.Ecos3phi)),0.05)) 
     {if (MiN(Dabs(E_cos3phi),Dabs(potret.Ecos3phi)) == 0.)
        {if ( MaX(Dabs(E_cos3phi),Dabs(potret.Ecos3phi)) > 50.*delta) erreur = 31;}
      else 
        erreur = 41;}
    if (diffpourcent(potret.EQQ,E_Qeps2,MaX(Dabs(E_Qeps2),Dabs(potret.EQQ)),0.05)) 
     {if (MiN(Dabs(E_Qeps2),Dabs(potret.EQQ)) == 0.)
        {if ( MaX(Dabs(E_Qeps2),Dabs(potret.EQQ)) > 50.*delta) erreur = 5;}
      else 
        erreur = 6;}  
    if (diffpourcent(potret.EVV,E_V2,MaX(Dabs(E_V2),Dabs(potret.EVV)),0.05)) 
     {if (MiN(Dabs(E_V2),Dabs(potret.EVV)) == 0.)
        {if ( MaX(Dabs(E_V2),Dabs(potret.EVV)) > 50.*delta) erreur = 7;}
      else 
        erreur = 8;}        
    if (diffpourcent(potret.Ecos3phi2,E_cos3phi_2,MaX(Dabs(E_cos3phi_2),Dabs(potret.Ecos3phi2)),0.05)) 
     {if (MiN(Dabs(E_cos3phi_2),Dabs(potret.Ecos3phi2)) == 0.)
        {if ( MaX(Dabs(E_cos3phi_2),Dabs(potret.Ecos3phi2)) > 50.*delta) erreur = 71;}
      else 
        erreur = 81;}
    if (diffpourcent(potret.EQV,E_VQeps,MaX(Dabs(E_VQeps),Dabs(potret.EQV)),0.05)) 
     {if (MiN(Dabs(E_VQeps),Dabs(potret.EQV)) == 0.)
      {if (Dabs(potret.EQV) == 0.)
         // si la valeur de la dérivée numérique est nulle cela signifie peut-être
         // que l'on est à un extréma, la seule chose que le l'on peut faire est de
         // vérifier que l'on tend numériquement vers cette extréma ici un minima
         {
           Invariant inv_et_ddVddQeps = inv_n0;
           inv_et_ddVddQeps.V += delta/10.;
           double Qeps_et_ddVddQeps = Qeps+delta/10.;
           double E_et_ddVddQeps = PoGrenoble(Qeps_et_ddVddQeps,inv_et_ddVddQeps);
           double Qeps_et_ddQeps = Qeps+delta/10.;
           double E_et_ddQeps = PoGrenoble(Qeps_et_ddQeps,inv_n0);
           double E_V_a_ddQeps = (E_et_ddVddQeps  - E_et_ddQeps )/(delta*10.);
           if (10.* Dabs(E_V_a_ddQeps) > Dabs(E_V_a_dQeps)) erreur = 9;
          }
       else 
         if ( MaX(Dabs(E_VQeps),Dabs(potret.EQV)) > 150.*delta) erreur = 10;
        } 
      else 
        erreur = 11;
      }
      
    if (diffpourcent(potret.EVcos3phi,E_dcos3phi_dV,MaX(Dabs(E_dcos3phi_dV),Dabs(potret.EVcos3phi)),0.05)) 
     {if (MiN(Dabs(E_dcos3phi_dV),Dabs(potret.EVcos3phi)) == 0.)
      {if (Dabs(potret.EVcos3phi) == 0.)
         // si la valeur de la dérivée numérique est nulle cela signifie peut-être
         // que l'on est à un extréma, la seule chose que le l'on peut faire est de
         // vérifier que l'on tend numériquement vers cette extréma ici un minima
         {
           /*Invariant inv_et_ddVddQeps = inv_n0;
           inv_et_ddVddQeps.V += delta/10.;
           double Qeps_et_ddVddQeps = Qeps+delta/10.;
           double E_et_ddVddQeps = PoGrenoble(Qeps_et_ddVddQeps,inv_et_ddVddQeps);
           double Qeps_et_ddQeps = Qeps+delta/10.;
           double E_et_ddQeps = PoGrenoble(Qeps_et_ddQeps,inv_n0);
           double E_V_a_ddQeps = (E_et_ddVddQeps  - E_et_ddQeps )/(delta*10.);
           if (10.* Dabs(E_V_a_ddQeps) > Dabs(E_V_a_dQeps))*/ erreur = 91;
          }
       else 
         if ( MaX(Dabs(E_dcos3phi_dV),Dabs(potret.EVcos3phi)) > 150.*delta) erreur = 101;
        } 
      else 
        erreur = 111;
      }
      
    if (diffpourcent(potret.EQcos3phi,E_dcos3phi_dQeps,MaX(Dabs(E_dcos3phi_dQeps),Dabs(potret.EQcos3phi)),0.05)) 
     {if (MiN(Dabs(E_dcos3phi_dQeps),Dabs(potret.EQcos3phi)) == 0.)
      {if (Dabs(potret.EQcos3phi) == 0.)
         // si la valeur de la dérivée numérique est nulle cela signifie peut-être
         // que l'on est à un extréma, la seule chose que le l'on peut faire est de
         // vérifier que l'on tend numériquement vers cette extréma ici un minima
         {
           /*Invariant inv_et_ddVddQeps = inv_n0;
           inv_et_ddVddQeps.V += delta/10.;
           double Qeps_et_ddVddQeps = Qeps+delta/10.;
           double E_et_ddVddQeps = PoGrenoble(Qeps_et_ddVddQeps,inv_et_ddVddQeps);
           double Qeps_et_ddQeps = Qeps+delta/10.;
           double E_et_ddQeps = PoGrenoble(Qeps_et_ddQeps,inv_n0);
           double E_V_a_ddQeps = (E_et_ddVddQeps  - E_et_ddQeps )/(delta*10.);
           if (10.* Dabs(E_V_a_ddQeps) > Dabs(E_V_a_dQeps))*/ erreur = 92;
          }
       else 
         if ( MaX(Dabs(E_dcos3phi_dQeps),Dabs(potret.EQcos3phi)) > 150.*delta) erreur = 102;
        } 
      else 
        erreur = 112;
      }
      
        
    if (erreur > 0)
     { cout << "\n erreur dans le calcul analytique des derivees du potentiel";
       cout << "\n IsoHyper3DFavier3::Verif_PoGrenoble_et_var(.."
            << " , numero d'increment = " << indic_Verif_PoGrenoble_et_var
            << " , numero d'erreur : " << erreur ;
 //      Sortie(1);
      } 
 };
