// 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 "AlgoriCombine.h"
#include "TypeQuelconqueParticulier.h"
#include "Fonction_expression_litterale_nD.h"

// CONSTRUCTEURS :
AlgoriCombine::AlgoriCombine() : // par defaut
   Algori()
  {// a priori ce constructeur n'est pas utilisé
   cout << "\n $$$$$$$$$ a priori ce constructeur n'est pas utilisable $$$$$$$ "
        << "\n revoir: AlgoriCombine::AlgoriCombine() " << endl;
   Sortie(1);
  };
     
// constructeur en fonction du type de calcul et du sous type
// il y a ici lecture des parametres attaches au type
AlgoriCombine::AlgoriCombine (const bool avec_typeDeCal
                              ,const list <EnumSousTypeCalcul>& soustype
                              ,const list <bool>& avec_soustypeDeCal
                              ,UtilLecture& entreePrinc) :
    Algori(COMBINER,avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc)
    // --------------------------------------------------------------------------------------
    // -- variables privées --
    // --------------------------------------------------------------------------------------
    ,tab_algo()
    ,nom_choix_algo(""),choix_algo(NULL),nom_gestion_sauvegarde(""),gestion_sauvegarde(NULL)
    ,nb_dernier_algo_qui_a_fait_une_sauvegarde(0)
    ,gestion_sortie_a_convergence(NULL),nom_gestion_sortie_a_convergence("")
    ,tb_combiner(NULL),cst_0(NULL),cst_1(NULL)
    // des infos définit en local pour les péréniser
    ,list_sousTypeCalcul(),list_avec_sousCalcul()

  { // puis lecture des paramètres attachés au type de calcul
    switch (entreePrinc.Lec_ent_info())
      { case 0 :
         {// il s'agit tout d'abord de lire les différents algos
          Lecture_algo_interne(avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc);
          // appel de la méthode de lecture de paramètre
          lecture_Parametres(entreePrinc); break;}
        case -11 : // cas de la création d'un fichier de commande
         { Info_commande_parametres(entreePrinc); break;}
        case -12 : // cas de la création d'un schéma XML, on ne fait rien à ce niveau
         {  break;}
        default:
          Sortie(1);
      };
    Creation_fct_cst(); // création de cst_0 et cst_1
   };
      
// constructeur de copie
AlgoriCombine::AlgoriCombine (const AlgoriCombine& algo):
    Algori(algo)
    // --------------------------------------------------------------------------------------
    // -- variables privées --
    // --------------------------------------------------------------------------------------
    ,tab_algo(algo.tab_algo)
    ,nom_choix_algo(algo.nom_choix_algo),choix_algo(NULL)
    ,nom_gestion_sauvegarde(algo.nom_gestion_sauvegarde),gestion_sauvegarde(NULL)
    ,nb_dernier_algo_qui_a_fait_une_sauvegarde(0)
    ,gestion_sortie_a_convergence(NULL)
    ,nom_gestion_sortie_a_convergence(algo.nom_gestion_sortie_a_convergence)
    ,tb_combiner(NULL),cst_0(NULL),cst_1(NULL)
    // des infos définit en local pour les péréniser
    ,list_sousTypeCalcul(algo.list_sousTypeCalcul),list_avec_sousCalcul(algo.list_avec_sousCalcul)
    { // les algorithmes
      list <list<EnumSousTypeCalcul> >::iterator  ili=list_sousTypeCalcul.begin();
      list <list<bool> >::iterator ala=list_avec_sousCalcul.begin();
      // les listes sont rangées : la première -> le dernier algo, etc.
      int nb_algo = algo.tab_algo.Taille();
      if (nb_algo)
       {for (int i=nb_algo;i>0;i--,ili++,ala++)
          {tab_algo(i) = New_idem(algo.tab_algo(i));
           // mise à jour des pointeurs relatifs aux types de calculs et sous types internes
           tab_algo(i) -> Change_affectation_pointeur_sous_type((*ili),(*ala));
          };
       };
      Creation_fct_cst(); // création de cst_0 et cst_1
      // on renseigne la variable: ptalgocombi de la classe Algori pour tous les sous-algo
      for (int i=1;i<=nb_algo;i++)
        tab_algo(i)->Change_ptalgocombi (this);

    };

// destructeur
AlgoriCombine::~AlgoriCombine ()
  { // les algorithmes
    if (tab_algo.Taille())
     {for (int i=1;i<= tab_algo.Taille();i++)
       delete tab_algo(i);
     };
    tab_algo.Libere();
    // les fonctions constantes
    delete cst_0;
    delete cst_1;
    // les autres fonctions sont globales, donc à ne pas supprimer !!
  };

//lecture des parametres de controle
// peut être modifié dans le cas d'un algo particulier
void AlgoriCombine::Lecture(UtilLecture & entreePrinc,ParaGlob & paraglob,LesMaillages&  lesMail)
  { // --- on commence par lire les infos concernant les paramètres généraux via la méthode par défaut
    Algori::Lecture(entreePrinc,paraglob,lesMail);
    // --- ces paramètres permettent d'initialiser les paramètres d'algo internes
    int nb_algo = tab_algo.Taille();
    for (int i=1;i<=nb_algo;i++)
      tab_algo(i)->Init_ParaAlgoControle(pa);
    // lecture des paramètres d'algo spécifiques à chaque algo
    MotCle motCle; // ref aux mots cle
    // on se positionne sur un mot cle
    while ( !motCle.SimotCle(entreePrinc.tablcar))
           entreePrinc.NouvelleDonnee();
    // PARA_SPECIFIQUE_SOUS_ALGO
    string nom; int num_algo=0;
    int val_defaut = 0;
    const string nom_class_methode("AlgoriCombine::Lecture");
    int min = 1; int max=nb_algo; string mot_cle("==PARA_SPECIFIQUE_SOUS_ALGO==");
    if (strstr(entreePrinc.tablcar,"==PARA_SPECIFIQUE_SOUS_ALGO==")!=NULL)
     {// a priori on a des paramètres spécifiques
      while (strstr(entreePrinc.tablcar,"==PARA_SPECIFIQUE_SOUS_ALGO==")!=NULL)
       {// on récupère le num d'algo
        bool lec_eff =  entreePrinc.Lecture_un_parametre_int(val_defaut,nom_class_methode
                 ,min,max,mot_cle,num_algo);
        if (lec_eff && (num_algo != 0))
         {// on lit les paramètres spécifiques de l'algo
          entreePrinc.NouvelleDonnee();
          tab_algo(num_algo)->pa.Lecture_paraAlgoControle(entreePrinc);
         }
        else // sinon pb
         { cout << "\n *** erreur en lecture de parametres specifiques d'algo interne "
                << "\n AlgoriCombine::Lecture(.. ";
           Sortie(1);
         };
       entreePrinc.NouvelleDonnee();
      };
     };
    // on met à jour certains conteneurs internes des sous-algo
    for (int i=1;i<=nb_algo;i++)
       tab_algo(i)->Preparation_conteneurs_interne(lesMail);
  };

// execution de l'algorithme dans le cas non dynamique, implicit, sans contact
void AlgoriCombine::Execution(ParaGlob * paraGlob,LesMaillages * lesMail
               ,LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
               ,VariablesExporter* varExpor,LesLoisDeComp* lesLoisDeComp, DiversStockage* divStock
               ,Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
  {
    Tableau < Fonction_nD* > * tb_combiner = NULL;
    // on définit le type de  calcul a effectuer :
    if ( soustypeDeCalcul->size()==0 )
      // cas où il n'y a pas de sous type, on fait le calcul d'équilibre classique
      // signifie que le type principal est forcément valide
       { // initialisation du calcul : deux cas, soit avec une lecture initiale du .info, soit une lecture secondaire
         if (paraGlob->EtatDeLaLecturePointInfo() == 0)
              {InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );}
         else {MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );
              };
         // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
         // bref que l'on n'a pas fini, sinon on passe
         if (! (charge->Fin(icharge,true) ) )
          { // calcul de l'équilibre
            CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats
                              ,tb_combiner);
            // fin du calcul, pour l'instant on ne considère pas les autres sous-types
            FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );
          };
       }
    else
     {if ( avec_typeDeCalcul )
        // cas où le type principal est valide et qu'il y a des sous_types
      { // on regarde si le sous-type "commandeInteractive" existe, si oui on le met en place
        // détermine si le sous type de calcul existe et s'il est actif
        if (paraGlob->SousTypeCalcul(commandeInteractive))
          {// -- cas avec commandes interactives
           // initialisation du calcul 
           InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );
           // calcul de l'équilibre tant qu'il y a des commandes
           while (ActionInteractiveAlgo())
           	{// on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
             if (! (charge->Fin(icharge,true) ) )
               CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats
                              ,tb_combiner);
           	};
           // fin du calcul, pour l'instant on ne considère pas les autres sous-types              
           FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );
          }
        else // cas sans commandes interactives
          {//  on fait le calcul d'équilibre
           // initialisation du calcul : deux cas, soit avec une lecture initiale du .info, soit une lecture secondaire
           if (paraGlob->EtatDeLaLecturePointInfo() == 0)
              {InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );;}
           else {// on est en lecture secondaire
           
                 MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );;
                };

           // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
           if (! (charge->Fin(icharge,true) ) )
            { // calcul de l'équilibre
              CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats
                              ,tb_combiner);
              // fin du calcul, pour l'instant on ne considère pas les autres sous-types
              FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,divStock,charge,lesCondLim,lesContacts,resultats );
            };
                                             
          };// fin du cas sans commandes interactives
		  // ensuite on teste en fonction des calculs complémentaires
        // dépendant des sous_types. Pour l'instant ici uniquement la remontée
        list <EnumSousTypeCalcul>::const_iterator ili,ili_fin = soustypeDeCalcul->end();
        list <bool>::const_iterator ila;
        for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin();
             ili!=ili_fin;ili++,ila++)
             if (*ila) // cas où le sous type est valide  
               {if (Remonte_in(*ili)) // on test la présence du calcul de remonté
                 { // certaines initialisations sont nécessaires car c'est le premier calcul
                   Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
                   Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
                   Algori::RemontSigma(lesMail);
                   Algori::RemontErreur(lesMail);
                  }
                else if ( (*ili) == sauveMaillagesEnCours )
                { cout << "\n================================================================="
                       << "\n|   ecriture des maillages en cours         en .her et .lis     |"
                       << "\n================================================================="
                       << endl;
         
                  // -----  sort les informations sur fichiers
                  // Affichage des donnees des maillages dans des fichiers dont le nom est construit 
                  // à partir du nom de chaque maillage au format  ".her" et ".lis"
                  lesMail->Affiche_maillage_dans_her_lis(TEMPS_tdt,*lesRef);
                };
              };
		    }
     else
        // cas ou le type principal n'est pas valide
        // on ne fait que le calcul complémentaire           
        { list <EnumSousTypeCalcul>::const_iterator ili,ili_fin = soustypeDeCalcul->end();
          list <bool>::const_iterator ila;
          for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin();
             ili!=ili_fin;ili++,ila++)
             if (*ila) // cas où le sous type est valide  
               {if (Remonte_in(*ili)) // on test la présence du calcul de remonté
                 { // certaines initialisations sont nécessaires car c'est le premier calcul
                   Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
                   Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
                   Algori::RemontSigma(lesMail);
                   Algori::RemontErreur(lesMail);
                  }
                else if ( (*ili) == sauveMaillagesEnCours )
                { cout << "\n================================================================="
                       << "\n|   ecriture des maillages en cours         en .her et .lis     |"
                       << "\n================================================================="
                       << endl;
         
                  // -----  sort les informations sur fichiers
                  // Affichage des donnees des maillages dans des fichiers dont le nom est construit 
                  // à partir du nom de chaque maillage au format  ".her" et ".lis"
                  // a priori ici on n'a pas fait de calcul donc on sort les grandeurs à t
                  lesMail->Affiche_maillage_dans_her_lis(TEMPS_0,*lesRef);
                };
              };
         }       
      }
    // si on a forcé la sortie des itérations et incréments, il faut réinitialiser l'indicateur 
    if (!(pa.EtatSortieEquilibreGlobal()))
      pa.ChangeSortieEquilibreGlobal(false);
    
   };

// lecture des paramètres du calcul
void AlgoriCombine::lecture_Parametres(UtilLecture& entreePrinc)
 { MotCle motCle; // ref aux mots cle
   deja_lue_entete_parametre = 1; // a priori pas de lecture d'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 un paramètre à lire
//   bool lecture_effective = false;
   if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL)
    { //cas de la définition de paramètres  
      // on signale à Algori qu'il y a eu déjà une lecture de paramètre
      deja_lue_entete_parametre=2; 
      // lecture du premier paramètres de l'algorithme
      entreePrinc.NouvelleDonnee(); // ligne suivante
     
      // on initialise tous les paramètres par défaut
      // non, car cela permettra éventuellement de garder les anciens paramètres
     
      // on s'arrête lorsqu'il n'y a plus de mot clé spécifique à lire
      while (    (strstr(entreePrinc.tablcar,"choix_algo_")!=NULL)
         || (strstr(entreePrinc.tablcar,"gestion_sauvegarde_")!=NULL)
         || (strstr(entreePrinc.tablcar,"gestion_sortie_a_convergence_")!=NULL)
        )
          
        {bool lecture_effective_interne = false;
         string nom_class_methode("AlgoriCombine::lecture_Parametres(...");
         
         //===  cas où on utilise un choix d'algo interne via une fct nD
         if (strstr(entreePrinc.tablcar,"choix_algo_")!=NULL)
          { string mot_cle="choix_algo_";
            { bool lec_eff = entreePrinc.Lecture_mot_cle_et_string
                                (nom_class_methode,mot_cle,nom_choix_algo);
              lecture_effective_interne = lecture_effective_interne || lec_eff;
            };
          };
         
         //===  cas où on utilise une gestion de la sauvegarde de chaque algo via une fct nD
         if (strstr(entreePrinc.tablcar,"gestion_sauvegarde_")!=NULL)
          { string mot_cle="gestion_sauvegarde_";
            // puis on lit
            { bool lec_eff = entreePrinc.Lecture_mot_cle_et_string
                                (nom_class_methode,mot_cle,nom_gestion_sauvegarde);
              lecture_effective_interne = lecture_effective_interne || lec_eff;
            };
          };
         
         //===  cas où on utilise une gestion de la sauvegarde de chaque algo via une fct nD
         if (strstr(entreePrinc.tablcar,"gestion_sortie_a_convergence_")!=NULL)
          { string mot_cle="gestion_sortie_a_convergence_";
            // puis on lit
            { bool lec_eff = entreePrinc.Lecture_mot_cle_et_string
                                (nom_class_methode,mot_cle,nom_gestion_sortie_a_convergence);
              lecture_effective_interne = lecture_effective_interne || lec_eff;
            };
          };

         if ((lecture_effective_interne) && ( !motCle.SimotCle(entreePrinc.tablcar)))
           {
             #ifdef ENLINUX
             if ((entreePrinc.entree)->fail())
                    // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
                {  entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
                }
             #else
             if ((entreePrinc.entree)->eof())
                // la lecture est bonne mais on a atteind la fin de la ligne
                {  entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
                }
             #endif
                // sinon ce n'est pas une ligne ad hoc, la lecture s'arrêtera
          };
         };
            
    };
     

   // puis appel de la méthode de la classe mère
   Algori::lecture_Parametres(entreePrinc); 
    
  };     
       
// création de cst_0 et cst_1
void AlgoriCombine::Creation_fct_cst()
  { // on crée si les fct n'existent pas déjà
    // 1) on crée les paramètres pour la création des fonctions
    Tableau <string > nom_variables;// les variables non globales -> 0
    Tableau <Enum_GrandeurGlobale > enu_variables_globale; // enu globaux -> 0
    Tableau <string > nom_variables_globales; // idem sous forme de strings
       
    // 2) maintenant on crée les fonctions
    if (cst_0 == NULL)
      {string nom_ref("_"); // nom de ref de la fonction
       string expression_fonction("0"); // la valeur de la fonction
       cst_0 = new Fonction_expression_litterale_nD
            (nom_ref,nom_variables,enu_variables_globale,nom_variables_globales
             ,expression_fonction);
      };
    if (cst_1 == NULL)
      {string nom_ref("_"); // nom de ref de la fonction
       string expression_fonction("1"); // la valeur de la fonction
       cst_1 = new Fonction_expression_litterale_nD
            (nom_ref,nom_variables,enu_variables_globale,nom_variables_globales
             ,expression_fonction);
      };
  };

// -------------------- Méthodes protégées --------------------------


// écriture des paramètres dans la base info
// = 1 : on écrit tout
// = 2 : on écrit uniquement les données variables (supposées comme telles)
void AlgoriCombine::Ecrit_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas)
 {
  ofstream& sort = *entreePrinc.Sort_BI();
  if (cas == 1)
   {//-- tout d'abord les fonctions de gestion d'algo
    // choix des sous_algo
    if (nom_choix_algo == "")
      {sort << "\n fct_choix_algo_ "<< "aucune ";}
    else
      {sort << "\n fct_choix_algo_ "<< nom_choix_algo;};
    // gestion de sauvegarde
    if (nom_gestion_sauvegarde == "")
      {sort << "\n fct_gestion_sauvegarde_ "<< "aucune ";}
    else
     {sort << "\n fct_gestion_sauvegarde_ "<< nom_gestion_sauvegarde;};
    // gestion de sortie à convergence
    if (nom_gestion_sortie_a_convergence == "")
      {sort << "\n fct_gestion_sortie_a_convergence_ "<< "aucune ";}
    else
     {sort << "\n fct_gestion_sortie_a_convergence_ "<< nom_gestion_sortie_a_convergence;};
   
    //--- puis  on passe en revue les algos internes
    int nb_algo = tab_algo.Taille();
    for (int i=1;i<=nb_algo;i++)
      {  sort << "\n ----->>parametres_sous_algo_specifiques_ "<< Nom_TypeCalcul(tab_algo(i)->TypeDeCalcul());
         tab_algo(i)->Ecrit_Base_info_Parametre(entreePrinc,cas);
         sort << "\n ----->>fin_parametres_sous_algo_specifiques_ "<< Nom_TypeCalcul(tab_algo(i)->TypeDeCalcul());
      };
    };
  };

    // lecture des paramètres dans la base info
    // = 1 : on récupère tout
    // = 2 : on récupère uniquement les données variables (supposées comme telles)
    // choix = true  : fonctionnememt normal
    // choix = false : la méthode ne doit pas lire mais initialiser les données à leurs valeurs par défaut
    //                 car la lecture est impossible
void AlgoriCombine::Lecture_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas,bool choix)
{
  // récup du flot
  ifstream * ent = entreePrinc.Ent_BI();
  if (cas == 1)
   {// dimensionnement
    if (choix)
     {// cas d'une lecture normale
      ifstream * ent = entreePrinc.Ent_BI();
      string toto;
      (*ent) >> toto; // on passe l'entête
      //-- tout d'abord les fonctions de gestion d'algo
      // choix des sous_algo
      (*ent) >> toto; // on passe l'entête
      if (toto == "aucune")
        {nom_choix_algo = "";choix_algo=NULL;}
      else
        {nom_choix_algo = toto;};
      // gestion de sauvegarde
      (*ent) >> toto; // on passe l'entête
      if (toto == "aucune")
        {nom_gestion_sauvegarde = "";gestion_sauvegarde=NULL;}
      else
        {nom_gestion_sauvegarde = toto;};
      // gestion de sortie à convergence
      (*ent) >> toto; // on passe l'entête
      if (toto == "aucune")
        {nom_gestion_sortie_a_convergence = "";gestion_sortie_a_convergence=NULL;}
      else
        {nom_gestion_sortie_a_convergence = toto;};
     };
    //--- puis  on passe en revue les algos internes
    int nb_algo = tab_algo.Taille();
    for (int i=1;i<=nb_algo;i++)
     {// si on est arrivée ici, cela veut dire que l'on a lue sur le .BI qu'il s'agit de paramètre spécifiques
      // de sous-algo donc il y a une première ligne qui indique de quel sous algo il s'agit
      // on suit la même logique que celle de Algori::Ecriture_base_info
      string nom1,nom2;
      (*ent) >> nom1 ;
      if (nom1 == "----->>parametres_sous_algo_specifiques_")
       { // lecture du nom de l'algo
         (*ent) >> nom2;
         if (Id_nom_TypeCalcul(nom2.c_str()) == tab_algo(i)->TypeDeCalcul())
          { // les données sauvegardées correspondent à l'algo en cours, on peut les récupérer
            Lecture_Base_info_Parametre(entreePrinc,cas,true);
            // on finit la lecture en passant les dernières lignes jusqu'au mot clé
            (*ent) >> nom1;
            while (nom1 != "----->>fin_parametres_sous_algo_specifiques_")
              (*ent) >> nom1;
            (*ent) >> nom1; // enfin on passe le nom de l'algo
          }
         else
          { // l'algo ne correspond pas, on passe les informations correspondants
            while (nom1 != "----->>fin_parametres_sous_algo_specifiques_:")
              (*ent) >> nom1;
            (*ent) >> nom1; // enfin on passe le nom de l'algo
            // on demande à l'agorithme de faire une initialisation sans lecture
            Lecture_Base_info_Parametre(entreePrinc,cas,false);
          };
       }
      else
       { // erreur on est mal positionné dans le fichier
         cout << "\n *** erreur en lecture des parametres specifiques de l'algorithme"
              << " on attendait le mot cle ----->>parametres_sous_algo_specifiques_ "
              << " et on a lue "<< nom1
              << "\n AlgoriCombine::Lecture_Base_info_Parametre(...";
         // 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);
       };

      tab_algo(i)->Lecture_Base_info_Parametre(entreePrinc,cas,choix);
     }
    }
};

// création d'un fichier de commande: cas des paramètres spécifiques
void AlgoriCombine::Info_commande_parametres(UtilLecture& entreePrinc)
 { // écriture dans le fichier de commande
   ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
   
   sort << "\n# exemple partiel de declaration d'un algorithme qui integre "
        << " 2 sous algorithmes " ;
   sort << "\n ";
   sort << "\n combiner  avec  plus visualisation "
        << "\n# ++++++++++++ liste des sous algorithmes  ++++++++++++ "
        << " liste_algorithmes_a_combiner_ # mot cle de debut de liste "
        << "\n# "
        << "\n# ============ algo 1 ============ "
        << "\n# ----- Dynamic Relaxation "
        << "\n dynamique_relaxation_dynam "
        << "\n   # puis les parametres particuliers de l'algorithme de relaxation ..."
        << "\n   #  ... a completer "
        << "\n "
        << "\n# ============ algo 2 ============ "
        << "\n# ----- newton statique "
        << "\n non_dynamique  "
        << "\n PARA_TYPE_DE_CALCUL "
        << "\n mode_debug_= 1 # il s'agit ici du mode debug uniquement pour le non_dynamique "
        << "\n# ... "
        << "\n fin_liste_algorithmes_a_combiner_ # mot cle de fin de liste de sous algo "
        << "\n "
        << "\n# ++++++++++++ parametres de l'algorithme combiner  ++++++++++++ "
        << "\n#   ils sont facultatifs et ici commentes cf. doc pour + de prec "
        << "\n PARA_TYPE_DE_CALCUL "
        << "\n## --- gestion du choix de l'algo"
        << "\n#   choix_algo_ fonc_choix_algo"
        << "\n#   #    --- gestion de la sauvegarde de chaque algo"
        << "\n#      gestion_sauvegarde_ fonc_gestion_sauvegarde # idem sauvegarde"
        << "\n#   #     ---   puis la sortie du sous algo si convergence"
        << "\n#      gestion_sortie_a_convergence_ fonc_gestion_sortie_a_convergence"
        << "\n " << flush;
      
   cout << "\n# description plus precise de l'algorithme combiner (rep o ou n defaut) ? ";
   string rep("n");
   // 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";
      };
   if ((rep == "o") || (rep == "O") ||(rep == "0"))
   {    sort << "\n                --- AlgoriCombine --- "
        << "\n#  l'algorithme combiner permets d'encapsuler et de controler  "
        << "\n#  plusieurs sous algorithmes a l'interieur d'un algorithme maitre. "
        << "\n#  NB:"
        << "\n#  - Il n'y a pas de limitation sur le nombre de sous algorithme "
        << "\n#  - un meme type d'algorithme peut apparaitre plusieurs fois "
        << "\n#  - les sous algorithmes sont reperes par leur numero d'apparition"
        << "\n#    lors de la lecture (et non par leur type) "
        << "\n#  "
        << "\n#  Par defaut le fonctionnement est le suivant: "
        << "\n#  - pour chaque increment de charge, l'ensemble des sous algorithmes "
        << "\n#    est execute dans l'ordre de leur lecture "
        << "\n#  - le programme sort d'un sous algorithme lorsque typiquement la precision "
        << "\n#    requise pour cet algorithme en fonction de la norme choisit, est "
        << "\n#    satisfaite (a noter que chaque algorithme peut redefinir sa propre "
        << "\n#    norme et sa propre precision via des fonctions nD et/ou des parametres"
        << "\n#    de controle specifique) "
        << "\n#  - seul le dernier algorithme valide (si convergence) le resultat final"
        << "\n#    "
        << "\n#  Il est possible d'etendre ce fonctionnement avec les parametres  "
        << "\n#  facultatifs propres a l'algo combiner definit par le mot cle: "
        << "\n#  PARA_TYPE_DE_CALCUL "
        << "\n#  positionne apres la definition de tous les sous algo (cf. mot cle "
        << "\n#  fin_liste_algorithmes_a_combiner_ ) "
        << "\n#  "
        << "\n#  - on peut definir une fonction  nD, dependante de grandeurs globales "
        << "\n#    qui doit retourner 1 scalaire. Ce scalaire indique le "
        << "\n#    choix de l'algo voulu. Dans ce cas, a chaque increment "
        << "\n#    de charge, la fonction est appelee et le nombre (entier) que retourne la"
        << "\n#    fonction indique le numero du sous algo a utiliser. En sortie du sous algo "
        << "\n#    on regarde s'il s'agissait d'un calcul avec validation ou non. "
        << "\n#    Le sous algo ne rend la main que si le calcul s'est deroule correctement "
        << "\n#    (cf. remarques si-dessous). Aussi si le calcul etait avec validation "
        << "\n#    la charge est incremente sinon il n'y a pas d'incrementation de la charge.  "
        << "\n#    Puis la fonction de choix d'algo est appelee pour designer le nouveau  "
        << "\n#    sous algo a appeler."
        << "\n#  "
        << "\n#     . la definition de la fonction s'effectue avec le mot cle choix_algo_"
        << "\n#       suivit du nom d'une fonction nD definit dans la suite de la mise"
        << "\n#       en donnees. "
        << "\n#    "
        << "\n#          exemple de definition : "
        << "\n#   choix_algo_ fonc_choix_algo  # gestion du choix de l'algo "
        << "\n#  "
        << "\n# - par defaut, c'est le dernier sous algo qui valide le calcul. On peut definir "
        << "\n#   une fonction nD, dependante de grandeurs globales, qui redefinit quand le sous algo "
        << "\n#   doit valider le calcul. Cette fonction est appelee a l'interieur du sous algo "
        << "\n#   a la fin de chaque iteration (implicit) ou increment (explicit) "
        << "\n#   et permet a l'utilisateur (par exemple en fonction de la precision obtenue) "
        << "\n#   de valider le calcul. "
        << "\n#   Conjointement avec la fonction de choix d'algo, la fonction de validation"
        << "\n#   est egalement appelee apres le retour du sous algo, pour incrementer la charge"
        << "\n#   ou non (cf. si-dessus)."
        << "\n#  "
        << "\n#     . la definition de la fonction s'effectue avec le mot cle gestion_sauvegarde_"
        << "\n#       suivit du nom d'une fonction nD definit dans la suite de la mise"
        << "\n#       en donnees. "
        << "\n#    "
        << "\n#          exemple de definition : "
        << "\n#   gestion_sauvegarde_ fonc_gestion_sauvegarde # gestion de la convergence de chaque algo "
        << "\n#  "
        << "\n#  - Par defaut, le programme sort d'un sous algorithme lorsque typiquement la precision "
        << "\n#    requise pour cette algorithme en fonction de la norme choisit, est "
        << "\n#    satisfaite, ceci pour un increment de charge. "
        << "\n#    Il est possible d'effectuer plusieurs increment de charge avec un meme sous algo."
        << "\n#    A priori il faut dans ce cas utiliser conjointement les fonction de "
        << "\n#    gestion de sauvegarde et de validation de calcul, et on utilise une troisieme"
        << "\n#    fonction nD qui dit quand on sort du sous algo."
        << "\n#  "
        << "\n#     . la def de la fonction s'effectue avec le mot cle gestion_sortie_a_convergence_"
        << "\n#       suivit du nom d'une fonction nD definit dans la suite de la mise"
        << "\n#       en donnees. "
        << "\n#    "
        << "\n#          exemple de definition : "
        << "\n#   gestion_sortie_a_convergence_ fonc_gestion_sortie_a_convergence # gestion de la sortie de chaque algo "
        << "\n#  "
        << "\n#  Autres remarques importantes: "
//        << "\n#  - dans le cas de l'utilisation des fct nD, l'incrementation du chargement peut "
//        << "\n#    s'effectuer a l'interieur d'un sous algo. Ainsi un certain sous algo peut "
//        << "\n#    (eventuellement) enchainer plusieurs increments de charge "
//        << "\n#     avant de rendre la main. "
        << "\n#  - un sous algo ne rend la main que s'il a fonctionne correctement. Par exemple  "
        << "\n#    s'il ne converge pas, il suit sa logique propre (cf. ses propres parametres"
        << "\n#    de controle) jusqu'a aboutir au resultat cible (increment, precision etc.)."
        << "\n#    Aussi, tant que l'algo ne rend pas la main, un nouveau choix de sous algo"
        << "\n#    n'est pas possible. Cependant, chaque test de convergence du sous algo"
        << "\n#    peut se controler via une fonction nD qui prend en compte l'evolution du calcul."
        << "\n#    On peut ainsi definir une strategie specifique, qui permet de sortir de l'algo."
        << "\n#    "
        << "\n#  - au cours de l'execution de l'algo combiner on peut consulter la variable"
        << "\n#    globale :  "
        << "\n#        algo_global_actuel"
        << "\n#    qui contient pendant l'execution, le numero de def du sous algo en cours "
        << "\n#    (voir la doc pour l'equivalence numero <-> type d'algo, car ce n'est pas le "
        << "\n#    numero de lecture !!)"
        << "\n#  - au cours de la mise en donnees generale (= le .info) on definit un ensemble de "
        << "\n#    parametres de controle (ex: pas de temps, increment, nombre d'iteration etc. )."
        << "\n#    Ces parametres s'appliquent a l'algorithme principal c-a-d combiner ."
        << "\n#    Par defaut, l'ensemble de ces parametres de controle, est re-attribue a chaque"
        << "\n#    sous algorithme. Mais il est egalement possible de modifier specifiquement certains"
        << "\n#    parametre pour un algorithme particulier. On se reportera a la documentation generale"
        << "\n#    pour plus d'info : cf. les mots cle : "
        << "\n#   ==PARA_SPECIFIQUE_SOUS_ALGO== "
        << "\n#   et "
        << "\n#  ==FIN_PARA_SPECIFIQUE_SOUS_ALGO_=="
        << "\n#  Ces 2 mots cles permettent de definir des parametres de controle specifiques pour un  "
        << "\n#  sous algorithme. "
        << "\n#  - Ils doivent etre utilises apres la definition des parametres de "
        << "\n#  controle generaux (parametre par defaut de tous les sous algo)"
        << "\n#  - le premier est suivi du numero d'algo auquel il s'applique "
        << "\n#  - le second termine la definition specifique "
        << "\n#  "
        << "\n#    "
        << "\n#          exemple de mise en donnees : "
        << "\n#  "
        << "\n#  "
        << "\n# para_affichage #------------ "
        << "\n#---------------------------"
        << "\n# PARAMETRE    |    VALEUR    |  "
        << "\n#--------------------------- "
        << "\n# FREQUENCE_AFFICHAGE_INCREMENT    1  "
        << "\n# FREQUENCE_AFFICHAGE_ITERATION    1  "
        << "\n# FREQUENCE_SORTIE_FIL_DU_CALCUL   1  "
        << "\n# ... fin des parametres generaux "
        << "\n#  "
        << "\n# ==PARA_SPECIFIQUE_SOUS_ALGO== 1 # para specifiques sous algo 1 "
        << "\n# controle #------------ "
        << "\n#-------------------- "
        << "\n# PARAMETER | VALUE |  "
        << "\n#--------------------  "
        << "\n# NORME E_cinetique/E_statique_ET_ResSurReact  "
        << "\n# PRECISION 5e-1 "
        << "\n# etc. "
        << "\n# ==FIN_PARA_SPECIFIQUE_SOUS_ALGO_== "
        << "\n#  "
        << "\n# ==PARA_SPECIFIQUE_SOUS_ALGO== 2 # para specifiques sous algo 2 "
        << "\n# .... "
        << "\n# ==FIN_PARA_SPECIFIQUE_SOUS_ALGO_== "
        ;
   };
	  // appel de la classe mère
	  Algori::Info_com_parametres(entreePrinc);
   sort << "\n" << endl;
 };
                    

// sortie sur fichier des temps cpu
// idem la forme générique de la classe mère
// + des infos partielles pour chaque sous-algorithme
void AlgoriCombine::Sortie_temps_cpu(const LesCondLim& lesCondLim
                      , const Charge& charge,const LesContacts & contact)
 {// -- on commence par appeler la méthode générique
  // mais auparavant, il faut abonder la partie loi de comportement
  // qui globalise automatiquement, donc qui n'est pas spécifique à chaque algo
  
  Algori::Sortie_temps_cpu(lesCondLim,charge,contact);
  
  // -- puis on complète pour chaque sous algo
  // NB: concernant le contact, le chargement et les CL ou CLL, les temps étant
  // stockés dans les objets concernés, il n'y a pas de séparation pour chaque
  // algo, donc on ne sort pas ces temps qui ne sont que globaux (pas spécifiques à
  // chaque algo)
  // on récupère le fichier des temps cpu
  entreePrinc->Ouverture_fichier_temps_cpu(); // ouverture au cas où
  // récupération du fichier des temps cpu
  ofstream & sort_cpu = entreePrinc->Sort_temps_cpu();
  int nbdigit = 6; // pour le pourcentage
  int nb_algo = tab_algo.Taille();
  for (int i=1;i<=nb_algo;i++)
   { // la petite méthode qui sert au transfert et qui doit-être appelé avant les sorties
     tab_algo(i)->Temps_CPU_HZpp_to_lesTempsCpu(lesCondLim,charge,contact);
     // on concatène la totalité pour ensuite sortir également des pourcentage
     double  total_cpu = tab_algo(i)->tempsInitialisation.Temps_CPU_User();
     total_cpu += tab_algo(i)->tempsMiseAjourAlgo.Temps_CPU_User();
     total_cpu += tab_algo(i)->tempsCalEquilibre.Temps_CPU_User();
     total_cpu += tab_algo(i)->tempsSauvegarde.Temps_CPU_User();
     total_cpu += tab_algo(i)->tempsSortieFilCalcul.Temps_CPU_User();
     sort_cpu << fixed;
     sort_cpu.precision(2);
     // pour éviter de faire une division par 0
     total_cpu = MaX(ConstMath::trespetit, total_cpu);

     sort_cpu << "\n ----->> specifiquement au sous_algo: "<< Nom_TypeCalcul(tab_algo(i)->TypeDeCalcul());
     sort_cpu << "\n ---> tps_total_sous_algo "
              << "("<< std::setw(nbdigit) << total_cpu/1000. << " )   ";

     sort_cpu << "\n tps_InitAlgo        "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsInitialisation.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsInitialisation.Temps_CPU_User_milli();
     sort_cpu << "\n tps_MiseAJourAlgo   "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsMiseAjourAlgo.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsMiseAjourAlgo.Temps_CPU_User_milli();
     sort_cpu << "\n tps_CalEquilibre    "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsCalEquilibre.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsCalEquilibre.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_MatSmLoc        "
              << ".("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsRaidSmEner.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsRaidSmEner.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_SmLoc           "
              << ".("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsSecondMembreEnerg.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsSecondMembreEnerg.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_lois_comp       "
              << "..("<< std::setw(nbdigit) << (100 * tab_algo(i)->temps_lois_comportement.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->temps_lois_comportement.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_metrique_KSM    "
              << "...("<< std::setw(nbdigit) << (100 * tab_algo(i)->temps_metrique_K_SM.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->temps_metrique_K_SM.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_ResSystLineaire "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsResolSystemLineaire.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsResolSystemLineaire.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_Sauvegarde      "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsSauvegarde.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsSauvegarde.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n tps_SortieFilCalcul "
              << "("<< std::setw(nbdigit) << (100 * tab_algo(i)->tempsSortieFilCalcul.Temps_CPU_User()/total_cpu) << " % )   "
              << tab_algo(i)->tempsSortieFilCalcul.Temps_CPU_User_milli()
              ;
     sort_cpu << "\n";
   };

 
 };

// une méthode qui a pour objectif de terminer tous les comptages, utile
// dans le cas d'un arrêt impromptu
void AlgoriCombine::Arret_du_comptage_CPU()
 { // tout d'abord on appel la méthode générique qui concerne finalement
   // que l'algo combiné
   Algori::Arret_du_comptage_CPU();
   
   // puis ici il s'agit de faire l'arrêt également de tous les sous algo
   int nb_algo = tab_algo.Taille();
   for (int i=1;i<=nb_algo;i++)
     tab_algo(i)->Arret_du_comptage_CPU();
 };

// ------- concernant les algo internes --------
// lecture des algorithmes internes
void AlgoriCombine::Lecture_algo_interne(const bool avec_typeDeCal
                         ,const list <EnumSousTypeCalcul>& soustype
                         ,const list <bool>& avec_soustypeDeCal
                         ,UtilLecture& entreePrinc)
 { // les algos internes sont encadrés par les mots clés:
   // liste_algorithmes_a_combiner_ et fin_liste_algorithmes_a_combiner_
   // ces mots clés doivent exister et il doit y avoir au moins un algo interne


   list_sousTypeCalcul.clear();
   list_avec_sousCalcul.clear();

   list <list<EnumSousTypeCalcul> >::const_iterator  ili=list_sousTypeCalcul.begin();
   list <list<bool> >::const_iterator ala=list_avec_sousCalcul.begin();

   try
    { entreePrinc.NouvelleDonnee();// on passe la ligne de définition de l'algo combiner
      string nom_class_methode("AlgoriCombine::Lecture_algo_interne(..."); // pour info lecture
      // on passe le mot clé de début de liste
      string mot_cle = "liste_algorithmes_a_combiner_";
//      bool lec_eff = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
      entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
      list < Algori * > list_algori_inter; // une liste de travail pour la lecture
      // maintenant on va lire chaque algorithme
      entreePrinc.NouvelleDonnee();
      do
        { // on lit les infos concernant le type de calcul interne
          EnumTypeCalcul typeCalcul;bool avec_Calcul;
          list<EnumSousTypeCalcul>  sousTypeCalcul;
          list<bool> avec_sousCalcul;
          LectureTypeCalcul(entreePrinc,typeCalcul,avec_Calcul,sousTypeCalcul,avec_sousCalcul);
          list_sousTypeCalcul.push_front(sousTypeCalcul);ili=list_sousTypeCalcul.begin();
          list_avec_sousCalcul.push_front(avec_sousCalcul);ala=list_avec_sousCalcul.begin();
          // du coup : les listes sont rangées : la première -> le dernier algo, etc.
          // def de l'algorithme
          Algori* algori = Algori::New_Agori
                      (typeCalcul,avec_Calcul, (*ili),(*ala),entreePrinc);
          list_algori_inter.push_back(algori);
        }
      while (strstr(entreePrinc.tablcar,"fin_liste_algorithmes_a_combiner_")==NULL) ;
//      entreePrinc.NouvelleDonnee(); // on passe le mot clé fin_liste_algorithmes_a_combiner_
      // maintenant on stocke dans le tableau ceci pour un acces non séquentiel futur
      int nb_algo = list_algori_inter.size();
      tab_algo.Change_taille(nb_algo);
      list < Algori * >::iterator il,ilfin= list_algori_inter.end();
      int i=1;
      for (il = list_algori_inter.begin();il != ilfin; il++,i++)
       tab_algo(i)=(*il);
    }
   catch (...)
    {
      cout << "\n *** erreur en lecture algorithme(s) interne(s) "
           << "\n AlgoriCombine::Lecture_algo_interne(.."<<flush;
      Sortie(1);
    };
   
   // on renseigne la variable: ptalgocombi de la classe Algori pour tous les sous-algo
   int nb_algo = tab_algo.Taille();
   for (int i=1;i<=nb_algo;i++)
     tab_algo(i)->Change_ptalgocombi (this);
    
  };


// sortie des temps cpu cumulées de tous les algos
void AlgoriCombine::AutreSortieTempsCPU(ofstream& sort,const int ) const
  { // on commence par cumuler tous les temps de calcul
    Tableau <Temps_CPU_HZpp>   lesTsCpu(10); // init

    // on passe en revue tous les algorithmes et on cumule les temps cpu
    int nb_algo = tab_algo.Taille();
    for (int i=1;i<=nb_algo;i++)
      tab_algo(i)->Ajout_Temps_CPU_HZpp_to_lesTempsCpu(lesTsCpu);
    // on n'ajoute pas les temps de  l'algo combiner, car sinon
    // on va compter 2 fois certains temps
    // en fait les temps de l'algo combiner ne sont pas très exploitable
    // dans la forme actuelle, peut-être à améliorer si on veut les temps
    // spécifique de l'algo combiner
    
    // puis on affiche comme dans
    //Algori::Ecriture_base_info(ofstream& sort,const int cas
    ///  ----> pour rappel:
    //    //------- temps cpu -----
    //    Temps_CPU_HZpp tempsInitialisation;          // lesTempsCpu(1)
    //    Temps_CPU_HZpp tempsMiseAjourAlgo;           // lesTempsCpu(2)
    //    Temps_CPU_HZpp tempsCalEquilibre;            // lesTempsCpu(3)
    //    Temps_CPU_HZpp tempsRaidSmEner;              // lesTempsCpu(4)
    //    Temps_CPU_HZpp tempsSecondMembreEnerg;       // lesTempsCpu(5)
    //    Temps_CPU_HZpp tempsResolSystemLineaire;     // lesTempsCpu(6)
    //    Temps_CPU_HZpp tempsSauvegarde;              // lesTempsCpu(7)
    //    Temps_CPU_HZpp tempsSortieFilCalcul;         // lesTempsCpu(8)
    //    Temps_CPU_HZpp tempsRaidSmEnerContact;       // lesTempsCpu(9)
    //    Temps_CPU_HZpp tempsSecondMembreEnergContact; // lesTempsCpu(10)
    //    Temps_CPU_HZpp temps_CL;                     // lesTempsCpu(11)
    //    Temps_CPU_HZpp temps_CLL;                    // lesTempsCpu(12)
    //    Temps_CPU_HZpp temps_lois_comportement;      // lesTempsCpu(13)
    //    Temps_CPU_HZpp temps_metrique_K_SM;          // lesTempsCpu(14)
    //    Temps_CPU_HZpp temps_chargement;             // lesTempsCpu(15)
    //    Temps_CPU_HZpp temps_rech_contact;           // lesTempsCpu(16)
    // cas d'un calcul parallèle: // passage des infos entre process
    //    Temps_CPU_HZpp  temps_transfert_court ;      // lesTempsCpu(17)
    //    Temps_CPU_HZpp  temps_transfert_long ;       // lesTempsCpu(19)
    //    Temps_CPU_HZpp  temps_attente ;              // lesTempsCpu(18)
    sort << "\n tps_InitAlgo        " << lesTsCpu(1);
    sort << "\n tps_MiseAJourAlgo   "<< lesTsCpu(2);
    sort << "\n tps_CalEquilibre    "<< lesTsCpu(3);
    sort << "\n tps_MatSmLoc        "<< lesTsCpu(4);
    sort << "\n tps_SmLoc           "<< lesTsCpu(5);
    sort << "\n tps_ResSystLineaire "<< lesTsCpu(6);
    sort << "\n tps_Sauvegarde      "<< lesTsCpu(7);
    sort << "\n tps_SortieFilCalcul "<< lesTsCpu(8);
    sort << "\n tps_contactMatSmLoc "<< lesTsCpu(9);
    sort << "\n tps_contactSmLoc    "<< lesTsCpu(10);

  };


// sortie pour info de la liste des énumérés de tous les sous-algo
list <EnumTypeCalcul> AlgoriCombine::List_Sous_Algo() const
  { list <EnumTypeCalcul> retour;
    int nb_algo = tab_algo.Taille();
    for (int i=1;i<=nb_algo;i++)
      retour.push_back(tab_algo(i)->TypeDeCalcul());
    // retour
    return retour;
  };
