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


#include "Algori.h"
#include "string"
#include "MathUtil.h"
#include <iostream>   //  pour utiliser la classe istrstream
#include <strstream>  //      nouveau dans CW5.3


//====================================================================================================== 
//                 troisième fichier pour l'implantation des méthodes d'Algori       
//======================================================================================================


// lecture des paramètres du calcul généraux pour tous les algos (dans le cas où il y en a)
// qui peuvent éventuellement ne pas servir !!
void Algori::lecture_Parametres(UtilLecture& entreePrinc)
{ bool a_lire = false;
  MotCle motCle; // ref aux mots cle
  // dans le cas où l'entête des paramètres n'a pas été lue par l'algorithme spécifique
  // on regarde s'il existe
  if (deja_lue_entete_parametre == 2)
   // on peut directement lire
   {a_lire = true;}
  else  // sinon
   { // deux cas suivant que l'algo spécifique a une méthode de lecture de paramètre ou non
     if (deja_lue_entete_parametre == 0)
       { // cas ou l'algo spécifique n'a pas de méthode de lecture de paramètre donc il n'y a pas
         // eu d'essai de lecture de l'entête 
         // on se positionne sur le prochain mot clé
         do { entreePrinc.NouvelleDonnee();}
         while ( !motCle.SimotCle(entreePrinc.tablcar)) ;
         // si le mot clé est "PARA_TYPE_DE_CALCUL" cela signifie 
         // qu'il y a une zone de paramètre éventuellement  à lire
         if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL) 
          {entreePrinc.NouvelleDonnee();
           a_lire = true;
           }
         else // sinon le mot clé ne concerne pas les paramètres il n'y a rien n'a lire
          {a_lire = false;
          };
       }
     else if (deja_lue_entete_parametre == 1) 
       { // cas ou l'algo spécifique a une méthode de lecture de paramètre donc il a
           // déjà essayer de lire  l'entête et n'a rien trouvé: il n'y a rien n'a lire
           a_lire = false;
         }
     else
       { cout << "\n erreur deja_lue_entete_parametre = " << deja_lue_entete_parametre
              << " alors qu'il devrait etre soit 1 ou 0 ou 2 !! "
              << "\n Algori::lecture_Parametres(....";
         // dans le cas où un comptage du calcul est en cours on l'arrête
         if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
         if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
         Sortie(1);
       };
   };
  // maintenant on lit en fonction du booléen a_lire     
  if (a_lire)
  {// on s'arrête lorsqu'il n'y a plus de mot clé spécifique à lire
		 while (    (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL)
				  || (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL)
				  || (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL)
				  || (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL)
				  || (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL)
      || (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL)
      || (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL)
				 ) 
						 
		 {bool lecture_effective = false;
    string nom_class_methode("Algori::lecture_Parametres((..."); // pour la lecture
    int min=1,max=0;string mot_cle;int int_defaut=0; double double_defaut=0;// variables inter qui servent pour la lecture
			 //=== parametres de controle du calcul de la matrice de viscosite =====
    if (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL)
     { mot_cle="parametre_calcul_de_la_viscosite_";
       lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
       // si on arrive ici c'est que l'on a bien lue le mot clé "parametre_calcul_de_la_viscosite_"
       // donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen
       
       // --- lecture éventuelle de type_calcul_visqu_critique
       int_defaut=0; mot_cle="type_calcul_visqu_critique="; min=1;max=3; 
       entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,type_calcul_visqu_critique);
       // on change le paramètre de viscosité numérique général en conséquence
       if (type_calcul_visqu_critique)
         pa.Change_amort_visco_artificielle(4); // on indique qu'il s'agit d'une gestion par un amortissement visqueux critique 
        // utilisé par de la relaxation dynamique
       // --- lecture éventuelle de opt_cal_C_critique
       int_defaut=-1; mot_cle="opt_cal_C_critique="; min=-1;max=2; 
       entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,opt_cal_C_critique);
       // --- lecture éventuelle de f_
       double_defaut=1.; mot_cle="f_="; min=1;max=0; 
       entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,f_);
       // --- lecture éventuelle de ampli_visco
       double_defaut=1.; mot_cle="ampli_visco_="; min=1;max=0; 
       entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,ampli_visco);
     };
//			else // sinon on met les valeurs par défaut
//				{ type_calcul_visqu_critique= 0;
//				  opt_cal_C_critique= 1; f_= 1.; ampli_visco= 1.;
//				};
    //===  cas où l'on veut de l'amortissement cinétique global avec éventuellement des paramètres particuliers de contrôle
    if (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL)
     { mot_cle="avec_amortissement_cinetique_";
       entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
       amortissement_cinetique=true; // on active l'amortissement cinétique
       string st1;
       // lecture des paramètres de l'amortissement cinétique
       while (st1 != "fi_parametre_amortissement_cinetique_")
       { entreePrinc.NouvelleDonnee();
       *(entreePrinc.entree) >> st1; 
       if (st1 == "max_nb_decroit_pourRelaxDyn_")
        {*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn; }
       else if (st1 == "inter_nb_entre_relax_")
          {// il faut que l'on regarde s'il y a éventuellement un remplacement par une
           // fonction nD
           if (strstr(entreePrinc.tablcar,"nom_fct_nD_inter_nb_entre_relax_")!=NULL)
             {mot_cle="nom_fct_nD_inter_nb_entre_relax_";
              entreePrinc.Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_fct_nD_inter_nb_entre_relax);
             }
           else // cas sans fonction nD
             {nom_fct_nD_inter_nb_entre_relax="";
              *(entreePrinc.entree) >> inter_nb_entre_relax;
             };
          }
       else if (st1 == "taille_moyenne_glissante_")
          {*(entreePrinc.entree) >> taille_moyenne_glissante;}
       else if (st1 == "test_fraction_energie_")
          {*(entreePrinc.entree) >> test_fraction_energie;}		
       else if  (st1 == "coef_arret_pourRelaxDyn_")
        {*(entreePrinc.entree) >> coef_arret_pourRelaxDyn; }
       else if  (st1 == "coef_redemarrage_pourRelaxDyn_")
        {*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn; }
       else if  (st1 == "max_deltaX_pourRelaxDyn_")
        {*(entreePrinc.entree) >> max_deltaX_pourRelaxDyn; }
       else if  (st1 == "nb_max_dX_OK_pourRelaxDyn_")
        {*(entreePrinc.entree) >> nb_max_dX_OK_pourRelaxDyn; }
       else if  (st1 == "nb_deb_testfin_pourRelaxDyn_")
        {*(entreePrinc.entree) >> nb_deb_testfin_pourRelaxDyn; }
       else if  (st1 == "nb_deb_test_amort_cinetique_")
        {*(entreePrinc.entree) >> nb_deb_test_amort_cinetique;};
                
       if ((st1 != "max_nb_decroit_pourRelaxDyn_")
        && (st1 != "inter_nb_entre_relax_")
        && (st1 != "taille_moyenne_glissante_")
        && (st1 != "test_fraction_energie_")
        && (st1 != "coef_arret_pourRelaxDyn_")
        && (st1 != "coef_redemarrage_pourRelaxDyn_")
        && (st1 != "max_deltaX_pourRelaxDyn_")
        && (st1 != "nb_max_dX_OK_pourRelaxDyn_")
        && (st1 != "nb_deb_testfin_pourRelaxDyn_") 
        && (st1 != "nb_deb_test_amort_cinetique_")
        && (st1 != "fi_parametre_amortissement_cinetique_"))
        {   cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique"
                 << "\n on attendait un mot cle , au lieu de " << st1
                 << "\n Algori::lecture_Parametres( ... ";
            // dans le cas où un comptage du calcul est en cours on l'arrête
            if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
            if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
            Sortie(1);
        };
                 };
       // préparation pour une nouvelle donnée
       lecture_effective= true;
     }; 
    //===  idem mais pour de l'amortissement cinétique à chaque noeud
    if (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL)
     { mot_cle="avec_au_noeud_amortissement_cinetique_";
       entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
       amortissement_cinetique_au_noeud=true; // on active l'amortissement cinétique
       string st1;
       // lecture des paramètres de l'amortissement cinétique
       while (st1 != "fi_parametre_au_noeud_amortissement_cinetique_")
       { entreePrinc.NouvelleDonnee();
         *(entreePrinc.entree) >> st1;
         if (st1 == "max_nb_decroit_pourRelaxDyn_noe_")
          {*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn_noe; }
         else if  (st1 == "coef_arret_pourRelaxDyn_noe_")
          {*(entreePrinc.entree) >> coef_arret_pourRelaxDyn_noe; }
         else if  (st1 == "coef_redemarrage_pourRelaxDyn_noe_")
          {*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn_noe; }
         else if  (st1 == "nb_deb_test_amort_cinetique_noe_")
          {*(entreePrinc.entree) >> nb_deb_test_amort_cinetique_noe;};
                  
         if ((st1 != "max_nb_decroit_pourRelaxDyn_noe_")
          && (st1 != "coef_arret_pourRelaxDyn_noe_")
          && (st1 != "coef_redemarrage_pourRelaxDyn_noe_")
          && (st1 != "nb_deb_test_amort_cinetique_noe_") 
          && (st1 != "fi_parametre_au_noeud_amortissement_cinetique_"))
           { cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique"
                  << "\n on attendait un mot cle , au lieu de " << st1
                  << "\n Algori::lecture_Parametres( ... ";
             // dans le cas où un comptage du calcul est en cours on l'arrête
             if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
             if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
             Sortie(1);
           };
       };
       // préparation pour une nouvelle donnée
       lecture_effective= true;
     }; 
    //===  contrôle éventuel d'un arrêt sur équilibre statique
    if (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL)
     { // on commence par regarder si l'on est en dynamique, si non on met un warning
       if (Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE)
				      cout << "\n *** Attention, on demande un arret sur l'equilibre statique, (cf. para de l'algo) "
							        << " alors que l'algorithme n'est pas dynamique ?????? il y a peut-etre une erreur de parametres " << endl;
				   // --- lecture éventuelle de opt_cal_C_critique
				   int_defaut=0; mot_cle="ARRET_A_EQUILIBRE_STATIQUE_"; min=0;max=2; lecture_effective= false;
				   lecture_effective = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,arret_a_equilibre_statique);
              //  sert aussi en fait pour retirer éventuellement la partie visqueuse numérique
				 };

    //===  contrôle d'un mode débug éventuel
    // cas où le paramètre de mode débug existe
    if (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL)
				 { int_defaut=0; mot_cle="mode_debug_=";min=1;max=ConstMath::tresgrand;
					  { bool lec_eff = entreePrinc.Lecture_un_parametre_int
                        (int_defaut,nom_class_methode,min,max,mot_cle,mode_debug);
					    lecture_effective = lecture_effective || lec_eff;
       };
     };
    
    //===  contrôle d'un niveau de commentaire spécifique à l'algo
    if (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL)
     { int_defaut=0; mot_cle="permet_affichage_";min=1;max=ConstMath::tresgrand;
       { bool lec_eff = entreePrinc.Lecture_un_parametre_int
                        (int_defaut,nom_class_methode,min,max,mot_cle,permet_affichage);
         lecture_effective = lecture_effective || lec_eff;
       };
     };

    //===  cas où on veut moduler la précision de la convergence globale via une fct nD
    if (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL)
     { mot_cle="modulation_precision_equilibre_=";
       { bool lec_eff = entreePrinc.Lecture_mot_cle_et_string
                           (nom_class_methode,mot_cle,nom_modulation_precision);
         lecture_effective = lecture_effective || lec_eff;
       };
     };    

    if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar)))
				  {entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
				   lecture_effective=false; 
				  };
		 };																								
		 // si le paramètre est activé, on définit le vecteur intermédiaire de sauvegarde du résidu statique
   // un pb cependant, la lecture de l'amortissement artificielle n'est éventuellement pas encore fait
   // c'est le cas d'une première lecture du .info, l'amortissement visqueux s'effectue au niveau des paramètres
   // de contrôle donc bien après l'algo, dans ce cas il faut prévoir dans l'initialisation des algo spécifiques
   // le dimensionnement de vglob_stat
		 if (   (arret_a_equilibre_statique ) // le dimensionnement se fera à l'affectation (=)
			  && (type_calcul_visqu_critique || pa.Amort_visco_artificielle()))
			{ if (vglob_stat == NULL) vglob_stat  = new Vecteur();}
		 else // dans le cas on ne veut pas un arret statique spécifique sans viscosité numérique
			{ if (vglob_stat != NULL) {delete vglob_stat; vglob_stat=NULL ;};}; 	
		 // on se positionne éventuellement sur le prochain mot clé si on n'y est pas déjà
		 while ( !motCle.SimotCle(entreePrinc.tablcar)) 
              entreePrinc.NouvelleDonnee();
  }; //-- fin du cas où on a regardé 
 };
  
// création d'un fichier de commande: cas des paramètres spécifiques
// par défaut on indique qu'il n'y a pas de paramètres.
void Algori::Info_com_parametres(UtilLecture& entreePrinc)
 { // écriture dans le fichier de commande
   ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
	  cout << "\n# exemple para facultatifs generaux d'algorithme (rep o ou n defaut) ? ";
	  string rep;
        rep = "_";
        // procédure de lecture avec prise en charge d'un retour chariot
        rep = lect_return_defaut(true,"n");
        // si la taille de rep == 0 cela veut dire que c'est un retour chariot
        if (rep.size()==0)
           {rep = "n";
            cout << "--> valeur par defaut : n "<<endl;
           };
	  if ((rep == "o") || (rep == "O") ||(rep == "0"))
	    { rep=" "; // init
       while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
        {
         try
          {
           cout 
              << "\n (0 ou f)  (fin)               "
              << "\n (1)  amortissement cinetique "
              << "\n (2)  calcul d'une matrice de viscosite numerique "
              << "\n      pour de l'amortissement critique par exemple "
              << "\n (3)  parametres supplementaires de controle du type d'arret de l'algo "
              << "\n (4)  parametres de controle du mod debug "
              << "\n (5)  def de fichiers externes contenant des contraintes, deformations ..."
              << "\n      preexistantes avant le debut du calcul "
              << "\n (6)  niveau de commentaire specifique aux algos "
              << "\n  ";
           // procédure de lecture avec prise en charge d'un retour chariot
           rep = lect_return_defaut(false,"f");
           if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
             break;
           int num = ChangeEntier(rep);
           bool choix_valide=false;
           if ((num >= 0)&&(num< 7))
                { choix_valide=true; }
           else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
                       << "\n redonnez une bonne valeur"
                       << "\n ou taper f ou 0 pour arreter le programme"; 
                  choix_valide=false;
                }
           switch (num)
            { case 0:  //fin
                { break;} // normalement cela a déjà été filtré avant
              case 1:  // amortissement cinetique
                {
    sort << "\n#---------------------------------------------------------------------"
         << "\n|  parametres communs a differents algorithmes (voir doc specifique) |"
         << "\n#---------------------------------------------------------------------"
         << "\n  #   IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  # ---   parametres de controle du calcul de l'amortissement cinetique  --- "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  #  Il est possible de prendre en compte un amortissement cinetique, dont l'objectif  "
         << "\n  #  est d'obtenir une solution statique a l'aide d'un algorithme dynamique."
         << "\n  #  Pour cela on introduit le mot cle: avec_amortissement_cinetique_ suivi "
         << "\n  #  de mots cles eventuels qui precisent des parametres. Ce groupe de parametres "
         << "\n  #  se termine par le mot cle fi_parametre_amortissement_cinetique_ "
         << "\n  #  Chaque parametre est suivi d'un nombre. Chaque parametre + nombre, doit etre sur une ligne a part."
         << "\n  #   deux techniques pour appliquer le test, qui conduit a mettre les vitesses à 0 "
         << "\n  #   1) on regarde si l'|energie cinetique| diminue n1 fois (consécutives) "
         << "\n  #      ou est inferieure n1 fois  fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle "
         << "\n  #      NB: le test ne se declanche que lorsque l'on a scrute au moins n1 valeurs de l'energie cinetique "
         << "\n  #   2) on regarde si la moyenne glissante de n2 |energie cinetique| consecutive diminue n1 fois (consecutives) "
         << "\n  #      ou est inferieure n1 fois  fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle "
         << "\n  #      NB: le test ne se declanche que lorsque l'on a au moins n2 valeurs consecutives disponibles de l'energie cinetique "
         << "\n  #   NB: le cas 1) est en fait un cas particulier du 2) pour lequel n2 == 1 "                           
         << "\n  #   Les parametres sont: "
         << "\n  #   max_nb_decroit_pourRelaxDyn_ : nombre n2 de diminution de de la moyenne glissante de l'energie cinetique a"
         << "\n  #       (Par exemple si = 3, cela signifie qu'il faut attendre 3 baisses de "
         << "\n  #        l'energie cinetique pour valider la relaxation. Ces 3 baisses peuvent apparaître au "
         << "\n  #        cours de n iterations, n etant plus grand que 3 ! De plus pendant ces en iterations,"
         << "\n  #        on peut egalement avoir des elevations de l'energie cinetique suivi de diminutions."
         << "\n  #        Seules les diminutions sont prises en compte. Apres une relaxation, le compteur de "
         << "\n  #        diminution est remis à 0 "
         << "\n  #       )"
         << "\n  #                                  partir de laquelle on met les vitesses a 0 "
         << "\n  #   inter_nb_entre_relax_        : intervalle autorise entre deux relaxation "
         << "\n  #       (Par exemple si = 10, cela signifie qu'apres une relaxation, une nouvelle relaxation"
         << "\n  #        ne sera accepte qu'apres 10 nouvelles iterations. "
         << "\n  #        Il est egalement possible de remplacer la valeur numerique par le resultat d'une fonction nD "
         << "\n  #        pour cela on indique le mot cle : nom_fct_nD_inter_nb_entre_relax_ "
         << "\n  #        suivi du nom de la fonction nD qui sera appelee a chaque fois que l'on aura besoin       "
         << "\n  #        du parametre inter_nb_entre_relax_  "
         << "\n  #       )"
         << "\n  #   taille_moyenne_glissante_    : valeur du nombre n2 de la moyenne glissante d'energie cinetique "
         << "\n  #   test_fraction_energie_       : si diff de 0, indique la valeur de fraction    " 
         << "\n  #   coef_arret_pourRelaxDyn_     : arret de l'amortissement lorsque l'energie cinetique est"
         << "\n  #                                  inferieur à ce coef * le dernier pic d'energie cinetique "
         << "\n  #   coef_redemarrage_pourRelaxDyn_ : redemarrage de l'amortissement lorsque l'energie cinetique"
         << "\n  #                                    est sup a ce coef * le maxi des pic d'energie enregistre"
         << "\n  #   max_deltaX_pourRelaxDyn_     : limite inferieur de delta x_(t->tdt) a partir de laquelle"
         << "\n  #                                  on arrete le calcul"
         << "\n  #   nb_max_dX_OK_pourRelaxDyn_   : nombre de fois que le critere precedent doit etre satisfait"
         << "\n  #                                  pour que le calcul s'arrete"
         << "\n  #   nb_deb_testfin_pourRelaxDyn_ : le nombre mini de passage dans l'amortissement, a partir duquel on test la fin"
         << "\n  #   nb_deb_test_amort_cinetique_ : le nombre mini d'iteration, a partir duquel on demarre l'algorithme"
         << "\n  #   fi_parametre_amortissement_cinetique_ : mot cle obligatoire indiquant la fin des parametres"
         << "\n  #   exemple de declaration"
         << "\n  #   "
         << "\n  #   avec_amortissement_cinetique_  "
         << "\n  #      max_nb_decroit_pourRelaxDyn_   1 "
         << "\n  #      inter_nb_entre_relax_          1 "
         << "\n  # ou "
         << "\n  #      inter_nb_entre_relax_          nom_fct_nD_inter_nb_entre_relax_   toto  "
         << "\n  #      taille_moyenne_glissante_      1 "
         << "\n  #      coef_arret_pourRelaxDyn_       0. "
         << "\n  #      coef_redemarrage_pourRelaxDyn_ 0.01 "
         << "\n  #      max_deltaX_pourRelaxDyn_       0.4 "
         << "\n  #      nb_max_dX_OK_pourRelaxDyn_     5 "
         << "\n  #      nb_deb_testfin_pourRelaxDyn_   100 "
         << "\n  #      nb_deb_test_amort_cinetique_   100 "
         << "\n  #   fi_parametre_amortissement_cinetique_ "
         << "\n  #   "
         << endl;
                  break;}
              case 2:  // calcul d'une matrice de viscosite numerique
                {
    sort << "\n#---------------------------------------------------------------------"
         << "\n|  parametres communs a differents algorithmes (voir doc specifique) |"
         << "\n#---------------------------------------------------------------------"
         << "\n  #   IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  # ---   parametres de controle du calcul de la matrice de viscosite  --- "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  #  Il est possible de prendre en compte de l'amortissement critique numerique "
         << "\n  #   classiquement utilise dans le cas de la relaxation dynamique "
         << "\n  #   "
         << "\n  #   ** PARAMETRES FACULTATIF **   "
         << "\n  #  on indique tout d'abord le mot cle : parametre_calcul_de_la_viscosite_  suivi des parametres associes eventuelles "
         << "\n  #  type_calcul_visqu_critique=  suivi du type de calcul  "
         << "\n  # si type_calcul_visqu_critique= 1 : la matrice C est calculee selon: C_{ii} = c * M_{ii} avec c = 2 * omega_0  "
         << "\n  # si type_calcul_visqu_critique= 2 : la matrice C est calculee selon: C_{ii} = c * M_{ii}   "
         << "\n  #												avec c = sqrt( 4*omega_0^2 - omega_0^4)"
         << "\n  # si type_calcul_visqu_critique= 3 : la matrice C est calculee selon: C_{ii} = c * M_{ii}   "
         << "\n  #												avec c = 2*sqrt(omega_0/(1+omega_0)) "
         << "\n  #                        "
         << "\n  #                                    puis il y a un choix via le parametre  opt_cal_C_critique=  "
         << "\n  #      opt_cal_C_critique= 0 :  (omega_0)^2 \approx  (Delta X^T Delta R_{i(statique)}^n) / (Delta X^T M Delta X) "
         << "\n  #      opt_cal_C_critique= 1 :  (omega_0)^2 \approx  (dot X^T Delta R_{i(statique)}^n) / (dot X^T M dot X)  "
         << "\n  #                        "
         << "\n  #				a) si (omega_0)^2 est négative on met omega_0^2=0 "
         << "\n  #				b) si (omega_0)^2 > f^2 * 4, on pose (omega_0) = f^2 * 4, par defaut: f= 0.9 "
         << "\n  #      on peut changer la valeur de f avec le parametre: f_= suivi de la valeur  "
         << "\n  #                        "
         << "\n  #      il est possible egalement d'amplifier la valeur de la viscosite calculee (avec cependant toujours les limites a) et b) "
         << "\n  #      ampli_visco_=   val_ampli   "
         << "\n  #                        "
         << "\n  #                             Exemple de declaration:  "
         << "\n  ##   parametre_calcul_de_la_viscosite_  type_calcul_visqu_critique= 1 opt_cal_C_critique= 0  f_= 1.3 "
         << "\n  #                       "
         << "\n  #   tous les parametres sont facultatifs: les valeurs par defaut sont:   "
         << "\n  #   opt_cal_C_critique= 1 ; f_= 0.9 ; ampli_visco_= 1.; "
         << "\n  #                        "
         << "\n  #                        "
         << endl;
                break;}
              case 3:  // parametres supplementaires de controle du type d'arret de l'algo
                {
    sort << "\n#---------------------------------------------------------------------"
         << "\n|  parametres communs a differents algorithmes (voir doc specifique) |"
         << "\n#---------------------------------------------------------------------"
         << "\n  #   IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
         << "\n  #              apres l'amortissement cinetique, apres la def de calcul de  viscosite et les autres qui precedent!!! "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  # ---   parametres de controle du type d'arret                       --- "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  #  ce parametre est utile dans le cas d'un calcul dynamique "
         << "\n  #  on peut egalement indiquer un arret correspondant a un equilibre statique. Dans ce cas "
         << "\n  #  le calcul s'arrete lorsqu'on considere que l'on a atteind un regime statique dont le critere est:"
         << "\n  #   - le residu statique est inferieur au maxi indique dans les parametres generaux de controle"
         << "\n  #   - si l'on utilise de l'amortissement cinetique: le critere d'arret est celui de cet algo"
         << "\n  #   Pour activer cette possibilite d'arret il faut indiquer sur la ligne qui suit le mot cle"
         << "\n  #   ARRET_A_EQUILIBRE_STATIQUE_  suivant d'un nombre "
         << "\n  #    ARRET_A_EQUILIBRE_STATIQUE_ 1  signifie que le residu statique est utilise comme critere"
         << "\n  #    ARRET_A_EQUILIBRE_STATIQUE_ 2  le residu statique et le critere de l'amortissement cinetique "
         << "\n  #                                   sont conjointement utilises, on retient le plus defavorable"
         << "\n  #    ARRET_A_EQUILIBRE_STATIQUE_ 0  pas de prise en compte de ce parametre (valeur par defaut)"
         << "\n  #   "
         << "\n  #    exemple d'utilisation "
         << "\n  #   "
         << "\n  #   ARRET_A_EQUILIBRE_STATIQUE_ 1 "
         << "\n  #   "
         << endl;
                break;}
              case 4:  // parametres de controle du mod debug
                {
     sort << "\n#---------------------------------------------------------------------"
         << "\n|  parametres communs a differents algorithmes (voir doc specifique) |"
         << "\n#---------------------------------------------------------------------"
         << "\n  #   IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
         << "\n  #              apres les parametres de controle de type d'arret et les autres qui precedent !!! "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  # ---                parametres de controle du mode debug            --- "
         << "\n  # ---------------------------------------------------------------------- "
         << "\n  #   ** PARAMETRES FACULTATIF **   "
         << "\n  #  mode_debug_=  parametre de debug (= 0 par defaut ->  calcul classique) "
         << "\n  #             =  n : a chaque n iteration on sort une visualisation "
         << "\n  ##  mode_debug_= 0   # a mettre apres les para de relaxation           "
         << "\n  #           "
         << "\n  #  modulation_precision_equilibre_=  fonction_nD "
         << "\n  #  la fonction fonction_nD module par multiplication, la precision en cours "
         << "\n  # **important**: ces parametres doivent etre mis chacun sur une ligne differente  "
         << endl;
                break;}
              case 5:  // def de fichiers externes contenant des contraintes, deformations ...
                {
                   sort << "\n  # --------------------------------------------------------------------------------- "
                        << "\n  # ---   lecture sur fichiers externes de grandeurs preexistantes au calcul      --- "
                        << "\n  # --------------------------------------------------------------------------------- "
                        << "\n  #  ce referer a la doc pour la syntaxe dans les fichiers  \n"
                        << "\n   flotExterne  #--- #  mot cle pour introduire la lecture \n";
         
                   string repi= " "; // init
                   rep=" "; // init
                   while ((Minuscules(repi) != "f")&&(Minuscules(repi) != "0"))
                    {
                     try
                       {
                         cout
                            << "\n (0 ou f)  (fin)               "
                            << "\n (1)  nouveau fichier de contraintes aux point d'integration "
                            << "\n (2)  nouveau fichier de deplacement aux noeuds "
                            << "\n  ";
                         // procédure de lecture avec prise en charge d'un retour chariot
                         repi = lect_return_defaut(false,"f");
                         if ((Minuscules(repi) == "f") || (Minuscules(repi) == "0"))// sortie directe
                           break;
                         int numi = ChangeEntier(repi);
                         bool choix_valide=false;
                         if ((numi >= 0)&&(numi<=2))
                              { choix_valide=true; }
                         else { cout << "\n Erreur on attendait un entier entre 0 et 2 !!, "
                                     << "\n redonnez une bonne valeur"
                                     << "\n ou taper f ou 0 pour arreter le programme"; 
                                choix_valide=false;
                              }
                         switch (numi)
                          { case 0:  //fin
                             { break;} // normalement cela a déjà été filtré avant
                            case 1:  // nouveau fichier de contraintes aux point d'integration
                             { string nom;
                               cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _cab.isoe ) ";
                               nom = lect_chaine();
                               sort << "\n  1  " << nom << "_cab.isoe   " ;
                               cout << "\n nom du maillage associe au fichier ? ";
                               nom = lect_chaine();
                               sort << nom << endl;
                               break;
                             }
                            case 2:  // nouveau fichier de contraintes aux point d'integration
                             { string nom;
                               cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _dpl.points ) ";
                               nom = lect_chaine();
                               sort << "\n  2  " << nom << "_dpl.points   " ;
                               cout << "\n nom du maillage associe au fichier ? ";
                               nom = lect_chaine();
                               sort << nom << endl;
                               break;
                             }
                            default:
                              cout << "\n le cas "<<repi<<" n'est pas encore traite !!, mais cela devrait ce faire sans tarder ";
                           };
                       }
                     catch (ErrSortieFinale)
                          // cas d'une direction voulue vers la sortie
                          // on relance l'interuption pour le niveau supérieur
                        { ErrSortieFinale toto;
                          throw (toto);
                        }
                     catch (...)//
                       {  cout << "\n Erreur on attendait un des mots cles proposés !!, "
                               << "\n redonnez une bonne valeur"
                               << "\n ou taper f ou 0 pour sortir "; 
                       };
                    }; //-- fin du while
                break;}
              case 6:  // parametres de controle du mod debug
                {
                 sort << "\n#---------------------------------------------------------------------"
                     << "\n|  parametres communs a differents algorithmes (voir doc specifique) |"
                     << "\n#---------------------------------------------------------------------"
                     << "\n  #   IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
                     << "\n  #              apres les parametres de controle de type d'arret et les autres qui precedent !!! "
                     << "\n  # ---------------------------------------------------------------------- "
                     << "\n  # ---    parametres de controle du niveau de commentaire             --- "
                     << "\n  # ---------------------------------------------------------------------- "
                     << "\n  #   ** PARAMETRES FACULTATIF **   "
                     << "\n  #  permet_affichage_  3 "
                     << "\n  # **important**: ce parametre doit etre mis  sur une ligne seule  "
                     << endl;
                 break;
                }
              default:
                cout << "\n le cas "<<rep<<" n'est pas encore traite !!, mais cela devrait ce faire sans tarder ";
            };
          }
         catch (ErrSortieFinale)
              // cas d'une direction voulue vers la sortie
              // on relance l'interuption pour le niveau supérieur
            { ErrSortieFinale toto;
              throw (toto);
            }
         catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
          {  cout << "\n Erreur on attendait un des mots cles proposés !!, "
                  << "\n redonnez une bonne valeur"
                  << "\n ou taper f ou 0 pour sortir "; 
          };
        }; //-- fin du while
	    };
   sort << "\n" << endl;
 };

// initialisation d'un calcul de remonté à des variables secondaires ou d'erreur
// globalement, cette initialisation dépend des paramètres utilisateurs
// ramène true s'il y a initialisation
bool Algori::InitRemont(LesMaillages * lesMail,LesReferences* lesRef, DiversStockage* diversStockage,Charge* charge,
                    LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
   {bool avec_remont=false;

    // on parcourt la liste soustypeDeCalcul si elle n'est pas vide
    if (soustypeDeCalcul->size() > 0)
     {if ((find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_sigma) != soustypeDeCalcul->end())
          || (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),avec_remonte_erreur) != soustypeDeCalcul->end()))
        {Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
         Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
         avec_remont=true;avec_remont_sigma=true;}
      if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_epsilon) != soustypeDeCalcul->end())
        {Algori::InitRemontEps(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
         avec_remont=true;avec_remont_eps=true;}
      if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_erreur) != soustypeDeCalcul->end())
        {if (!avec_remont_sigma)
            {Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
             avec_remont_sigma=true;}
          Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
          avec_remont=true;avec_erreur=true;}
     };

    return avec_remont;
    };   

// calcul d'une remontée à des variables secondaires ou d'erreur, ceci pour un post traitement de visualisation
// ce calcul dépend des paramètres utilisateurs, il n'est fait qu'à chaque sortie .BI
// ramène true s'il y a un calcul effectif
bool Algori::CalculRemont(LesMaillages * lesMail,OrdreVisu::EnumTypeIncre type_incre,int incre)
   {  bool change=false;
      bool remont_contrainte=false;
      if (pa.SauvegardeAutorisee(incre,temps_derniere_sauvegarde,type_incre))
           { if (avec_remont_sigma) {Algori::RemontSigma(lesMail);change=true;remont_contrainte=true;};
             if (avec_remont_eps) {Algori::RemontEps(lesMail);change=true;};
             if (avec_erreur) {Algori::RemontErreur(lesMail);change=true;};
            }; 
      return change;
    };  

// affichage éventuelle de la matrice de raideur et du second membre
void Algori::Affiche_RaidSM(const Vecteur & vglobin,const Mat_abstraite& matglob) const
 {      // affichage éventuelle de la matrice de raideur et du second membre     
       if (ParaGlob::NiveauImpression() >= 10)
        { string entete = " affichage de la matrice de raideur  ";
          matglob.Affichage_ecran(entete); 
          entete = " affichage du second membre  ";
          vglobin.Affichage_ecran(entete); 
         }                        
   };
   
// algorithme classique de line search
// le line seach agit sur une partie de la puissance et non sur la norme du résidu
// le line search à pour objectif de minimiser une partie de l'acroissement de la puissance
// en jeux, ainsi on peut avoir une minimisation réussi tout en ayant une norme d'équilibre
// qui continue à grandir
// cependant en général les deux sont lié et l'application du line_seach garantit que dans
// la direction de descente choisi on minimise norme (mais ce minimum peut cependant être
// supérieur à l'ancienne norme!)
bool  Algori::Line_search1(Vecteur& sauve_deltadept,double& puis_precedente,
              Vecteur& vres,LesMaillages * lesMail,Vecteur* sol 
              ,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex
              ,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal
              ,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb
              ,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)

 {  // ------------------------------------------------------------
    // |on regarde s'il faut utiliser l'algorithme de line search |
    // ------------------------------------------------------------
    // nombre d'incrément mini à partir duquel on exécute le line_search
    const int nb_incr_min_line_search = 2;
    // les mini et maxi du facteur de line _search 
    const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit
    // le nombre de fois que l'algorithme bute sur le mini et maxi
    int nbfois_alphmin = 0; int nbfois_alphmax = 0;
    const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2;
    // nombre maxi de boucle de line_search
    const int iwwmax = 5;
    // limite sur la puissance pour activer le line_search
    const double epsilon_p = 0.01; 
    double ancien_residu_norme = vres.Max_val_abs ();
    double norme_dep = sauve_deltadept.Max_val_abs ();
    double ancien_residuN = (- vres  * (*sol));
    // sauvegarde du déplacement
    sauve_deltadept = *sol;
    // il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre
    // en oeuvre l'algorithme 
      // 1 - on sauvegarde les conditions actuelles
      // récupération de l'incrément total de t à tdt avant le déplacement
    lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb);
      // 2 - on met en place le nouveau déplacement
    lesMail->PlusDelta_tdt(*sol,nb_casAssemb);
      // 3 - initialisation de la puissance externe puis on la calcul
    vglobex.Zero();
    if (!(charge->ChargeSecondMembre_Ex_mecaSolid
                 (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
       { cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
              << " des efforts externes: arret"
              << "\n Algori::Line_search1(...";
         // dans le cas où un comptage du calcul est en cours on l'arrête
         if (tempsCalEquilibre.Comptage_en_cours())
                    tempsCalEquilibre.Arret_du_comptage();
         Sortie(1);
       };
     // 4 - idem pour la puissance interne
     vglobin.Zero();
      // 5 - calcul du second membre et des énergies
    // dans le cas d'un calcul inexploitable arrêt de la boucle
    if (!SecondMembreEnerg(lesMail,Ass,vglobin))
    	{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret"
    	       << "\n Algori::Line_search1(...";
       // dans le cas où un comptage du calcul est en cours on l'arrête
       if (tempsCalEquilibre.Comptage_en_cours())
                  tempsCalEquilibre.Arret_du_comptage();
    	  Sortie(1);
    	};
      // 6 - second membre total
    vglobaal = vglobex ;vglobaal += vglobin;
      // 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu
    lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
    double nouvelle_norme = vglobaal.Max_val_abs ();
    
    // calcul d'une partie de la variation de puissance relative au delta ddl
    // cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl
    // et la direction du résidu 
    double var_puis  =  - vglobaal * sauve_deltadept; // calcul de  la puissance
    cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis;
    cout << "\n puissance  " << var_puis ;
    cout << "\n  ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme);

    if ((compteur >= nb_incr_min_line_search)  
         && ((Abs(var_puis) >  epsilon_p * norme_dep * nouvelle_norme) 
         || (nouvelle_norme > 0.1 * ancien_residu_norme))) 
 //      ((var_puis >  puis_precedente) || (nouvelle_norme > ancien_residu_norme))) 
     //       || (puis_reelle < 0.))
        {// signifie que le déplacement précédent était trop grand
         // ou pas dans la bonne direction ! 
         // 1) on revient aux conditions du début de l'itération
         v_travail -= sauve_dept_a_tdt;
         lesMail->PlusDelta_tdt(v_travail,nb_casAssemb);
         // 2) on traite la direction
         // si la puissance est négative cela signifie que la matrice n'est pas définie
         // positive, dans ce cas on utilise comme direction de descente 
         // - la direction trouvée ou le résidu
     /*    if (puis_reelle < 0.)
             { // message d'avertissement
               cout << "\n ********** attention puissance négative, changement de descente "; 
             //  ancien_dep = - vres;
               ancien_dep = - ancien_dep;
              } */
    /*        else if (Abs(puis_reelle) > pa.max_puissance)
               // si la puissance est trop grande arrêt des itérations
              {
                non_convergence = true;
                break;
               } */
          // 3) Maintenant application du line search, 
          //calcul d'alpha en utilisant une approximation linéaire de la puissance
          double alph = 1.; // initialisation du coef multiplicateur du delta ddl
          // dans le cas ou la nouvelle et l'ancienne puissance sont très proche
          // on change de alpha
          if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme)
             alph = 0.66; // par exemple
          // dans un premier temps on effectue un nombre de  boucle fixé pour alpha
          bool reduc_reussi = false; 
          bool reduc_possible = true;
          for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++)
             { // calcul du nouveau résidu
               // mise en place du nouveau déplacement
               // pour éviter de créer un nouveau vecteur qui peut être de grande taille
               // on utilise la place de vglobex pour le déplacement   
               Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement
               nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept;
               lesMail->TversTdt();
               lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb );
               //puissance externe
               vglobex.Zero();
              
               if (!(charge->ChargeSecondMembre_Ex_mecaSolid
                             (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
                   { cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
                          << " des efforts externes: arret"
                          << "\n Algori::Line_search1(...";
                     // dans le cas où un comptage du calcul est en cours on l'arrête
                     if (tempsCalEquilibre.Comptage_en_cours())
                                tempsCalEquilibre.Arret_du_comptage();
                     Sortie(1);
                   };
               // puissance interne boucle sur les elements
               vglobin.Zero();
               // calcul du second membre et des énergies
               // dans le cas d'un calcul inexploitable arrêt de la boucle
               if (!SecondMembreEnerg(lesMail,Ass,vglobin))
                 { cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret"
                        << "\n Algori::Line_search1(...";
                   // dans le cas où un comptage du calcul est en cours on l'arrête
                   if (tempsCalEquilibre.Comptage_en_cours())
                     tempsCalEquilibre.Arret_du_comptage();
                   Sortie(1);
                 };
               // second membre total
               vglobaal = vglobex ;vglobaal += vglobin;
               // mise en place des conditions limites
               lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
               // calcul du nouveau coefficient
   //            double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep);
   //            double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu  * ancien_dep);//vres.Norme();
               double nouveau_residuN = alph * (- vglobaal * sauve_deltadept);
               double ancien_alph = alph;
               nouvelle_norme = vglobaal.Max_val_abs ();
               alph = - alph* ancien_residuN/
                       (nouveau_residuN - ancien_residuN);
               // test d'arrêt 
               if ((alph < alphmin) || (alph > alphmax))
                { // troncature d'alpha
                  if (alph < alphmin) 
                   {alph = alphmin;nbfois_alphmin++;
                    if (nbfois_alphmin > nbfois_alphmin_max)
          /*           if (nouvelle_norme < ancien_residu_norme)
                       // soit la norme à diminuée => on prend le nouveau déplacement
                       // et on arrête car dans tous les cas ce n'est pas une bonne convergence
                       // d'être acculé à la borne 
                      { reduc_reussi = true;
                        // on remet au mieux les choses comme au début de la méthode
                        *sol = ancien_alph * sauve_deltadept;
                        vres = vglobal;
                        puis_precedente = Abs(nouveau_residuN);
                        break; 
                       }
                     else */
                     // sinon il n'y a pas en plus de convergence on arrête tout   
                       reduc_possible = false;
                    }
                  if (alph > alphmax) 
                   {alph = alphmax;nbfois_alphmax++;
                    if (nbfois_alphmax > nbfois_alphmax_max)
           /*          if (nouvelle_norme < ancien_residu_norme)
                       // soit la norme à diminuée => on prend le nouveau déplacement
                       // et on arrête car dans tous les cas ce n'est pas une bonne convergence
                       // d'être acculé à la borne 
                      { reduc_reussi = true;
                        // on remet au mieux les choses comme au début de la méthode
                        *sol = ancien_alph * sauve_deltadept;
                        vres = vglobal;
                        puis_precedente = Abs(nouveau_residuN);
                        break; 
                       }
                     else */
                     // sinon il n'y a pas en plus de convergence on arrête tout   
                        reduc_possible = false;
                    }
                 } 
               else // sinon on test la convergence
      //           if (nouvelle_norme <  0.8 * ancien_residu_norme )  
                {if ((Abs(nouveau_residuN) <  0.5 * Abs(puis_precedente) ) 
                    && (nouvelle_norme < ancien_residu_norme)) 
                 { reduc_reussi = true;
                   // on remet au mieux les choses comme au début de la méthode
                   *sol = ancien_alph * sauve_deltadept;
                   vres = vglobaal;
                   puis_precedente = Abs(nouveau_residuN);
                   break; 
                   }
      //           else if (iww==iwwmax) 
                 else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme))
                  {reduc_reussi = true;
                   // on remet au mieux les choses comme au début de la méthode
                   *sol = ancien_alph * sauve_deltadept;
                   vres = vglobaal;
                   puis_precedente =  Abs(nouveau_residuN);
                   break; 
                   }                  
                 }  
               // sinon on incrémente la position à tdt      
               cout << "\n coefficient de line_search = " << alph
                    << " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN;            
              }
            // si la réduction c'est mal passée alors on laisse la solution
            // identique à avant le line_search
            if (!reduc_reussi)
             {  // mise en place du  déplacement existant avant le line_search
                // ainsi que les autres grandeurs actives
                lesMail->TversTdt();
                v_travail = sauve_dept_a_tdt + sauve_deltadept;
                lesMail->PlusDelta_tdt( v_travail,nb_casAssemb);
                // retour du fait qu'il n'y a pas eu de line search
                return false;
              } 
             else
             {
              // retour du fait que le line search a été effectué
              return true;
              }  
            }
         else // cas ou l'on ne fait pas de line seach
             return false;
   };
                           
    // algorithme de line search qui utilise une approximation cubique du résidu ( (R).<ddl>)
    // en fonction du paramètre lambda de line search ( X+lambda. delta_ddl)
    // la méthode renvoi si oui ou non le line search a été effecué
    // sauve_deltadept : vecteur de travail servant à sauver la valeur calculée de sol
    // vres : correspond en entrée au vecteur résidu
    // sauve_dept_a_tdt : vecteur de travail utilisé pour sauvegarder la totalité de l'incrément de t à t+dt
    // vglobex : puissance externe
    // v_travail : vecteur de travail à la même dimension que sol 
    // vglobal : = & vglobin: vecteur puissance globale
bool  Algori::Line_search2(Vecteur& sauve_deltadept,double& puis_precedente,
              Vecteur& vres,LesMaillages * lesMail,Vecteur* sol 
              ,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex
              ,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal
              ,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb
              ,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)

 { 
 
 /*  // initialisation des différentes grandeurs nécessaires pour le calcul du polynome cubique complet ou dégénéré
   double f1=      ;// puissance pour lambda = 0 
   double f2=      ;// puissance pour lambda = 1
   double g1=      ;//  */
 
 
    // ------------------------------------------------------------
    // |on regarde s'il faut utiliser l'algorithme de line search |
    // ------------------------------------------------------------
    // nombre d'incrément mini à partir duquel on exécute le line_search
    const int nb_incr_min_line_search = 2;
    // les mini et maxi du facteur de line _search 
    const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit
    // le nombre de fois que l'algorithme bute sur le mini et maxi
    int nbfois_alphmin = 0; int nbfois_alphmax = 0;
    const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2;
    // nombre maxi de boucle de line_search
    const int iwwmax = 5;
    // limite sur la puissance pour activer le line_search
    const double epsilon_p = 0.01; 
    double ancien_residu_norme = vres.Max_val_abs ();
    double norme_dep = sauve_deltadept.Max_val_abs ();
    double ancien_residuN = (- vres  * (*sol));
    // sauvegarde du déplacement
    sauve_deltadept = *sol;
    // il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre
    // en oeuvre l'algorithme 
      // 1 - on sauvegarde les conditions actuelles
      // récupération de l'incrément total de t à tdt avant le déplacement
    lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb);
      // 2 - on met en place le nouveau déplacement
    lesMail->PlusDelta_tdt(*sol,nb_casAssemb);
      // 3 - initialisation de la puissance externe puis on la calcul
    vglobex.Zero();
  
    if (!(charge->ChargeSecondMembre_Ex_mecaSolid
                    (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
          { cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
                 << " des efforts externes: arret"
                 << "\n Algori::Line_search2(...";
            // dans le cas où un comptage du calcul est en cours on l'arrête
            if (tempsCalEquilibre.Comptage_en_cours())
                       tempsCalEquilibre.Arret_du_comptage();
            Sortie(1);
          };
      // 4 - idem pour la puissance interne
    vglobin.Zero();
      // 5 - calcul du second membre et des énergies
    // dans le cas d'un calcul inexploitable arrêt de la boucle
    if (!SecondMembreEnerg(lesMail,Ass,vglobin))
       { cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret"
              << "\n Algori::Line_search2(...";
         // dans le cas où un comptage du calcul est en cours on l'arrête
         if (tempsCalEquilibre.Comptage_en_cours())
            tempsCalEquilibre.Arret_du_comptage();
         Sortie(1);
       };
      // 6 - second membre total ( vglobal est identique a vglobin)
    vglobaal = vglobex ; vglobaal += vglobin;
      // 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu
    lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
    double nouvelle_norme = vglobaal.Max_val_abs ();
    
    // calcul d'une partie de la variation de puissance relative au delta ddl
    // cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl
    // et la direction du résidu 
    double var_puis  =  - vglobaal * sauve_deltadept; // calcul de  la puissance
    cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis;
    cout << "\n puissance  " << var_puis ;
    cout << "\n  ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme);

    if ((compteur >= nb_incr_min_line_search)  
         && ((Abs(var_puis) >  epsilon_p * norme_dep * nouvelle_norme) 
         || (nouvelle_norme > 0.1 * ancien_residu_norme))) 
 //      ((var_puis >  puis_precedente) || (nouvelle_norme > ancien_residu_norme))) 
     //       || (puis_reelle < 0.))
        {// signifie que le déplacement précédent était trop grand
         // ou pas dans la bonne direction ! 
         // 1) on revient aux conditions du début de l'itération
         v_travail -= sauve_dept_a_tdt;
         lesMail->PlusDelta_tdt(v_travail,nb_casAssemb);
         // 2) on traite la direction
         // si la puissance est négative cela signifie que la matrice n'est pas définie
         // positive, dans ce cas on utilise comme direction de descente 
         // - la direction trouvée ou le résidu
     /*    if (puis_reelle < 0.)
             { // message d'avertissement
               cout << "\n ********** attention puissance négative, changement de descente "; 
             //  ancien_dep = - vres;
               ancien_dep = - ancien_dep;
              } */
    /*        else if (Abs(puis_reelle) > pa.max_puissance)
               // si la puissance est trop grande arrêt des itérations
              {
                non_convergence = true;
                break;
               } */
          // 3) Maintenant application du line search, 
          //calcul d'alpha en utilisant une approximation linéaire de la puissance
          double alph = 1.; // initialisation du coef multiplicateur du delta ddl
          // dans le cas ou la nouvelle et l'ancienne puissance sont très proche
          // on change de alpha
          if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme)
             alph = 0.66; // par exemple
          // dans un premier temps on effectue un nombre de  boucle fixé pour alpha
          bool reduc_reussi = false; 
          bool reduc_possible = true;
          for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++)
             { // calcul du nouveau résidu
               // mise en place du nouveau déplacement
               // pour éviter de créer un nouveau vecteur qui peut être de grande taille
               // on utilise la place de vglobex pour le déplacement   
               Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement
               nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept;
               lesMail->TversTdt();
               lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb );
               //puissance externe
               vglobex.Zero();
              
               if (!(charge->ChargeSecondMembre_Ex_mecaSolid
                             (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
                   { cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
                          << " des efforts externes: arret"
                          << "\n Algori::Line_search2(...";
                     // dans le cas où un comptage du calcul est en cours on l'arrête
                     if (tempsCalEquilibre.Comptage_en_cours())
                                tempsCalEquilibre.Arret_du_comptage();
                     Sortie(1);
                   };
               // puissance interne boucle sur les elements
               vglobin.Zero();
               // calcul du second membre et des énergies
               // dans le cas d'un calcul inexploitable arrêt de la boucle
               if (!SecondMembreEnerg(lesMail,Ass,vglobin))
    	            { cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret"
    	                   << "\n Algori::Line_search1(...";
                   // dans le cas où un comptage du calcul est en cours on l'arrête
                   if (tempsCalEquilibre.Comptage_en_cours())
                       tempsCalEquilibre.Arret_du_comptage();
    	              Sortie(1);
    	            };
               // second membre total ( vglobal est identique a vglobin)
               vglobaal = vglobex ;vglobaal += vglobin;
               // mise en place des conditions limites
               lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
               // calcul du nouveau coefficient
   //            double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep);
   //            double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu  * ancien_dep);//vres.Norme();
               double nouveau_residuN = alph * (- vglobaal * sauve_deltadept);
               double ancien_alph = alph;
               nouvelle_norme = vglobaal.Max_val_abs ();
               alph = - alph* ancien_residuN/
                       (nouveau_residuN - ancien_residuN);
               // test d'arrêt 
               if ((alph < alphmin) || (alph > alphmax))
                { // troncature d'alpha
                  if (alph < alphmin) 
                   {alph = alphmin;nbfois_alphmin++;
                    if (nbfois_alphmin > nbfois_alphmin_max)
          /*           if (nouvelle_norme < ancien_residu_norme)
                       // soit la norme à diminuée => on prend le nouveau déplacement
                       // et on arrête car dans tous les cas ce n'est pas une bonne convergence
                       // d'être acculé à la borne 
                      { reduc_reussi = true;
                        // on remet au mieux les choses comme au début de la méthode
                        *sol = ancien_alph * sauve_deltadept;
                        vres = vglobal;
                        puis_precedente = Abs(nouveau_residuN);
                        break; 
                       }
                     else */
                     // sinon il n'y a pas en plus de convergence on arrête tout   
                       reduc_possible = false;
                    }
                  if (alph > alphmax) 
                   {alph = alphmax;nbfois_alphmax++;
                    if (nbfois_alphmax > nbfois_alphmax_max)
           /*          if (nouvelle_norme < ancien_residu_norme)
                       // soit la norme à diminuée => on prend le nouveau déplacement
                       // et on arrête car dans tous les cas ce n'est pas une bonne convergence
                       // d'être acculé à la borne 
                      { reduc_reussi = true;
                        // on remet au mieux les choses comme au début de la méthode
                        *sol = ancien_alph * sauve_deltadept;
                        vres = vglobal;
                        puis_precedente = Abs(nouveau_residuN);
                        break; 
                       }
                     else */
                     // sinon il n'y a pas en plus de convergence on arrête tout   
                        reduc_possible = false;
                    }
                 } 
               else // sinon on test la convergence
      //           if (nouvelle_norme <  0.8 * ancien_residu_norme )  
                {if ((Abs(nouveau_residuN) <  0.5 * Abs(puis_precedente) ) 
                    && (nouvelle_norme < ancien_residu_norme)) 
                 { reduc_reussi = true;
                   // on remet au mieux les choses comme au début de la méthode
                   *sol = ancien_alph * sauve_deltadept;
                   vres = vglobaal;
                   puis_precedente = Abs(nouveau_residuN);
                   break; 
                   }
      //           else if (iww==iwwmax) 
                 else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme))
                  {reduc_reussi = true;
                   // on remet au mieux les choses comme au début de la méthode
                   *sol = ancien_alph * sauve_deltadept;
                   vres = vglobaal;
                   puis_precedente =  Abs(nouveau_residuN);
                   break; 
                   }                  
                 }  
               // sinon on incrémente la position à tdt      
               cout << "\n coefficient de line_search = " << alph
                    << " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN;            
              }
            // si la réduction c'est mal passée alors on laisse la solution
            // identique à avant le line_search
            if (!reduc_reussi)
             {  // mise en place du  déplacement existant avant le line_search
                // ainsi que les autres grandeurs actives
                lesMail->TversTdt();
                v_travail = sauve_dept_a_tdt + sauve_deltadept;
                lesMail->PlusDelta_tdt( v_travail,nb_casAssemb);
                // retour du fait qu'il n'y a pas eu de line search
                return false;
              } 
             else
             {
              // retour du fait que le line search a été effectué
              return true;
              }  
            }
         else // cas ou l'on ne fait pas de line seach
             return false;
   };
   
// initialisation des paramètres pour l'amortissement cinétique  (au cas ou on veut plusieurs amortissement)
void Algori::InitialiseAmortissementCinetique()
	{ compteur_decroit_pourRelaxDyn=0;
   dernier_pic = pic_E_cint_t = -1.; 
   max_pic_E_cin = -1.;
   compteur_test_pourRelaxDyn = 0;
   compteur_pic_energie = 0;compteur_pic_energie_noe= 0;
		 // cas de l'utilisation d'une moyenne glissante
		 sauve_E_cin.Change_taille(taille_moyenne_glissante);
		 nb_Ecin_stocker = 0;indice_EC1= 0;
		 moyenne_glissante = 0.;
		 moy_gliss_t = 0.;
	};                         
       
// méthode d'application de l'amortissement cinétique 
// on arrête l'amortissement lorsque E_cin_tdt < E_cin_t * pic_E_cint_t
// on redémarre l'amortissement lorsque  E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn
    // retour un int :
    //   = 1  : il y a eu amortissement mais le calcul continue
    //   = 0  : pas d'amortissement
    //   = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait
int Algori::AmortissementCinetique(const Vecteur & delta_ddl,const double& coef_mass,const Vecteur& X
                               ,const Mat_abstraite& mat_mass,int icharge,Vecteur& V)
 {int relax_vit = 0;
  bool relaxation_effectuee = false; // initialisation

 #ifdef UTILISATION_MPI
  // cas d'un  calcul //, seule le  CPU 0 calcule
  // car lui-seule possède la bonne matrice masse
  int proc_en_cours = ParaGlob::Monde()->rank();
  Vecteur v_inter(4); // pour la transmission des infos du proc 0 au proc i

  if (proc_en_cours == 0)
   {
 #endif

  nb_depuis_derniere_relax++; // on incrémente à chaque passage
  // dans le cas où inter_nb_entre_relax dépend d'une fonction nD, on calcule sa valeur
  if (fct_nD_inter_nb_entre_relax != NULL)
   {int old_valeur = inter_nb_entre_relax;
    inter_nb_entre_relax = (fct_nD_inter_nb_entre_relax->Valeur_pour_variables_globales())(1);
    if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 1))
      if (old_valeur != inter_nb_entre_relax)
      cout << "\n >>> changement de inter_nb_entre_relax de " << old_valeur
           << " en ==> "<< inter_nb_entre_relax;
   };
//  #ifdef UTILISATION_MPI
//      // debug
//      cout << "\n debug Algori::AmortissementCinetique  N: " << icharge
//           << " debut, proc= "<< ParaGlob::Monde()->rank() << flush;
//      // fin debug
//  #endif

//	 // dans le cas où l'on veut un amortissement individuel aux noeuds, on appelle la méthode spécifique
//  int relax_vit_individuel = 0;
//	 if (amortissement_cinetique_au_noeud && !relax_vit)
//	   { relax_vit_individuel=AmortissementCinetique_individuel_aux_noeuds(delta_ddl,coef_mass,X,mat_mass,icharge,V);};

//*** je ne comprends pas le test que j'ai mis ici: abscon !! 16 oct 2018
  // on ne continue que s'il n'y a pas d'amortissement cinétique en route
  if (!((icharge > nb_deb_test_amort_cinetique_noe) && amortissement_cinetique_au_noeud))
// ---- non la suite n'est pas bonne et converge beaucoup moins bien !!
// je le remplace : on test si on est en amortissement cinétique, et que le nombre d'itérations
// est suffisant
///  if ((icharge > nb_deb_test_amort_cinetique_noe) && (!amortissement_cinetique_au_noeud)
///      && amortissement_cinetique )
// --- fin modif avorté !!!
    {

//  if (!relax_vit_individuel)
////  else
//    {
//	 cout << "\n E_cin_t= " << E_cin_t << " E_cin_tdt= " << E_cin_tdt
//	      << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn;

// remarque: 
// compteur_decroit_pourRelaxDyn: indique combien de fois le test de pic a été effectué avec succés 
//       si == -2 : indique que la procédure de test est gelé
//       si == 0  : indique que la procédure est active, et qu'il n'y a pas eu pour l'instant de pic détecté
//       si > 0   : indique que la procédure est active, et que, de manière consécutive, indique 
//                  le nombre de fois où il y a eu baisse               

      bool relaxation_reactive = false;  // "
      if ((amortissement_cinetique)&&(icharge != 0) && (icharge > nb_deb_test_amort_cinetique))
       { // on regarde si l'énergie cinétique a déjà été calculée, sinon on la calcule
         if (icharge < pa.NbIncrCalEnergie())  // ******* a revoir, car le test n'est peut-être pas suffisant avec tous les algos
             { // initialisation 
               v_int.Change_taille(V.Taille()); v_int.Zero(); 
               // calcul de l'énergie cinétique
               E_cin_tdt = (0.5/coef_mass) * (V * (mat_mass.Prod_vec_mat(V,v_int)));
             };
         // on calcul éventuellement la moyenne glissante
         if (taille_moyenne_glissante > 1)
          { if (nb_Ecin_stocker < taille_moyenne_glissante)
             { // c'est le cas où la moyenne n'est pas finalisée
               nb_Ecin_stocker++; indice_EC1=1;
               sauve_E_cin(nb_Ecin_stocker) = E_cin_tdt;
             }
            else // cas ou la moyenne est finalisée	
             { sauve_E_cin(indice_EC1) = E_cin_tdt;
               indice_EC1++; // mise à jour de l'indice pour le prochain stockage
               // si l'indice dépasse la taille du taille, on remet au début
               if (indice_EC1 > taille_moyenne_glissante) indice_EC1 = 1;
             }; 
            // maintenant on regarde de nouveau si on peut calculer la moyenne
            if (nb_Ecin_stocker == taille_moyenne_glissante)
              {moy_gliss_t = moyenne_glissante; moyenne_glissante = sauve_E_cin.Moyenne();}
            else 	{moy_gliss_t= 0.; moyenne_glissante = 0.;}; // au cas où on met une valeur très grande
          };
         // écriture d'info pour le débug au cas où
         if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3))
            {if (taille_moyenne_glissante == 1)
               {cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn
                     << " pic_E_cint_t= " << pic_E_cint_t << endl;
               }
             else
              {cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn 
                    << "  moyenne_glissante= " << moyenne_glissante	<< " moy_gliss_t= " << moy_gliss_t
                    << " pic_E_cint_t= " << pic_E_cint_t << endl;
              };
            };	 	  
         // --- application de l'algo
         // a) dans le cas où la procédure a été gelée précédemment, on regarde 
         // s'il faut la redémarrer
         if (compteur_decroit_pourRelaxDyn == -2)
           {if (E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn)
              {compteur_decroit_pourRelaxDyn = 0; // indique que l'amortissement est de nouveau active
               relaxation_reactive = true;
              };
           };
         // b) on regarde pour l'application de l'amortissement
         if (compteur_decroit_pourRelaxDyn != -2) // != -2 veut dire que la procédure est active
           {if (taille_moyenne_glissante == 1)
             { 
           
    //debug ------
    //cout << "\n E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl; 
    // fin debug					  
              if ((E_cin_tdt > E_cin_t) && (E_cin_tdt > pic_E_cint_t)) //pic_E_cint_t)
               { 
           
    //debug ------
    //cout << "\n marquage d'un nouveau pic: E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl; 
    // fin debug					  
           
                 pic_E_cint_t = E_cin_tdt;
               } //X_EcinMax = X; 
              max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin);
             }
            else 
             { if ((moyenne_glissante > moy_gliss_t) && (moyenne_glissante > pic_E_cint_t))//pic_E_cint_t)
                { pic_E_cint_t = moyenne_glissante;
                };// X_EcinMax = X; }
               max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin);
             };

            // on considère qu'il y a décroissance, lorsque soit:
            // 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique
            //    ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin
            // 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante
            //    ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin
            // NB: si le pic_E_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide
            if (  ((test_fraction_energie == 0.) &&
                     (   ((taille_moyenne_glissante == 1) && (E_cin_tdt < pic_E_cint_t)) // cas sans moyenne glissante
                  || ((taille_moyenne_glissante != 1) && (moyenne_glissante < pic_E_cint_t)) // cas avec moyenne glissante
                          )
                   )
                  ||
                     ((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente
                       (   ((taille_moyenne_glissante == 1) && (E_cin_tdt < (test_fraction_energie * pic_E_cint_t))) // cas sans moyenne glissante
                  || ((taille_moyenne_glissante != 1) && (moyenne_glissante < (test_fraction_energie * pic_E_cint_t))) // cas avec moyenne glissante
                       )
                     )
              )
             { 
    //debug ------
    //cout << "\n descente: E_cin_tdt " << E_cin_tdt  << " pic_E_cint_t " << pic_E_cint_t << endl; 
    // fin debug					  
               compteur_decroit_pourRelaxDyn++;
               if ((compteur_decroit_pourRelaxDyn >= max_nb_decroit_pourRelaxDyn)
                   && (nb_depuis_derniere_relax >= inter_nb_entre_relax))
                { // cas ou on met en place l'amortissement
                  V.Zero();relaxation_effectuee=true;

                  nb_depuis_derniere_relax = 0;
                  dernier_pic = pic_E_cint_t; // on sauvegarde
                  if (taille_moyenne_glissante != 1) // on remet tout à 0
                    {nb_Ecin_stocker = 0;indice_EC1= 0;};
                  relax_vit=1;
                  compteur_pic_energie++;
                  compteur_decroit_pourRelaxDyn=0;
           
                  if ( dernier_pic == -1) 
    //					    { if (   ((taille_moyenne_glissante != 1) && ( moyenne_glissante < dernier_pic*coef_arret_pourRelaxDyn))
    //						       || ((taille_moyenne_glissante == 1) && ( E_cin_tdt < dernier_pic*coef_arret_pourRelaxDyn)) )
                    { pic_E_cint_t = 0.; // on remet à 0 le pic
                      E_cin_tdt = 0.;
                    }
                  else 	 
                    { if  ( dernier_pic < max_pic_E_cin*coef_arret_pourRelaxDyn)
    //	     	    if (E_cin_tdt <= pic_E_cint_t*coef_arret_pourRelaxDyn)
                 // cas où on suspend l'amortissement pour la suite
                        {compteur_decroit_pourRelaxDyn=-2;}; // inactive l'amortissement
                      pic_E_cint_t = 0.; // on remet à 0 le pic
                      E_cin_tdt = 0.;
                    };
                  E_cinNoe_tdt.Zero();
                  pic_E_cint_t_noe.Zero();
                };
             }
            else // sinon cela signifie que la diminution n'est pas validée donc 
              // on re-initialise le compteur de décroissance (qui sert à valider des décroissances consécutives)
              {compteur_decroit_pourRelaxDyn=0;};
            // c) on regarde s'il faut arrêter le calcul, relativement au delta_ddl, seulement à partir d'un
            // certain nombre de fois que la méthode à été activé
            // ce qui permet d'éviter des pbs au démarrage, pour lequel l'énergie cinétique démarre forcément
            // de 0 puis petit à petit grandie
            // de plus on ne test le delta_ddl que:
            // 1) si on a passé au moins "un" pic d'énergie cinétique (sinon on peut avoir un deltat ddl = 0 car on est presqu'au
            //     maxi et ce maxi = pas du tout l'équilibre !!)
    // non pour l'instant ...		// 2) si l'énergie cinétique est suffisament faible
            compteur_test_pourRelaxDyn++;
            if (compteur_test_pourRelaxDyn > nb_deb_testfin_pourRelaxDyn)
            { if ((max_pic_E_cin != -1)
                  || // on ajoute le cas très particulier où l'énergie cinétique reste nulle
                  ((E_cin_tdt ==0.) && (E_cin_t==0.)) // c'est le cas où rien ne bouge !!
                 )
              { if (delta_ddl.Max_val_abs() <= max_deltaX_pourRelaxDyn) nb_dX_OK_pourRelaxDyn++;
                if (nb_dX_OK_pourRelaxDyn > nb_max_dX_OK_pourRelaxDyn) 
                  { relax_vit = -1;
                    if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3))
                      cout << "\n critere en deplacement ok: max_deltaX= " << delta_ddl.Max_val_abs();
                    nb_dX_OK_pourRelaxDyn=0; // on initialise pour une prochaine fois
                      // dans le cas ou l'arrêt réel n'est pas drivé par le déplacement 
                      // mais par exemple sur le résidu 
                  };
              };	
            };
           }; // -- fin du cas où l'on applique l'amortissement
       };
       
       
      // on tente d'afficher que si l'amortissement a effectivement eu lieu
    //	  if (relax_vit && pa.AfficheIncrEnergie())
      if (relaxation_effectuee)
        {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 2))
         {cout << "\n N:" << icharge << "  relaxation cinetique effectuee "
               << " pic_E_cint_t("<<compteur_pic_energie<<") " << dernier_pic 
               << " max_pic_E_cin= " << max_pic_E_cin;
            //--- info pour le  debug
    /*		  if (ParaGlob::NiveauImpression() > 8)
            {if (taille_moyenne_glissante == 1)
        {cout << "\n nb_Ecin_stocker= " << nb_Ecin_stocker << " indice_EC1= " << indice_EC1  << endl;
        }
       else 
        {cout << "\n nb_Ecin_stocker= " << nb_Ecin_stocker << " indice_EC1= " << indice_EC1 
          << "  moyenne_glissante= " << moyenne_glissante	<< " moy_gliss_t= " << moy_gliss_t << endl;
        };
       };*/
          if (compteur_decroit_pourRelaxDyn == -2) 
            cout << " relaxation_gelee " ;
          if (relaxation_reactive)
            cout << " relaxation_re_active ";
          cout << endl;
         };

        };
    };
#ifdef UTILISATION_MPI
   // on va transférer les infos aux proc i
   v_inter(1) = (double) relaxation_effectuee;
   v_inter(2) = E_cin_tdt;
   v_inter(3) = pic_E_cint_t;
   v_inter(4) = max_pic_E_cin;
 }; // fin de la partie spécifique à proc 0
// envoi à tous les proc
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
v_inter.Broadcast(0);

if (proc_en_cours != 0) // récup pour les proc i
 {// récup des infos pour les proc i
  relaxation_effectuee = (bool) v_inter(1) ;
  E_cin_tdt = v_inter(2);
  pic_E_cint_t = v_inter(3);
  max_pic_E_cin = v_inter(4);
 };
  
//  broadcast(*ParaGlob::Monde(), relaxation_effectuee, 0);
// debug
//cout << "\n debug Algori::AmortissementCinetique "
//         << " barriere transfert relaxation_effectuee , proc= "<< ParaGlob::Monde()->rank() << flush;
    // fin debug
//             ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
  temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
#endif

#ifdef UTILISATION_MPI
//  // debug
//  cout << "\n debug Algori::AmortissementCinetique "
//       << " relaxation_effectué = "<< relaxation_effectuee << " proc= "<< ParaGlob::Monde()->rank() << flush;
//  // fin debug

  if (relaxation_effectuee && (proc_en_cours != 0))
//    if (relaxation_effectuee )
     { V.Zero();
//    // debug
//    cout << "\n debug Algori::AmortissementCinetique "
//         << " mise à 0 du vecteur vitesse, proc= "<< ParaGlob::Monde()->rank() << flush;
//    // fin debug
              
      };
#endif

	 // dans le cas où l'on veut également un amortissement individuel aux noeuds, on appelle la méthode spécifique
  // que si il n'y a pas eu d'amortissement cinétique global
  int relax_vit_individuel = 0;int retour = 0;
	 if (amortissement_cinetique_au_noeud && !relax_vit)
	   { relax_vit_individuel=AmortissementCinetique_individuel_aux_noeuds(delta_ddl,coef_mass,X,mat_mass,icharge,V);
      // ici on a relax_vit = 0 donc le retour est uniquement particularisé par relax_vit_individuel
      retour = relax_vit_individuel;
    }
  else // sinon on est dans le cas où on a seulement un amortissement global et seul relax_vit donne une info à ce sujet
    { retour = relax_vit;};
    
#ifdef UTILISATION_MPI
  temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
  broadcast(*ParaGlob::Monde(), retour, 0);
  temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
//// debug
//cout << "\n debug Algori::AmortissementCinetique  N: " << icharge
//     << " fin, proc= "<< ParaGlob::Monde()->rank() << flush;
//// fin debug
#endif

  return retour;
  
//  la ligne qui suit est fausse car avec un "ou" le résultat est uniquement 1 ou 0, et en particulier
//  les - sont supprimé !! ce qui pose un pb lorsque relax_vit = -1 !! 
//  return (relax_vit||relax_vit_individuel);
  
	};

// méthode interne d'application de l'amortissement cinétique, exploratoire
// cas d'un amortissement local
// retour un int :
    //   = 1  : il y a eu au moins un amortissement 
    //   = 0  : pas d'amortissement
int Algori::AmortissementCinetique_individuel_aux_noeuds(const Vecteur & delta_ddl,const double& coef_mass,const Vecteur& X
                               ,const Mat_abstraite& mat_mass,int icharge,Vecteur& V)
	{int relax_vit = 0;

	 if ((amortissement_cinetique_au_noeud)&&(icharge != 0) && (icharge > nb_deb_test_amort_cinetique_noe))
	  { // on va faire une boucle sur tous les noeuds
     int nbddl = delta_ddl.Taille(); int dim = ParaGlob::Dimension();
	    int NBN = nbddl / dim;
    
     // mise à jour des tailles
     if (E_cinNoe_tdt.Taille() == 0)
       { E_cinNoe_tdt.Change_taille(NBN,0.);E_cinNoe_t.Change_taille(NBN,0.);
         compteur_decroit_pourRelaxDyn_noe.Change_taille(NBN,0);
         dernier_pic_noe.Change_taille(NBN,-1);
         pic_E_cint_t_noe.Change_taille(NBN,-1);
         max_pic_E_cin_noe.Change_taille(NBN,-1);
       };

     // un compteur de relaxation pour info
     int compteur_relaxation_ok=0; // init
     
		   for (int noe =1; noe <= NBN; noe++)
  		  { // on calcul l'énergie pour le noeud
	       bool relaxation_effectuee = false; // initialisation
	       bool relaxation_reactive = false;  // "
        double& eN_cin_tdt = E_cinNoe_tdt(noe);
        double& eN_cin_t = E_cinNoe_t(noe);
        double& pic_eN_cint_t = pic_E_cint_t_noe(noe);
        double& dernier_pic_eN = dernier_pic_noe(noe);
        eN_cin_tdt = 0.; // init
        int ptint = (noe-1)*dim;
        switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
                       case 2: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
                       case 1: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
                     };
/*        switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5  * V(ptint)*V(ptint);
                       case 2: ptint++; eN_cin_tdt += 0.5  * V(ptint)*V(ptint);
                       case 1: ptint++; eN_cin_tdt += 0.5  * V(ptint)*V(ptint);
                     };
*/
	       // --- application de l'algo
        // a) dans le cas où la procédure a été gelée précédemment, on regarde 
	       // s'il faut la redémarrer
        double & max_pic_eN_cin = max_pic_E_cin_noe(noe);
        int & compt_decroit_pourRelaxDyn_noe = compteur_decroit_pourRelaxDyn_noe(noe);
	       if (compt_decroit_pourRelaxDyn_noe == -2)
	        {if (eN_cin_tdt > max_pic_eN_cin * coef_redemarrage_pourRelaxDyn_noe)
	         {compt_decroit_pourRelaxDyn_noe = 0; // indique que l'amortissement est de nouveau active
				       relaxation_reactive = true;
				      };
	        };
	       // b) on regarde pour l'application de l'amortissement
  	     if (compt_decroit_pourRelaxDyn_noe != -2) // != -2 veut dire que la procédure est active
					    { 					  
////debug ------
//if (noe==220)
//{ cout << "\n V(i)= "<<V((noe-1)*dim+1)<<" "<<V((noe-1)*dim+2)<<" "<<V((noe-1)*dim+3)<<" "
//       << mat_mass((noe-1)*dim+1,(noe-1)*dim+1)<<" "<<mat_mass((noe-1)*dim+2,(noe-1)*dim+2)
//       <<" "<<mat_mass((noe-1)*dim+3,(noe-1)*dim+3)<<" ";
//  cout << "\n eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// }
// fin debug
					     if ((eN_cin_tdt > eN_cin_t) && (eN_cin_tdt > pic_eN_cint_t)) //pic_eN_cint_t)
					      { 
////debug ------
//if (noe==220)
//cout << "\n marquage d'un nouveau pic: eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
//// fin debug					  
							      pic_eN_cint_t = eN_cin_tdt;
           }; //X_EcinMax = X;
						    max_pic_eN_cin=MaX(pic_eN_cint_t,max_pic_eN_cin);
         };

		      // on considère qu'il y a décroissance, lorsque soit:
		      // 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique
		      //    ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin
		      // 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante
		      //    ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin
			     // NB: si le pic_eN_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide
			     if (  ((test_fraction_energie == 0.) && (eN_cin_tdt < pic_eN_cint_t))
            ||
              ((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente
		                   (eN_cin_tdt < (test_fraction_energie * pic_eN_cint_t)))
           )
		       { 
//debug ------
//cout << "\n descente: eN_cin_tdt " << eN_cin_tdt  << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// fin debug					  
 		       compt_decroit_pourRelaxDyn_noe++;
          if (compt_decroit_pourRelaxDyn_noe >= max_nb_decroit_pourRelaxDyn_noe)
				       { // cas ou on met en place l'amortissement
             int depart = (noe-1)*dim+1;
             for (int i=0;i<dim;i++)
               V(depart+i)=0.;
//     V(depart+i)*=0.5; // test: on diminue la vitesse par 2 au lieu de la supprimer
////debug ------
//if (noe==220)
//cout << "\n amortissemen:eN_cin_tdt " << eN_cin_tdt << " pic_eN_cint_t " << pic_eN_cint_t << endl;
//// fin debug					  
             relaxation_effectuee=true;
					        dernier_pic_eN = pic_eN_cint_t; // on sauvegarde
					        relax_vit=1;
		           compteur_pic_energie_noe++;
					        compt_decroit_pourRelaxDyn_noe=0;
             compteur_relaxation_ok++; // pour l'affichage éventuelle
				   
					        if ( dernier_pic_eN == -1)
               { pic_eN_cint_t = 0.; // on remet à 0 le pic
							          eN_cin_tdt = 0.;
//							 eN_cin_tdt *= 0.25;  // test, comme la vitesse est diminuée de 2, ecin est diminuée de 4
               }
					        else 	 
					          { if  ( dernier_pic_eN < max_pic_eN_cin*coef_arret_pourRelaxDyn_noe)
					               {compt_decroit_pourRelaxDyn_noe=-2;}; // inactive l'amortissement
							          pic_eN_cint_t = 0.; // on remet à 0 le pic
							          eN_cin_tdt = 0.;
//							 eN_cin_tdt = 0.25; // test, comme la vitesse est diminuée de 2, ecin est diminuée de 4
               };
           };
         }
		      else // sinon cela signifie que la diminution n'est pas validée donc 
		       { // on re-initialise le compteur de décroissance (qui sert à valider des décroissances consécutives)
		         compt_decroit_pourRelaxDyn_noe=0;
         };
	  
////debug ------
//if (relaxation_effectuee && (noe==220))
//{ cout << "\n relaxation:V(i)= "<<V((noe-1)*dim+1)<<" "<<V((noe-1)*dim+2)<<" "<<V((noe-1)*dim+3)<<" "
//       << mat_mass((noe-1)*dim+1,(noe-1)*dim+1)<<" "<<mat_mass((noe-1)*dim+2,(noe-1)*dim+2)
//       <<" "<<mat_mass((noe-1)*dim+3,(noe-1)*dim+3)<<" ";
//  cout << "\n eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// }
//// fin debug					  
	       // on tente d'afficher que si l'amortissement a effectivement eu lieu
	       if (relaxation_effectuee)
         if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 7)) || (permet_affichage > 5))
	        {cout << "\n relax effectue au noeud " << noe
	              << " pic_eN_cint_t("<<compteur_pic_energie_noe<<") " << dernier_pic_eN
	              << " max_pic_eN_cin= " << max_pic_eN_cin;
	         if (compt_decroit_pourRelaxDyn_noe == -2)
	           cout << " relaxation_gelee " ;
		        if (relaxation_reactive)
		          cout << " relaxation_re_activee ";	 
	         cout << endl;
	        };
      }; // fin de la boucle sur les noeuds
     if (compteur_relaxation_ok>0) // affichage global éventuel
      if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 2))
         cout << "\n nb de relaxation individuelle effectuee: " << compteur_relaxation_ok;

	  };// -- fin du cas où l'on applique l'amortissement
		
	  return relax_vit;
	};
    
// pilotage de la convergence, ceci en fonction du type de pilotage choisit
// ramène true si le pas de temps a été modifié, false sinon
// arret = true: indique dans le cas d'une non convergence, neanmoins rien n'a changé, il faut donc arrêter
bool Algori::Pilotage_du_temps(Charge* charge,bool& arret)
  { arret = false; // initialisation
    bool modif_pas_de_temps = false;
    // choix en fonction des différents cas
    switch (pa.TypeDePilotage())
     { case  AUCUN_PILOTAGE: // pas de pilotage
       {if (phase_de_convergence >= 0) // cas normal 
        { // on regarde s'il faut augmenter le paramètre de charge
         if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
          { // cas ou on augmente
        //    modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation());
            // réinitialisation pour la suite
 //           nombre_de_bonnes_convergences = 0;
//				nombre_de_mauvaises_convergences = 0;
           }
         bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit
         // car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier
         modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge
         }
       else
        { // cas ou l'incrément précédent n'a pas convergé
     //    modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution());
     //    if (!modif_pas_de_temps)
          { // dans le cas où il n'y a pas de modification du pas de temps on le signale
            cout << "\n pas de pilotage ===> pas de modification possible du pas de temps"; 
            arret = true;
          }
          bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit
          // car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier
          modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge
          phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
         }
        break;
        }
       case  PILOTAGE_BASIQUE: case PILOT_GRADIENT : // cas du pilotage basique
		   // et également pour le gradient pour l'instant
        {//cout << "\n phase de convergence " << phase_de_convergence << endl;
         if (phase_de_convergence >= 0) // cas normal
          {// on regarde s'il faut augmenter le paramètre de charge
           if (phase_de_convergence < 2)
            {if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
              { // cas ou on augmente le pas de temps
                bool etat_charge= charge->Augmente_inc_charge(pa.Facteur_augmentation());
                modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
                // réinitialisation pour la suite
                nombre_de_bonnes_convergences = 0;nombre_de_mauvaises_convergences=0;
              };
            }
           else // cas la convergence n'a pas été bonne: phase_de_convergence >= 2
            { // on va diminuer l'incrément
              bool etat_charge= charge->Diminue_inc_charge(pa.Fact_dim_en_mauvaiseConv());
              modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
              // réinitialisation pour la suite
              nombre_de_bonnes_convergences = 0;
      // on laisse le nombre de mauvaises convergence nombre_de_mauvaises_convergences = 0; // mais ça a convergé donc on met à 0
            };
          }
         else
          { // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps
           // on revient en arrière
           charge->Precedant(false);
           bool etat_charge= charge->Diminue_inc_charge(pa.Facteur_diminution());
           modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
           if (!modif_pas_de_temps)
            { // dans le cas où il n'y a pas de modification du pas de temps on le signale
              // l'arrêt sera traité par le programme appelant
              cout << "\n Pilotage ===> pas de modification possible du pas de temps";
              arret = true;
             };
           phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
          }
         bool etat_charge= charge->Avance();
         modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
         break;
        };
/*       case  PILOT_GRADIENT: // pour l'instant idem cas du pilotage basique
       {if (phase_de_convergence >= 0) // cas normal
        {// on regarde s'il faut augmenter le paramètre de charge
         if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
          { // cas ou on augmente le pas de temps
            modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation());
            // réinitialisation pour la suite
            nombre_de_bonnes_convergences = 0;
           } 
         } 
        else
        { // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps
         // on revient en arrière
         charge->Precedant(false);
         modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution());
         if (!modif_pas_de_temps)
          { // dans le cas où il n'y a pas de modification du pas de temps on le signale
            // l'arrêt sera traité par le programme appelant
            cout << "\n Pilotage ===> pas de modification possible du pas de temps"; 
            arret = true; 
           }             
         phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
         }
        charge->Avance(); // increment de charge
        break; 
        }
*/		  
       default:
        { cout << "\n erreur le cas de pilotage " << Nom_TypePilotage(pa.TypeDePilotage())
               << " n'est pas implante !!! "
               << "\n Algori::Pilotage_du_temps(... ";
          // dans le cas où un comptage du calcul est en cours on l'arrête
          if (tempsCalEquilibre.Comptage_en_cours())
                  tempsCalEquilibre.Arret_du_comptage();
          Sortie(1);
        }; 
      }; // fin des différents cas de pilotage  
     // retour de l'information sur la modification ou non du pas de temps
//debug
//cout << "\n Algori::Pilotage_du_temps: phase_de_convergence=" << phase_de_convergence 
//     << " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences
//	  << " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl  ;
//fin debug
     cout << flush; // pour que l'on puisse voir quelque chose ! en cours de calcul en particulier s'il y a pb
     return modif_pas_de_temps;
    };

// pilotage de la fin des itération en implicite : utilisation conjointe avec: Pilotage_du_temps()
// ramène vraie si la convergence est correcte, sinon false
bool Algori::Pilotage_fin_iteration_implicite(int compteur)
  {  bool fin_iter = false;
     if (a_converge)
      { if (compteur < pa.Nb_iter_pour_bonne_convergence())
          { // cas où le calcul a convergé en moins de pa.Nb_iter_pour_bonne_convergence
            nombre_de_bonnes_convergences++; // incrémentation de la bonne convergence
            nombre_de_mauvaises_convergences=0;
            phase_de_convergence = 1; //signalement pour Pilotage_du_temps 
           }
         else if (compteur > (pa.Nb_iter_pour_mauvaise_convergence()))
          { // cas où on considère que la convergence n'a pas été bonne et qu'il vaut mieux diminuer l'incrément
            // pour la prochaine fois, on efface également le nombre de bonnes convergences
            nombre_de_bonnes_convergences = 0;
            nombre_de_mauvaises_convergences++;
         	  phase_de_convergence = 2;	
         	}
         else // cas où c'est ni très bon, ni très mauvais, on laisse en l'état
         	{ phase_de_convergence = 1; //signalement pour Pilotage_du_temps
				        nombre_de_bonnes_convergences=0;
				        nombre_de_mauvaises_convergences=0;				 
         	}; 
//		  nombre_de_mauvaises_convergences = 0; // dans tous les cas on a convergé		            
        fin_iter = true; // on signale qu'il y a eu convergence et que l'on a fini les itérations
      }
     else if (compteur > pa.Iterations()) 
      {  nombre_de_mauvaises_convergences++;
			      nombre_de_bonnes_convergences = 0;
         if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
					     { cout << "\n============================================================================"
						           << "\n   ******* NON convergence des iterations d'equilibre ********* "
						           << "\n============================================================================";
          }
				     else 
					     { cout << "\n============================================================================="
						           << "\n *** NON convergence of the balance iteration                           ***** "
						           << "\n=============================================================================";
						    };
         phase_de_convergence = -1; //signalement pour Pilotage_du_temps    
         fin_iter = false; // on signale qu'il n'y a pas convergence
      }
     else if (phase_de_convergence == -2) // cas où c'est Convergence() qui est la cause de l'arret
                                          // pour cause d'évolution divergente des résidus
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
					    { cout << "\n============================================================================"
						          << "\n  *** NON convergence equilibre: evolution divergente des residus ********* "
						          << "\n============================================================================";
         }
				    else 
         { cout << "\n============================================================================="
						          << "\n *** NON convergence of balance: divergente evolution of the residues   ***** "
						          << "\n=============================================================================";
						   };
        fin_iter = false; // on signale qu'il n'y a pas convergence
				    nombre_de_bonnes_convergences=0;
				    nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -3) // cas où c'est Convergence() qui est la cause de l'arret
                                          // pour cause de variation de ddl minimal atteinte
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
          { cout << "\n============================================================================"
                 << "\n  *** NON convergence equilibre: variation de ddl minimal atteinte ********* "
                 << "\n============================================================================";
          }
        else 
          { cout << "\n============================================================================="
                 << "\n *** NON convergence of balance: reaching of the minimum allowed of ddf ***** "
                 << "\n=============================================================================";
          };
        fin_iter = false; // on signale qu'il n'y a pas convergence
				    nombre_de_bonnes_convergences=0;
				    nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -4) // cas où c'est Convergence() qui est la cause de l'arret
                                          // pour cause de variation de ddl maximal atteinte
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
					     { cout << "\n============================================================================"
								         << "\n  *** NON convergence equilibre: variation de ddl maximum atteinte ********* "
								         << "\n============================================================================";
						    }
				    else
          { cout << "\n============================================================================="
								         << "\n *** NON convergence of balance: reaching of the maximum allowed of ddl ***** "
								         << "\n=============================================================================";
						    };
				    nombre_de_bonnes_convergences=0;
				    nombre_de_mauvaises_convergences++;
        fin_iter = false; // on signale qu'il n'y a pas convergence
      }
     else if (phase_de_convergence == -5) // cas d'un arrêt à cause d'un jacobien négatif, qui est géré
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         { cout << "\n============================================================================"
                << "\n  *** NON convergence due a la gestion de jacobien negatif         ********* "
								        << "\n============================================================================";
         }
				    else
					    { cout << "\n============================================================================"
								        << "\n  *** NON convergence due to the management of negative jacobian  ********* "
								        << "\n============================================================================";
						   };
       fin_iter = false; // on signale qu'il n'y a pas convergence
				   nombre_de_bonnes_convergences=0;
				   nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -6) // cas d'un arrêt à cause d'une variation de jacobine trop grande
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         { cout << "\n============================================================================"
								        << "\n  *** NON convergence due a une variation de jacobien trop grande ********* "
								        << "\n============================================================================";
						   }
				    else
					     { cout << "\n============================================================================"
								         << "\n  *** NON convergence due to a too big variation of the jacobian  ********* "
								         << "\n============================================================================";
						    };
        fin_iter = false; // on signale qu'il n'y a pas convergence
				    nombre_de_bonnes_convergences=0;
				    nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -7) // cas d'un arrêt à cause d'une non convergence de la loi de comp
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
			       {if(ParaGlob::Francais())
					       { cout << "\n============================================================================"
								           << "\n  *** NON convergence due a la loi de comportement                 ********* "
								           << "\n============================================================================";
						      }
				       else
					       { cout << "\n============================================================================"
								           << "\n  *** NON convergence due to the material behaviour               ********* "
								           << "\n============================================================================";
						      };
				      };
        fin_iter = false; // on signale qu'il n'y a pas convergence
        nombre_de_bonnes_convergences=0;
        nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -8) // cas d'un arrêt à cause d'une non convergence de la loi de comp
      // mais pour un pb qui couve depuis plusieurs incréments
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         {if(ParaGlob::Francais())
            { cout << "\n============================================================================"
                   << "\n  *** NON convergence du a la loi de comportement                 ********* "
                   << "\n  ***  probablement due a des erreurs sur plusieurs increments    ********* "
                   << "\n============================================================================";
            }
          else 
            { cout << "\n============================================================================"
                   << "\n  *** NON convergence due to the material behaviour               ********* "
                   << "\n  ***  probably due to  errors along several increments           ********* "
                   << "\n============================================================================";
            };
         };
        fin_iter = false; // on signale qu'il n'y a pas convergence
        nombre_de_bonnes_convergences=0;
        nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -9) // cas d'un arrêt à cause d'un pb de la résolution du syteme linéaire
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         {if(ParaGlob::Francais())
            { cout << "\n=============================================================================="
                   << "\n  *** NON convergence due a un pb de resolution du systeme lineaire    ********* "
                   << "\n==============================================================================";
            }
          else 
            { cout << "\n================================================================================="
                   << "\n  *** NON convergence due to the resolution of the global linear system  ********* "
                   << "\n=================================================================================";
            };
         };
         fin_iter = false; // on signale qu'il n'y a pas convergence
         nombre_de_bonnes_convergences=0;
         nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -10) // cas d'un arrêt à cause d'un pb de calcul des efforts extérieurs
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         {if(ParaGlob::Francais())
            { cout << "\n=============================================================================="
                   << "\n  *** NON convergence due a un pb de calcul des efforts exterieurs    ********* "
                   << "\n==============================================================================";
            }
          else
            { cout << "\n================================================================================="
                   << "\n  *** NON convergence due to extern loading problem  ********* "
                   << "\n=================================================================================";
            };
         };
         fin_iter = false; // on signale qu'il n'y a pas convergence
         nombre_de_bonnes_convergences=0;
         nombre_de_mauvaises_convergences++;
      }
     else if (phase_de_convergence == -11) // cas d'un arrêt à cause d'un nan ou infini sur forces ext, int
      { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         {if(ParaGlob::Francais())
            { cout << "\n=============================================================================="
                   << "\n *** NON convergence due a un nan ou infini sur forces int, ext, totales ********* "
                   << "\n==============================================================================";
            }
          else
            { cout << "\n================================================================================="
                   << "\n  *** NON convergence due to nan value   ********* "
                   << "\n=================================================================================";
            };
         };
         fin_iter = false; // on signale qu'il n'y a pas convergence
         nombre_de_bonnes_convergences=0;
         nombre_de_mauvaises_convergences++;
      }
     else // cas d'une erreur de pilotage: on ne sait pas pourquoi il s'est arrêté sans convergence
         { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
			          {if(ParaGlob::Francais())
					          {cout << "\n cas de pilotage de fin d'iteration inconnues ? ou alors qui suit une erreur signalee precedemment ";
                if (ParaGlob::NiveauImpression() > 5)
                   cout  << "\n   bool Pilotage_fin_iteration_implicite(int compteur) ";
                cout << endl;
               }
				          else {cout << "\n unknown case of management for the end of iteration or, following an error  ";
							             if (ParaGlob::NiveauImpression() > 5)
                      cout  <<  "\n   bool Pilotage_fin_iteration_implicite(int compteur) ";
                    cout << endl;
                   };
			          };
           // si il ne s'agit pas d'une sortie voulue des itérations et incréments
           // on s'arrête
           if (!(pa.EtatSortieEquilibreGlobal()))
             { // dans le cas où un comptage du calcul est en cours on l'arrête
               if (tempsCalEquilibre.Comptage_en_cours())
                  tempsCalEquilibre.Arret_du_comptage();
               Sortie(1);
             };
           // sinon on continue
         }
     return fin_iter;
//debug
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
 { cout << "\n Algori::Pilotage_fin_iteration_implicite: phase_de_convergence=" << phase_de_convergence
        << " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences
	       << " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl ;
 };
//fin debug
		
    };
		 
 // pilotage spécifique de la fin de la relaxation dynamique, en tenant compte des différents critères demandés
 // relax_vit_acce :    
 //   = 1  : il y a eu relaxation mais le calcul continue
 //   = 0  : pas de relaxation
 //   = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait
 // compteur: indique le nombre d'itération ou d'incrément en cours
 // iter_ou_incr : =1: il s'agit d'itération", =0 il s'agit d'incrément 
 // lit arret, puis modifie arret en true ou false = il faut arrêter ou non
 // si true met à jour en interne certains paramètres de gestion de pilotage pour dire que l'on a bien convergé
bool	Algori::Pilotage_fin_relaxation_et_ou_residu(const int& relax_vit_acce,const int& iter_ou_incr,
                                                 const int& compteur, const bool& arretResidu, bool& arret)
  {
    // pour mémoire: arret_a_equilibre_statique indique, si diff de 0, que l'on veut contrôler une convergence vers la solution
		  // statique. Si = 1: le residu statique est utilise comme critere
		  //           si = 2: nécessite que les deux critères précédents soient satisfait                   
	  
    // examen de la convergence éventuelle, utilisant le déplacement et/ou le résidu
  #ifdef UTILISATION_MPI
    int proc_en_cours = ParaGlob::Monde()->rank();
    // === première partie commune à tous les proc
    // normalement tous les buffers ont été rempli, on se contente de rediriger les flux
  #endif
		  string nom="l'iteration"; if (!iter_ou_incr) nom = "l'increment";
    switch (relax_vit_acce)
    { case -1: // cas où le critère en déplacement est ok
       {if (!arret_a_equilibre_statique) // cas ou on ne considère pas l'équilibre en résidu
              {arret=true;a_converge = true;
            #ifdef UTILISATION_MPI
               if (proc_en_cours == 0)
            #endif
                 cout << "\n   critere en deplacement satisfait pour "<< nom << " : "  << compteur
                      << "  max_deltaX= " <<delta_X.Max_val_abs() << endl;
              }
        else if ((arret_a_equilibre_statique==2) && arretResidu) // cas ou  considère l'équilibre en résidu et en amortissement cinétique
              {arret=true;a_converge = true;
            #ifdef UTILISATION_MPI
               if (proc_en_cours == 0)
            #endif
                 cout << "\n   critere en deplacement et en residu satisfait pour "<< nom << " : "
                      << compteur << "  max_deltaX= " <<delta_X.Max_val_abs()  <<endl;
              }
        
       }
       break;
      case 0: case 1: // cas où le critère en déplacement n'est pas satisfait ou qu'il y a eu une relaxation (donc pas encore de convergence)
       {if ( (arret_a_equilibre_statique==1) && arretResidu) // cas du critère en résidu uniquement
          {arret=true;a_converge = 1;
        #ifdef UTILISATION_MPI
           if (proc_en_cours == 0)
        #endif
             cout << "\n   critere equilibre statique satisfait pour "<< nom << " : "  << compteur << " " <<endl;
          }
        else // sinon on est pas avec un contrôle avec le résidu donc on se base uniquement sur le déplacement
         {arret=false;a_converge = false;}
       }
       break;

     default:
       cout << "\n *** erreur: relax_vit_acce= "<<relax_vit_acce
            << "\n ce cas n'est pas prevu... \n Algori::Pilotage_fin_relaxation_et_ou_residu(...";
       Sortie(1);
       break;
   };
   
   
//    if (relax_vit_acce == -1) // en amortissement cinétique, on a convergé
//       {if (!arret_a_equilibre_statique) // cas ou on ne considère pas l'équilibre en résidu
//              {arret=true;a_converge = 1;
//               cout << "\n   critere en deplacement satisfait pour "<< nom << " : "  << compteur << " " <<endl;
//              }
//        else if ((arret_a_equilibre_statique==2) && arretResidu) // cas ou  considère l'équilibre en résidu et en amortissement cinétique
//              {arret=true;a_converge = 1;
//               cout << "\n   critere en deplacement et en residu satisfait pour "<< nom << " : "
//                    << compteur << " " <<endl;
//              }
//
//       }
//    else if ( (arret_a_equilibre_statique==1) && arretResidu) // cas du critère en résidu uniquement
//        {arret=true;a_converge = 1;
//         cout << "\n   critere equilibre statique satisfait pour "<< nom << " : "  << compteur << " " <<endl;
//        };
		  return arret;
		};	    

// pilotage à chaque itération: 
//    - sous ou sur relaxation
//    - limitation de la norme de delta ddl
//    - indication de précision pour les éléments (utilisée pour certain type de gestion d'hourglass)
// en entrée: le maxi de var ddl juste après résolution
// ramène le maxi de var ddl maxDeltaDdl modifié, ainsi que sol modifié éventuellement, 
void Algori::Pilotage_chaque_iteration(Vecteur* sol,double& maxDeltaDdl,const int& itera,LesMaillages * lesMail)
{ // -- sur ou sous relaxation
  double sursousrelax = pa.SurSousRelaxation();
  (*sol) *= sursousrelax; 
  if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 3)) || (permet_affichage > 2))
  if (sursousrelax != 1.)
			{if(ParaGlob::Francais())
			    {cout << "\n intervention d'une sur-sous relaxation:  ";}
			 else {cout << "\n intervention of an over or under relaxation: ";};
			 cout << sursousrelax;
			};	 
  // --limitation de la norme de delta ddl 
  // dans le cas où le maxi de variation de ddl est supérieur à la limite fixée on ramène la valeur
  if (pa.NormeMax_increment() > 0.)
   {// cas d'une limitation globale (tout le vecteur sol change
    if (maxDeltaDdl > pa.NormeMax_increment()) 
     { double facteur=(pa.NormeMax_increment()/maxDeltaDdl);
       if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
				    {if(ParaGlob::Francais())
				         {cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl ";}
         else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof ";};
			      cout << facteur;		 
				    };
       (*sol) *= facteur;
       // mise à jour  du maxi de variation de ddl  
       maxDeltaDdl = pa.NormeMax_increment();        
     };
   }
  else // ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
   {// cas d'une limitation globale (tout le vecteur sol change
    if (maxDeltaDdl > Abs(pa.NormeMax_increment())) 
     { double maxa= Abs(pa.NormeMax_increment());
       Vecteur & vect = *sol; // pour simplifier
       int taill=vect.Taille();
       bool modif = false;
       for (int i=1;i<= taill;i++)
         { if (Abs(vect(i)) > maxa) 
            { vect(i) = Signe(vect(i),maxa); modif = true;};
         };
       if (modif) 
         {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
				       {if(ParaGlob::Francais())
					            {cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl, limitation des maxis ";}
					       else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof, limitation of the maxis ";};
						     };	 
				     };
          // mise à jour  du maxi de variation de ddl  
          maxDeltaDdl = maxa;        
     };
   }; 
		
	 // -- indication de précision pour les éléments (utilisée pour certain type de gestion d'hourglass)
	 // pour l'instant l'idée est la suivante: si le résidu augmente => on demande un calcul précis sur les éléments
	 // pour le prochain calcul
  int nb_cycle_controle = MaX(2,pa.NbCycleControleResidu());
	 if (itera == 0)
	  { lesMail->Drapeau_preparation_calcul_precis(10);} // par défaut à l'itération 0 on demande un calcul précis
  if (itera > 1)
	  { bool change = false; // indicateur pour la demande d'un calcul précis		
		   if (itera <= nb_cycle_controle)
		     { if (max_var_residu(itera) > max_var_residu(itera-1)) change = true;}
     else { if (max_var_residu(nb_cycle_controle) > max_var_residu(nb_cycle_controle-1)) change = true;};
		   if (change) // dans le cas où le résidu augmente => on demande un calcul précis sur les éléments
		     { lesMail->Drapeau_preparation_calcul_precis(4);}
		   else {lesMail->Drapeau_preparation_calcul_precis(4);}; // sinon pas de modif
   };
};

// pilotage pour l'initialisation de Xtdt à chaque début d'incrément, en implicite
// avec la même direction qu'au pas précédent
// ramène true, si c'est ok pour initialiser Xtdt 
bool Algori::Pilotage_init_Xtdt()
 { return (nombre_de_mauvaises_convergences <= 2); 
  };

 
// pilotage en dynamique implicite, du maxi des déplacements et/ou vitesses
// limitation spécifiquement des maxi en déplacements et/ou vitesses
// il y a calcul éventuel de delta_X, mais c'est considéré comme une variable de travail
void Algori::Pilotage_maxi_X_V(const Vecteur& X_t,Vecteur& X_tdt,const Vecteur& V_t,Vecteur& V_tdt)
{ // --limitation de la norme de delta X
  // dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur
  double normeMax_X_increment = pa.NormeMax_X_increment();
  if ((normeMax_X_increment > 0.)&&( normeMax_X_increment!= ConstMath::tresgrand))
   {// cas d'une limitation globale sur X
    if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille());
    vec_trav = X_tdt; vec_trav -= X_t;
    double maxDeltaDdl=vec_trav.Max_val_abs();
    if (maxDeltaDdl > normeMax_X_increment)
     { double facteur=(normeMax_X_increment/maxDeltaDdl);
       if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
				    {if(ParaGlob::Francais())
				         {cout << "\n ===>>>>> intervention de la reduction du vecteur delta X ";}
         else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X ";};
			      cout << facteur << "( maxDeltaX= " << maxDeltaDdl<<")";
				    };
       vec_trav *= facteur;
       X_tdt = X_t; X_tdt += vec_trav;
     };
   }
  else if ( normeMax_X_increment!= ConstMath::tresgrand)
  // cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
   {// cas d'une limitation globale (tout le vecteur sol change
    int taill=X_t.Taille();
    if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille());
    vec_trav = X_tdt; vec_trav -= X_t;
    double maxDeltaDdl=vec_trav.Max_val_abs();
    if (maxDeltaDdl > -normeMax_X_increment)
     { double maxa= -normeMax_X_increment;
       bool modif = false;
       for (int i=1;i<= taill;i++)
         { if (Abs(vec_trav(i)) > maxa)
            { vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;};
         };
       if (modif) 
         {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
				       {if(ParaGlob::Francais())
					            {cout << "\n ===>>>>> intervention de la reduction du vecteur delta X, limitation des maxis ";}
					       else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X, limitation of the maxis ";};
						     };	 
          X_tdt = X_t; X_tdt += vec_trav;
				     };
     };
   };
 
// --limitation de la norme de delta V
  // dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur
  double normeMax_V_increment = pa.NormeMax_V_increment();
  if ((normeMax_V_increment > 0.)&&( normeMax_V_increment!= ConstMath::tresgrand))
   {// cas d'une limitation globale sur V
    if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille());
    vec_trav = V_tdt; vec_trav -= V_t;
    double maxDeltaDdl=vec_trav.Max_val_abs();
    if (maxDeltaDdl > normeMax_V_increment)
     { double facteur=(normeMax_V_increment/maxDeltaDdl);
       if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
				    {if(ParaGlob::Francais())
				         {cout << "\n ===>>>>> intervention de la reduction du vecteur delta V ";}
         else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V ";};
			      cout << facteur ;
				    };
       vec_trav *= facteur;
       V_tdt = V_t; V_tdt += vec_trav;
     };
   }
  else if ( normeMax_V_increment!= ConstMath::tresgrand)
    // cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
   {// cas d'une limitation globale (tout le vecteur sol change
    int taill=V_t.Taille();
    if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille());
    vec_trav = V_tdt; vec_trav -= V_t;
    double maxDeltaDdl=vec_trav.Max_val_abs();
    if (maxDeltaDdl > -normeMax_V_increment)
     { double maxa= -normeMax_V_increment;
       bool modif = false;
       for (int i=1;i<= taill;i++)
         { if (Abs(vec_trav(i)) > maxa)
            { vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;};
         };
       if (modif) 
         {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 0))
				       {if(ParaGlob::Francais())
					            {cout << "\n ===>>>>> intervention de la reduction du vecteur delta V, limitation des maxis ";}
					       else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V, limitation of the maxis ";};
						     };	 
          V_tdt = V_t; V_tdt += vec_trav;
				     };
     };
   }; 
 
};

// passage des grandeurs gérées par l'algorithme de tdt à t
// en particulier les énergies et les puissances
void Algori::TdtversT()
 {  // cas du calcul des énergies, passage des grandeurs de tdt à t
     // les énergies globales
    E_cin_t=E_cin_tdt; E_int_t = E_int_tdt; E_ext_t = E_ext_tdt;
    // la quantité de mouvement globale
    q_mov_t = q_mov_tdt; 
     // les forces internes et externes généralisées
    F_int_t = F_int_tdt;  F_ext_t = F_ext_tdt; 
     // l'énergie visqueuse numérique
    E_visco_numerique_t=E_visco_numerique_tdt;

    // les puissances
    P_acc_t = P_acc_tdt; P_int_t = P_int_tdt; P_ext_t = P_ext_tdt; bilan_P_t = bilan_P_tdt;
  
    // cas particulier de l'amortissement cinétique à chaque noeud
    if (amortissement_cinetique_au_noeud)
       E_cinNoe_t = E_cinNoe_tdt;

 };                                          

// vérification d'une singularité éventuelle de la matrice de raideur de dim: nbddl 
// pour un problème de mécanique, en comparant le nombre de point d'intégration total 
// et le nombre totale de degré de liberté 
void Algori::VerifSingulariteRaideurMeca(int nbddl,const LesMaillages& lesMail) const
	{
   #ifdef UTILISATION_MPI
   // cas d'un  calcul //, seule la matrice du CPU 0 est concernée
   if (ParaGlob::Monde()->rank() != 0)
     return ;
   #endif
   if (ParaGlob::NiveauImpression() != 0)
	   {  // récup du nombre de grandeurs génératrices
//       Enum_ddl enu(SIG11); // init par défaut
     
       // on récupère la liste des problèmes physiques gérés par les éléments de tous les maillages
       const list <Enum_ddl >& li = lesMail.Ddl_representatifs_des_physiques();
       // on boucle sur la liste
       list <Enum_ddl >::const_iterator ili,iliend = li.end();
       int nbpt=0; // init
       for (ili = li.begin();ili != iliend; ili++)
        nbpt += lesMail.NbTotalGrandeursGeneratrices(*ili);
       // affichage
       const double ratio = 1.2; // le pourcentage
       if (nbpt < ratio * nbddl)
         if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
         	{ cout << "\n *** Attention, le nombre total de grandeurs generatrices aux point d'integrations dans "
         	       << " le probleme: " << nbpt << "  est inferieur "
         	       << " a " << ratio << " * le nombre total de ddl du probleme !! c-a-d: "<< int(ratio * nbddl)
         	       << "\n en consequence il est possible que la matrice de raideur soit naturellement singuliere \n\n ";
               if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 7)) || (permet_affichage > 0))
                 cout << "\n void Algori::VerifSingulariteRaideurMeca(... ";      
         	};
	   };
	};                                         
        
// retouve le numéro de l'incrément sauvegardé trouvé dont le numéro est juste inf ou égale au 
// dernier incrément calculé  - nb_incr_en_arriere.
// ramène false si on n'a pas trouvé d'incrément a-doc
// en retour icharge prend la valeur de l'incrément trouvé (si tout c'est bien passé)
bool Algori::Controle_retour_sur_un_increment_enregistre(int nb_incr_en_arriere,int& icharge)        
{   // tout d'abord on calcul le numéro d'incrément auquel il faut se placer
    List_io <Entier_et_Double>::iterator inc_ok = list_incre_temps_calculer.begin();
    List_io <Entier_et_Double>::iterator inc_fin = list_incre_temps_calculer.end();
    for (int i=1;i<=nb_incr_en_arriere;i++)
     if (inc_ok != inc_fin)
       {inc_ok++;  } // les incréments sont rangés du dernier vers le premier
     else
       {return false;}; // sinon l'opération n'est pas possible 
    // donc inc_ok  représente maintenant le num maxi à partir duquel on va chercher un incrément enregistré
    List_io <Entier_et_Double>::iterator in_sauve =  list_incre_temps_sauvegarder.begin(); 
    List_io <Entier_et_Double>::iterator in_sauve_fin =  list_incre_temps_sauvegarder.end(); 
    // on recherche le premier incrément sauvegardé juste inf à celui que l'on s'est fixé
    while (((*in_sauve).n > (*inc_ok).n)&&(in_sauve != in_sauve_fin))
       in_sauve++;
    // on vérifie que l'incrément est valide sinon on est obligé d'arrêter
    if (in_sauve == in_sauve_fin)
    	{return false;}; // opération non possible
    // sinon c'est ok 
    icharge = (*in_sauve).n;
    return true;
};

// cohérence du type de convergence adopté en fonction de l'algorithme: par exemple on vérifie que l'on n'utilise
// pas une convergence sur l'énergie cinétique avec un algo statique !!
void Algori::Coherence_Algo_typeConvergence()
 { if ((Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE) 
       && (strstr(pa.Norme().nom1.c_str(),"E_cinetique/E_statique"))
		 && (Evolution_temporelle_du_calcul(typeCalcul) != AUCUNE_EVOLUTION))
	    { cout << "\n *** erreur: utilisation de la norme E_cinetique/E_statique avec un calcul non dynamique"
	           << " arret ! ";
       if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5)) || (permet_affichage > 0))
	         cout << "\n Algori::Coherence_Algo_typeConvergence() ";
       // dans le cas où un comptage du calcul est en cours on l'arrête
       if (tempsCalEquilibre.Comptage_en_cours())
           tempsCalEquilibre.Arret_du_comptage();
	      Sortie(1);
	    };
 };



