// 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
// -- la liste des algorithems actuellement disponibles#include "Projet.h"
#include "AlgoriNonDyna.h"
#include "ImpliNonDynaCont.h"
#include "AlgoriFlambLineaire.h"
#include "AlgoInformations.h"
#include "AlgoUtils.h"
#include "AlgoriDynaExpli.h"
#include "AlgoriNewmark.h"
#include "Algori_chung_lee.h"
#include "AlgoriDynaExpli_zhai.h"
#include "Algori_tchamwa.h"
#include "AlgoUmatAbaqus.h"
#include "AlgoRungeKutta.h"
#include "AlgoBonelli.h"
#include "Algori_relax_dyna.h"
#include "AlgoriCombine.h"
//-- fin liste algo

#include "ReferenceNE.h"
#include "ReferenceAF.h"
                           

// passage aux noeuds éventuellement des grandeurs globales, pour une sortie de post-traitement par exemple
// mais pas seulement, c'est aussi utilisé pour récupérer des infos dans le contact avec le type 4
// le principe est que ce passage s'effectue si les conteneurs existent au niveau des noeuds
void Algori::Passage_aux_noeuds_grandeurs_globales(LesMaillages * lesMail)
{ // on va boucler sur tous les grandeurs, mais on utilise le premier noeud actif pour savoir si
  // a priori le transfert est à faire
  int nb_maillage = lesMail->NbMaillage(); // récup du nombre de maillage
  List_io < TypeQuelconque >::iterator il,ilfin=listeVecGlob.end();
  for (il=listeVecGlob.begin();il!=ilfin;il++)
   {TypeQuelconque& tq = (*il);
    TypeQuelconque_enum_etendu enuq = tq.EnuTypeQuelconque(); // l'enumeré du type
    Enum_ddl enuDdl = tq.Enum(); // de ddl associé definissant le point ou est calculé tq
    Noeud* noe=NULL;
    // on recherche un noeud où enuDdl est actif
    for (int imail=1;imail<=nb_maillage;imail++)
     {int nb_N = lesMail->Nombre_noeud(imail);
      for (int inoe=1;inoe<=nb_N;inoe++)
        if (lesMail->Noeud_LesMaille(imail,inoe).En_service(enuDdl))
         {noe=&lesMail->Noeud_LesMaille(imail,inoe); break;}; // sort de la première boucle
      if (noe != NULL) break; // sortie de la boucle sur les maillages
     };
    if (noe == NULL) // cela veut que la grandeur n'est pas active et donc pas à transférer
     break; // on sort de la boucle sur les grandeurs globales
    // arrivée ici la suite est spécifique à chaque grandeur
    switch (enuq.EnumTQ())
     { case FORCE_GENE_EXT:
         lesMail->Quelconque_glob_vers_local(enuDdl,F_ext_tdt,tq,casAssemb_principal->Nb_cas_assemb());
//debug
//cout << "\n debug: Algori::Passage_aux_noeuds_grandeurs_globales ";
//F_ext_tdt.Affiche();
//fin debug
         break;
       case FORCE_GENE_INT:
         lesMail->Quelconque_glob_vers_local(enuDdl,F_int_tdt,tq,casAssemb_principal->Nb_cas_assemb());
         break;
       case FORCE_GENE_TOT:
         F_totale_tdt.Change_taille(F_ext_tdt.Taille()); // au cas où
         F_totale_tdt = F_ext_tdt; F_totale_tdt += F_int_tdt;
         lesMail->Quelconque_glob_vers_local(enuDdl,F_totale_tdt,tq,casAssemb_principal->Nb_cas_assemb());
         break;
       case RESIDU_GLOBAL:
         lesMail->Quelconque_glob_vers_local(enuDdl,residu_final,tq,casAssemb_principal->Nb_cas_assemb());
         break;
       case DELTA_XI:
         lesMail->Quelconque_glob_vers_local(enuDdl,delta_X,tq,casAssemb_principal->Nb_cas_assemb());
         break;
       default:
          cout << "\n ** erreur, pour l'instant le transfert depuis global vers noeud de "
               << enuq.NomPlein() << " n'est pas implante ... le demander !! "
               << "\n Algori::Passage_aux_noeuds_grandeurs_globales(..."<<endl;
            // dans le cas où un comptage du calcul est en cours on l'arrête
            if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
            if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
            if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
            if (tempsSortieFilCalcul.Comptage_en_cours()) tempsSortieFilCalcul.Arret_du_comptage();
            if (tempsSauvegarde.Comptage_en_cours()) tempsSauvegarde.Arret_du_comptage();
          Sortie(1);
     };
   };
};

// passage aux noeuds de F_int_t et F_ext_t
void Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(LesMaillages * lesMail)
{ int dim = ParaGlob::Dimension(); // dimension du pb
  if(ParaGlob::AxiSymetrie())
    dim--; // en axisymétrie on récupère uniquement les forces en x et y
  // def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
  Coordonnee coor(dim); // un type coordonnee typique
  Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
  // def d'un type quelconque représentatif  pour un vecteur force à chaque noeud
  TypeQuelconque typQ_gene_int_t(FORCE_GENE_INT_t,X1,gt);
  TypeQuelconque typQ_gene_ext_t(FORCE_GENE_EXT_t,X1,gt);
  
  lesMail->Quelconque_glob_vers_local(X1,F_ext_t,typQ_gene_ext_t,casAssemb_principal->Nb_cas_assemb());
  lesMail->Quelconque_glob_vers_local(X1,F_int_t,typQ_gene_int_t,casAssemb_principal->Nb_cas_assemb());

};

// passage aux noeuds éventuellement d'une grandeur globale particulière,
// typeGeneriqu : indique le type de grandeur à passer
// Le passage s'effectue si le conteneur existe au niveau des noeuds sinon erreur
// seules les grandeurs globales qui n'ont pas été transférées par la méthode
// Passage_aux_noeuds_grandeurs_globales , sont concernées
void Algori::Passage_aux_noeuds_grandeur_globale_particuliere(const TypeQuelconque& typeGeneriqu, LesMaillages * lesMail,const Nb_assemb& nb_casAssemb)
{ TypeQuelconque_enum_etendu enuq = typeGeneriqu.EnuTypeQuelconque(); // l'enumeré du type
  Enum_ddl enuDdl = typeGeneriqu.Enum(); // de ddl associé definissant le point ou est calculé tq
  // arrivée ici la suite est spécifique à chaque grandeur
  switch (enuq.EnumTQ())
   { case FORCE_GENE_EXT:
         lesMail->Quelconque_glob_vers_local(enuDdl,F_ext_tdt,typeGeneriqu,casAssemb_principal->Nb_cas_assemb());
//debug
//cout << "\n debug: Algori::Passage_aux_noeuds_grandeurs_globales ";
//F_ext_tdt.Affiche();
//fin debug
         break;
       case FORCE_GENE_INT:
         lesMail->Quelconque_glob_vers_local(enuDdl,F_int_tdt,typeGeneriqu,casAssemb_principal->Nb_cas_assemb());
         break;
       case FORCE_GENE_TOT:
         F_totale_tdt.Change_taille(F_ext_tdt.Taille()); // au cas où
         F_totale_tdt = F_ext_tdt; F_totale_tdt += F_int_tdt;
         lesMail->Quelconque_glob_vers_local(enuDdl,F_totale_tdt,typeGeneriqu,casAssemb_principal->Nb_cas_assemb());
         break;
       case RESIDU_GLOBAL:
         lesMail->Quelconque_glob_vers_local(enuDdl,residu_final,typeGeneriqu,casAssemb_principal->Nb_cas_assemb());
         break;
       case DELTA_XI:
         lesMail->Quelconque_glob_vers_local(enuDdl,delta_X,typeGeneriqu,casAssemb_principal->Nb_cas_assemb());
         break;
       default:
          cout << "\n ** erreur, pour l'instant le transfert depuis global vers noeud de "
               << enuq.NomPlein() << " n'est pas implante ... le demander !! "
               << "\n Algori::Passage_aux_noeuds_grandeur_globale(..."<<endl;
            // dans le cas où un comptage du calcul est en cours on l'arrête
            if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage();
            if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
            if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
            if (tempsSortieFilCalcul.Comptage_en_cours()) tempsSortieFilCalcul.Arret_du_comptage();
            if (tempsSauvegarde.Comptage_en_cours()) tempsSauvegarde.Arret_du_comptage();
          Sortie(1);
     };
};


// passage des grandeurs globales aux noeuds où il y a des variables globales attachées
// nb_casAssemb correspond au cas d'assemblage de X1
void Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(LesMaillages * lesMail
                 ,VariablesExporter* varExpor,const Nb_assemb& nb_casAssemb,const LesReferences& lesRef)
{ int dim = ParaGlob::Dimension(); // dimension du pb
  if(ParaGlob::AxiSymetrie())
    dim--; // en axisymétrie on récupère uniquement les forces en x et y
  // récupération de la liste des variables en type quelconque
  const List_io <VariablesExporter::Quelconque_a_un_noeud>& liQuel = varExpor->List_noeud_type_quelconque();
  List_io <VariablesExporter::Quelconque_a_un_noeud>::const_iterator it,itfin=liQuel.end();
  for (it = liQuel.begin(); it!=itfin;it++)
    { const TypeQuelconque_enum_etendu& ty = (*it).Quelc_const(); // la grandeur constante
      switch (ty.EnumTQ())
       { case FORCE_GENE_EXT:
           {// récup de la reférence
            const ReferenceNE & ref =
            ((ReferenceNE &) lesRef.Trouve((*it).Ref_const(),&(*it).Nom_mail_const()));
            int ne = ref.Numero(1); // le num du noeud: uniquement le premier

//            int ne = (*it).Num_NE_const();  // le num du noeud
            int nmail = 1;
            if ((*it).Nom_mail_const() != "")
             nmail = lesMail->NumMaillage((*it).Nom_mail_const()); // num du maillage
            // recup du noeud
            Noeud * noo = & lesMail->Noeud_LesMaille(nmail,ne);
            // si le noeud n'est pas actif pour ce ddl, on ne continue pas
            if (noo->Existe_ici(X1)) // ellimine les noeuds non concernés
            // ** en fait cela pourrait changer pour la thermique pure, mais pour l'instant ce n'est
            // pas pris en compte, a voir si on veut les forces généralisées associées à de la thermique pure
             {if ((noo->Existe_ici(ty)) && (noo->En_service(X1)))
              {// FORCE_GENE_EXT est associé au type coordonnée
               TypeQuelconque& typQ = noo->ModifGrandeur_quelconque(ty); // récup du conteneur du noeud
               // récup de la grandeur
               Grandeur_coordonnee* gcoor = (Grandeur_coordonnee*) typQ.Grandeur_pointee();
               Coordonnee& conoe = *(gcoor->ConteneurCoordonnee()); // les coordonnées
               int iglob = noo->Pointeur_assemblage(X1,nb_casAssemb.n);
               #ifdef MISE_AU_POINT
                if ( iglob == -1 )
                 { cout << "\nErreur : ddl " << X1
                        << " inexistant  pour le cas de charge " << nb_casAssemb.n
                        <<  '\n'
                        << "Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(\n";
                    Sortie(1);
                  };
                #endif
               switch (dim) // on rempli les coordonnées
                { case 3: conoe(3)=F_ext_tdt(iglob+2);
                  case 2: conoe(2)=F_ext_tdt(iglob+1);
                  case 1: conoe(1)=F_ext_tdt(iglob);
                };
              };
             };
           break;
           }
         case FORCE_GENE_INT:
           {// récup de la reférence
            const ReferenceNE & ref =
            ((ReferenceNE &) lesRef.Trouve((*it).Ref_const(),&(*it).Nom_mail_const()));
            int ne = ref.Numero(1); // le num du noeud: uniquement le premier
//           int ne = (*it).Num_NE_const();  // le num du noeud
            int nmail = 1;
            if ((*it).Nom_mail_const() != "")
             nmail = lesMail->NumMaillage((*it).Nom_mail_const()); // num du maillage
            // recup du noeud
            Noeud * noo = & lesMail->Noeud_LesMaille(nmail,ne);
            // le type FORCE_GENE_INT est associé au ddl X1
            // si le noeud n'est pas actif pour ce ddl, on ne continue pas
            if (noo->Existe_ici(X1)) // ellimine les noeuds non concernés
             // ** en fait cela pourrait changer pour la thermique pure, mais pour l'instant ce n'est
             // pas pris en compte, a voir si on veut les forces généralisées associées à de la thermique pure
             {if ((noo->Existe_ici(ty)) && (noo->En_service(X1)))
              {// FORCE_GENE_INT est associé au type coordonnée
               TypeQuelconque& typQ = noo->ModifGrandeur_quelconque(ty); // récup du conteneur du noeud
               // récup de la grandeur
               Grandeur_coordonnee* gcoor = (Grandeur_coordonnee*) typQ.Grandeur_pointee();
               Coordonnee& conoe = *(gcoor->ConteneurCoordonnee()); // les coordonnées
               int iglob = noo->Pointeur_assemblage(X1,nb_casAssemb.n);
               #ifdef MISE_AU_POINT
                if ( iglob == -1 )
                 { cout << "\nErreur : ddl " << X1
                        << " inexistant  pour le cas de charge " << nb_casAssemb.n
                        <<  '\n'
                        << "Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(\n";
                    Sortie(1);
                  };
                #endif
               switch (dim) // on rempli les coordonnées
                { case 3: conoe(3)=F_int_tdt(iglob+2);
                  case 2: conoe(2)=F_int_tdt(iglob+1);
                  case 1: conoe(1)=F_int_tdt(iglob);
                };
              };
             };
           break;
           }
         case FORCE_GENE_TOT:
           {// récup de la reférence
            const ReferenceNE & ref =
            ((ReferenceNE &) lesRef.Trouve((*it).Ref_const(),&(*it).Nom_mail_const()));
            int ne = ref.Numero(1); // le num du noeud: uniquement le premier
//int ne = (*it).Num_NE_const();  // le num du noeud
            int nmail = 1;
            if ((*it).Nom_mail_const() != "")
             nmail = lesMail->NumMaillage((*it).Nom_mail_const()); // num du maillage
            // recup du noeud
            Noeud * noo = & lesMail->Noeud_LesMaille(nmail,ne);
            // le type FORCE_GENE_TOT est associé au ddl X1
            // si le noeud n'est pas actif pour ce ddl, on ne continue pas
            if (noo->Existe_ici(X1)) // ellimine les noeuds non concernés
             // ** en fait cela pourrait changer pour la thermique pure, mais pour l'instant ce n'est
             // pas pris en compte, a voir si on veut les forces généralisées associées à de la thermique pure
             {if ((noo->Existe_ici(ty)) && (noo->En_service(X1)))
              {// FORCE_GENE_TOT est associé au type coordonnée
               TypeQuelconque& typQ = noo->ModifGrandeur_quelconque(ty); // récup du conteneur du noeud
               // récup de la grandeur
               Grandeur_coordonnee* gcoor = (Grandeur_coordonnee*) typQ.Grandeur_pointee();
               Coordonnee& conoe = *(gcoor->ConteneurCoordonnee()); // les coordonnées
               int iglob = noo->Pointeur_assemblage(X1,nb_casAssemb.n);
               #ifdef MISE_AU_POINT
                if ( iglob == -1 )
                 { cout << "\nErreur : ddl " << X1
                        << " inexistant  pour le cas de charge " << nb_casAssemb.n
                        <<  '\n'
                        << "Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(\n";
                    Sortie(1);
                  };
                #endif
               switch (dim) // on rempli les coordonnées
                { case 3: conoe(3)=F_int_tdt(iglob+2)+F_ext_tdt(iglob+2);
                  case 2: conoe(2)=F_int_tdt(iglob+1)+F_ext_tdt(iglob+1);
                  case 1: conoe(1)=F_int_tdt(iglob)+F_ext_tdt(iglob);
                };
              };
             };
           break;
           }
         case RESIDU_GLOBAL:
           {// récup de la reférence
            const ReferenceNE & ref =
            ((ReferenceNE &) lesRef.Trouve((*it).Ref_const(),&(*it).Nom_mail_const()));
            int ne = ref.Numero(1); // le num du noeud: uniquement le premier

//            int ne = (*it).Num_NE_const();  // le num du noeud
            int nmail = 1;
            if ((*it).Nom_mail_const() != "")
             nmail = lesMail->NumMaillage((*it).Nom_mail_const()); // num du maillage
            // recup du noeud
            Noeud * noo = & lesMail->Noeud_LesMaille(nmail,ne);
            // le type RESIDU_GLOBAL est associé au ddl X1
            // si le noeud n'est pas actif pour ce ddl, on ne continue pas
            if (noo->Existe_ici(X1)) // ellimine les noeuds non concernés
             // ** en fait cela pourrait changer pour la thermique pure, mais pour l'instant ce n'est
             // pas pris en compte, a voir si on veut les forces généralisées associées à de la thermique pure
             {if ((noo->Existe_ici(ty)) && (noo->En_service(X1)))
              {// RESIDU_GLOBAL est associé au type coordonnée
               TypeQuelconque& typQ = noo->ModifGrandeur_quelconque(ty); // récup du conteneur du noeud
               // récup de la grandeur
               Grandeur_coordonnee* gcoor = (Grandeur_coordonnee*) typQ.Grandeur_pointee();
               Coordonnee& conoe = *(gcoor->ConteneurCoordonnee()); // les coordonnées
               int iglob = noo->Pointeur_assemblage(X1,nb_casAssemb.n);
               #ifdef MISE_AU_POINT
                if ( iglob == -1 )
                 { cout << "\nErreur : ddl " << X1
                        << " inexistant  pour le cas de charge " << nb_casAssemb.n
                        <<  '\n'
                        << "Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(\n";
                    Sortie(1);
                  };
                #endif
               switch (dim) // on rempli les coordonnées
                { case 3: conoe(3)=residu_final(iglob+2);
                  case 2: conoe(2)=residu_final(iglob+1);
                  case 1: conoe(1)=residu_final(iglob);
                };
              };
             };
           break;
           }
         case DELTA_XI:
           {// récup de la reférence
            const ReferenceNE & ref =
            ((ReferenceNE &) lesRef.Trouve((*it).Ref_const(),&(*it).Nom_mail_const()));
            int ne = ref.Numero(1); // le num du noeud: uniquement le premier
//int ne = (*it).Num_NE_const();  // le num du noeud
            int nmail = 1;
            if ((*it).Nom_mail_const() != "")
             nmail = lesMail->NumMaillage((*it).Nom_mail_const()); // num du maillage
            // recup du noeud
            Noeud * noo = & lesMail->Noeud_LesMaille(nmail,ne);
            // le type DELTA_XI est associé au ddl X1
            // si le noeud n'est pas actif pour ce ddl, on ne continue pas
            if (noo->Existe_ici(X1)) // ellimine les noeuds non concernés
             // ** en fait cela pourrait changer pour la thermique pure, mais pour l'instant ce n'est
             // pas pris en compte, a voir si on veut les forces généralisées associées à de la thermique pure
             {if ((noo->Existe_ici(ty)) && (noo->En_service(X1)))
              {// DELTA_XI est associé au type coordonnée
               TypeQuelconque& typQ = noo->ModifGrandeur_quelconque(ty); // récup du conteneur du noeud
               // récup de la grandeur
               Grandeur_coordonnee* gcoor = (Grandeur_coordonnee*) typQ.Grandeur_pointee();
               Coordonnee& conoe = *(gcoor->ConteneurCoordonnee()); // les coordonnées
               int iglob = noo->Pointeur_assemblage(X1,nb_casAssemb.n);
               #ifdef MISE_AU_POINT
                if ( iglob == -1 )
                 { cout << "\nErreur : ddl " << X1
                        << " inexistant  pour le cas de charge " << nb_casAssemb.n
                        <<  '\n'
                        << "Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(\n";
                    Sortie(1);
                  };
                #endif
               switch (dim) // on rempli les coordonnées
                { case 3: conoe(3)=delta_X(iglob+2);
                  case 2: conoe(2)=delta_X(iglob+1);
                  case 1: conoe(1)=delta_X(iglob);
                };
              };
             };
           break;
           }
         default:  // on ne fait rien
           break;
       };
   };
  
};

//    //------- temps cpu -----
//   //   ainsi en sortie on pourra différencier les temps totaux et les temps partiels
//  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)
//  Temps_CPU_HZpp tempsCalMasse;                // lesTempsCpu(17)
//  Temps_CPU_HZpp tempsCalViscoNum;             // lesTempsCpu(18)
//#ifdef UTILISATION_MPI
//  // cas d'un calcul parallèle: // passage des infos entre process
//  Temps_CPU_HZpp  temps_transfert_court_algo ;    // lesTempsCpu(19)
//  Temps_CPU_HZpp  temps_transfert_long_algo ;     // lesTempsCpu(20)
//  Temps_CPU_HZpp  temps_attente_algo ;            // lesTempsCpu(21)
//  Temps_CPU_HZpp  temps_transfert_court_matSm ;   // lesTempsCpu(22)
//  Temps_CPU_HZpp  temps_transfert_long_matSm ;    // lesTempsCpu(23)
//  Temps_CPU_HZpp  temps_attente_matSm ;           // lesTempsCpu(24)
//  Temps_CPU_HZpp  temps_transfert_court_charge ;  // lesTempsCpu(25)
//  Temps_CPU_HZpp  temps_transfert_long_charge ;   // lesTempsCpu(26)
//  Temps_CPU_HZpp  temps_attente_charge ;          // lesTempsCpu(27)
//  Temps_CPU_HZpp  temps_transfert_court_contact ; // lesTempsCpu(28)
//  Temps_CPU_HZpp  temps_transfert_long_contact ;  // lesTempsCpu(29)
//  Temps_CPU_HZpp  temps_attente_contact ;         // lesTempsCpu(30)

//
//    Tableau <Coordonnee3> lesTempsCpu; // un tableau intermédiaire qui récupère et globalise les temps pour les sorties
//                                        // via listeVarGlob, mais c'est les variables Temps_CPU_HZpp qui stockent
//                                        // réellement les temps
// méthode qui sert au transfert entre les variables "Temps_CPU_HZpp" et le tableau "lesTempsCpu"
// et qui doit-être appelé avant l'utilisation du tableau via listeVarGlob par exemple
void Algori::Temps_CPU_HZpp_to_lesTempsCpu
      (const LesCondLim& lesCondLim, const Charge& charge, const LesContacts& contact)
 { lesTempsCpu(1)(1)=tempsInitialisation.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(1)(2)=tempsInitialisation.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(1)(3)=tempsInitialisation.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(2)(1)=tempsMiseAjourAlgo.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(2)(2)=tempsMiseAjourAlgo.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(2)(3)=tempsMiseAjourAlgo.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(3)(1)=tempsCalEquilibre.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(3)(2)=tempsCalEquilibre.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(3)(3)=tempsCalEquilibre.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(4)(1)=tempsRaidSmEner.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(4)(2)=tempsRaidSmEner.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(4)(3)=tempsRaidSmEner.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(5)(1)=tempsSecondMembreEnerg.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(5)(2)=tempsSecondMembreEnerg.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(5)(3)=tempsSecondMembreEnerg.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(6)(1)=tempsResolSystemLineaire.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(6)(2)=tempsResolSystemLineaire.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(6)(3)=tempsResolSystemLineaire.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(7)(1)=tempsSauvegarde.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(7)(2)=tempsSauvegarde.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(7)(3)=tempsSauvegarde.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(8)(1)=tempsSortieFilCalcul.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(8)(2)=tempsSortieFilCalcul.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(8)(3)=tempsSortieFilCalcul.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(9)(1)=tempsRaidSmEnerContact.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(9)(2)=tempsRaidSmEnerContact.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(9)(3)=tempsRaidSmEnerContact.Temps_CPU_System(); // conversion de long long en double
   lesTempsCpu(10)(1)=tempsSecondMembreEnergContact.Temps_CPU_User(); // conversion de long long en double
//   lesTempsCpu(10)(2)=tempsSecondMembreEnergContact.Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(10)(3)=tempsSecondMembreEnergContact.Temps_CPU_System(); // conversion de long long en double
   // pour les temps cpu relatifs aux CL et CLL, on les récupères
   temps_CL=lesCondLim.Temps_cpu_CL();
   lesTempsCpu(11)(1)=temps_CL.Temps_CPU_User();
//   lesTempsCpu(11)(2)=lesCondLim.Temps_cpu_CL().Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(11)(3)=lesCondLim.Temps_cpu_CL().Temps_CPU_System(); // conversion de long long en double
   temps_CLL=lesCondLim.Temps_cpu_CLL();
   lesTempsCpu(12)(1)=temps_CLL.Temps_CPU_User();
//   lesTempsCpu(12)(2)=lesCondLim.Temps_cpu_CLL().Temps_CPU_Reel(); // conversion de long long en double
//   lesTempsCpu(12)(3)=lesCondLim.Temps_cpu_CLL().Temps_CPU_System(); // conversion de long long en double

   lesTempsCpu(13)(1)=temps_lois_comportement.Temps_CPU_User();
   lesTempsCpu(14)(1)=temps_metrique_K_SM.Temps_CPU_User();
   temps_chargement = charge.Temps_cpu_chargement();
   lesTempsCpu(15)(1)= temps_chargement.Temps_CPU_User();
   temps_rech_contact = contact.Temps_cpu_Contact();
   lesTempsCpu(16)(1)= temps_rech_contact.Temps_CPU_User();
   lesTempsCpu(17)(1)= tempsCalMasse.Temps_CPU_User();
   lesTempsCpu(18)(1)= tempsCalViscoNum.Temps_CPU_User();
  #ifdef UTILISATION_MPI
   //  cas des temps de l'algorithme
   lesTempsCpu(19)(1)=  temps_transfert_court_algo.Temps_CPU_User();
   lesTempsCpu(20)(1)=  temps_transfert_long_algo.Temps_CPU_User();
   lesTempsCpu(21)(1)=  temps_attente_algo.Temps_CPU_User();
   // des mat et SM locaux
   lesTempsCpu(22)(1)=  temps_transfert_court_matSm.Temps_CPU_User();
   lesTempsCpu(23)(1)=  temps_transfert_long_matSm.Temps_CPU_User();
   lesTempsCpu(24)(1)=  temps_attente_matSm.Temps_CPU_User();
   // du chargement
   temps_transfert_court_charge = charge.Temps_transfert_court();
   lesTempsCpu(25)(1)= temps_transfert_court_charge.Temps_CPU_User();
   temps_transfert_long_charge = charge.Temps_transfert_long();
   lesTempsCpu(26)(1)= temps_transfert_long_charge.Temps_CPU_User();
   temps_attente_charge = charge.Temps_attente();
   lesTempsCpu(27)(1)= temps_attente_charge.Temps_CPU_User();
   // du contact
   temps_transfert_court_contact = contact.Temps_transfert_court();
   lesTempsCpu(28)(1)= temps_transfert_court_contact.Temps_CPU_User();
   temps_transfert_long_contact = contact.Temps_transfert_long();
   lesTempsCpu(29)(1)= temps_transfert_long_contact.Temps_CPU_User();
   temps_attente_contact = contact.Temps_attente();
   lesTempsCpu(30)(1)= temps_attente_contact.Temps_CPU_User();
  #endif

 };

// idem la méthode de transfert si-dessus mais concerne uniquement les temps internes à l'algo
//  utilisé par l'algo combiné
// ajoute  au tableau passé en paramètre, les temps de l'algo
Tableau <Temps_CPU_HZpp> & Algori::Ajout_Temps_CPU_HZpp_to_lesTempsCpu(Tableau <Temps_CPU_HZpp> &  lesTsCpu)
 { // test éventuel de la taille du tableau
 #ifdef MISE_AU_POINT
   int taille_lesTsCpu = 18; // init
  #ifdef UTILISATION_MPI
   taille_lesTsCpu = 30;
  #endif
   if (lesTsCpu.Taille() != taille_lesTsCpu)
     {cout << "\n erreur de dim de tableau: dim lesTsCpu= " << lesTsCpu.Taille()
           << " au lieu de 18 !! "
           << "\n Algori::Ajout_Temps_CPU_HZpp_to_lesTempsCpu(... " ;
      Sortie(1);
     };
 #endif

   // on stocke les infos
   lesTsCpu(1) += tempsInitialisation; // conversion de long long en double
   lesTsCpu(2) += tempsMiseAjourAlgo; // conversion de long long en double
   lesTsCpu(3) += tempsCalEquilibre; // conversion de long long en double
   lesTsCpu(4) += tempsRaidSmEner; // conversion de long long en double
   lesTsCpu(5) += tempsSecondMembreEnerg; // conversion de long long en double
   lesTsCpu(6) += tempsResolSystemLineaire; // conversion de long long en double
   lesTsCpu(7) += tempsSauvegarde; // conversion de long long en double
   lesTsCpu(8) += tempsSortieFilCalcul; // conversion de long long en double
   lesTsCpu(9) += tempsRaidSmEnerContact; // conversion de long long en double
   lesTsCpu(10) += tempsSecondMembreEnergContact; // conversion de long long en double
   lesTsCpu(17) += tempsCalMasse; // conversion de long long en double
   lesTsCpu(18) += tempsCalViscoNum; // conversion de long long en double
  #ifdef UTILISATION_MPI
   lesTsCpu(19) += temps_transfert_court_algo;
   lesTsCpu(20) += temps_transfert_long_algo;
   lesTsCpu(21) += temps_attente_algo;
   lesTsCpu(22) += temps_transfert_court_matSm;
   lesTsCpu(23) += temps_transfert_long_matSm;
   lesTsCpu(24) += temps_attente_matSm;
   lesTsCpu(25) += temps_transfert_court_charge;
   lesTsCpu(26) += temps_transfert_long_charge;
   lesTsCpu(27) += temps_attente_charge;
   lesTsCpu(28) += temps_transfert_court_contact;
   lesTsCpu(29) += temps_transfert_long_contact;
   lesTsCpu(30) += temps_attente_contact;
  #endif
   // retour
   return lesTsCpu;
  
 };

// une méthode qui a pour objectif de terminer tous les comptages, utile
// dans le cas d'un arrêt impromptu
void Algori::Arret_du_comptage_CPU()
 { tempsInitialisation.Arret_du_comptage();
   tempsMiseAjourAlgo.Arret_du_comptage();
   tempsCalEquilibre.Arret_du_comptage();
   tempsRaidSmEner.Arret_du_comptage();
   tempsSecondMembreEnerg.Arret_du_comptage();
   tempsResolSystemLineaire.Arret_du_comptage();
   tempsSauvegarde.Arret_du_comptage();
   tempsSortieFilCalcul.Arret_du_comptage();
   tempsRaidSmEnerContact.Arret_du_comptage();
   tempsSecondMembreEnergContact.Arret_du_comptage();
   temps_CL.Arret_du_comptage();
   temps_CLL.Arret_du_comptage();
   temps_lois_comportement.Arret_du_comptage();
   temps_metrique_K_SM.Arret_du_comptage();
   temps_chargement.Arret_du_comptage();
   temps_rech_contact.Arret_du_comptage();
   tempsCalMasse.Arret_du_comptage();
   tempsCalViscoNum.Arret_du_comptage();
  #ifdef UTILISATION_MPI
   temps_transfert_court_algo.Arret_du_comptage();
   temps_transfert_long_algo.Arret_du_comptage();
   temps_attente_algo.Arret_du_comptage();
   temps_transfert_court_matSm.Arret_du_comptage();
   temps_transfert_long_matSm.Arret_du_comptage();
   temps_attente_matSm.Arret_du_comptage();
   temps_transfert_court_charge.Arret_du_comptage();
   temps_transfert_long_charge.Arret_du_comptage();
   temps_attente_charge.Arret_du_comptage();
   temps_transfert_court_contact.Arret_du_comptage();
   temps_transfert_long_contact.Arret_du_comptage();
   temps_attente_contact.Arret_du_comptage();
  #endif
 };

// sortie sur fichier des temps cpu
void Algori::Sortie_temps_cpu(const LesCondLim& lesCondLim
                              , const Charge& charge,const LesContacts & contact)
 {  // la petite méthode qui sert au transfert et qui doit-être appelé avant les sorties
    Temps_CPU_HZpp_to_lesTempsCpu(lesCondLim,charge,contact);
    // 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();
    // on concatène la totalité pour ensuite sortir également des pourcentage
    double  total_cpu = tempsInitialisation.Temps_CPU_User();
    total_cpu += tempsMiseAjourAlgo.Temps_CPU_User();
    total_cpu += tempsCalEquilibre.Temps_CPU_User();
//    total_cpu += tempsRaidSmEner.Temps_CPU_User();
//    total_cpu += tempsSecondMembreEnerg.Temps_CPU_User();
//    total_cpu += tempsResolSystemLineaire.Temps_CPU_User();
    total_cpu += tempsSauvegarde.Temps_CPU_User();
    total_cpu += tempsSortieFilCalcul.Temps_CPU_User();
//    total_cpu += tempsRaidSmEnerContact.Temps_CPU_User();
//    total_cpu += tempsSecondMembreEnergContact.Temps_CPU_User();
//    total_cpu += temps_CL.Temps_CPU_User();
//    total_cpu += temps_CLL.Temps_CPU_User();
//    total_cpu += temps_lois_comportement.Temps_CPU_User();
//    total_cpu += temps_metrique_K_SM.Temps_CPU_User(); // il ne faut pas ajouter la métrique
//    total_cpu += temps_chargement.Temps_CPU_User();
//    total_cpu += temps_rech_contact.Temps_CPU_User();
    int nbdigit = 6; // pour le pourcentage
//    int nbdigit_temps = 14; // pour les temps
  
  #ifdef UTILISATION_MPI
    // les temps de transfert
    total_cpu += temps_transfert_court_algo.Temps_CPU_User();
    total_cpu += temps_transfert_long_algo.Temps_CPU_User();
    total_cpu += temps_attente_algo.Temps_CPU_User();
    total_cpu += temps_transfert_court_matSm.Temps_CPU_User();
    total_cpu += temps_transfert_long_matSm.Temps_CPU_User();
    total_cpu += temps_attente_matSm.Temps_CPU_User();
    total_cpu += temps_transfert_court_charge.Temps_CPU_User();
    total_cpu += temps_transfert_long_charge.Temps_CPU_User();
    total_cpu += temps_attente_charge.Temps_CPU_User();
    total_cpu += temps_transfert_court_contact.Temps_CPU_User();
    total_cpu += temps_transfert_long_contact.Temps_CPU_User();
    total_cpu += temps_attente_contact.Temps_CPU_User();
  #endif

    // écriture des temps cpu de l'algo:

    sort_cpu << "\n==========================================================================";
  #ifndef UTILISATION_MPI
    sort_cpu << "\n        Herezh++ :  bilan temps cpu pour l'algorithme: " << Nom_TypeCalcul(TypeDeCalcul());;
  #else
    sort_cpu << "\n Herezh++: (CPU "<< ParaGlob::Monde()->rank() << " - "
             << ParaGlob::Monde()->size() << ") bilan temps cpu, algorithme: " << Nom_TypeCalcul(TypeDeCalcul());;
  #endif
    sort_cpu << "\n==========================================================================\n";
    // puis affichage de la version
    ParaGlob::Sortie_Version(sort_cpu);  
    #ifndef MISE_AU_POINT
          sort_cpu << " (version la plus rapide )";
    #endif
    #ifdef MISE_AU_POINT
          sort_cpu << " (version avec le plus de verifications pendant le calcul et les I/O ) ";
    #endif
    sort_cpu << "\n \n ---------------  temps_locaux_cpu_en_milliseconde: ---------";
    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 ---> tps_total_algo "
             << "("<< std::setw(nbdigit) << total_cpu/1000. << " )   ";

    sort_cpu << "\n tps_InitAlgo        "
             << "("<< std::setw(nbdigit) << (100*tempsInitialisation.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsInitialisation.Temps_CPU_User_milli();
    sort_cpu << "\n tps_MiseAJourAlgo   "
             << "("<< std::setw(nbdigit) << (100*tempsMiseAjourAlgo.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsMiseAjourAlgo.Temps_CPU_User_milli();
    sort_cpu << "\n tps_CalEquilibre    "
             << "("<< std::setw(nbdigit) << (100*tempsCalEquilibre.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsCalEquilibre.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_MatSmLoc        "
             << ".("<< std::setw(nbdigit) << (100*tempsRaidSmEner.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsRaidSmEner.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_SmLoc           "
             << ".("<< std::setw(nbdigit) << (100*tempsSecondMembreEnerg.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsSecondMembreEnerg.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_lois_comp       "
             << "..("<< std::setw(nbdigit) << (100*temps_lois_comportement.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_lois_comportement.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_metrique_KSM    "
             << "...("<< std::setw(nbdigit) << (100*temps_metrique_K_SM.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_metrique_K_SM.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_chargement      "
             << ".("<< std::setw(nbdigit) << (100*temps_chargement.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_chargement.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_rech_contact    "
             << ".("<< std::setw(nbdigit) << (100*temps_rech_contact.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_rech_contact.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_contactMatSmLoc "
             << ".("<< std::setw(nbdigit) << (100*tempsRaidSmEnerContact.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsRaidSmEnerContact.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_contactSmLoc    "
             << ".("<< std::setw(nbdigit) << (100*tempsSecondMembreEnergContact.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsSecondMembreEnergContact.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_CL              "
             << ".("<< std::setw(nbdigit) << (100*temps_CL.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_CL.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_CLL             "
             << ".("<< std::setw(nbdigit) << (100*temps_CLL.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_CLL.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tempsCalMasse       "
             << ".("<< std::setw(nbdigit) << (100*tempsCalMasse.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsCalMasse.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tempsCalViscoNum    "
             << ".("<< std::setw(nbdigit) << (100*tempsCalViscoNum.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsCalViscoNum.Temps_CPU_User_milli()
             ;

    sort_cpu << "\n tps_ResSystLineaire "
             << ".("<< std::setw(nbdigit) << (100*tempsResolSystemLineaire.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsResolSystemLineaire.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_Sauvegarde      "
             << "("<< std::setw(nbdigit) << (100*tempsSauvegarde.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsSauvegarde.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps_SortieFilCalcul "
             << "("<< std::setw(nbdigit) << (100*tempsSortieFilCalcul.Temps_CPU_User()/total_cpu) << " % )   "
             << tempsSortieFilCalcul.Temps_CPU_User_milli()
             ;
  #ifdef UTILISATION_MPI
    sort_cpu << "\n --------- dialogue inter cpu ---------  ";
    sort_cpu << "\n tps__transfert_court_Algo "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_court_algo.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_court_algo.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_long_Algo "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_long_algo.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_long_algo.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__attente_Algo "
             << "("<< std::setw(nbdigit) << (100*temps_attente_algo.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_attente_algo.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_court-Mat-Smloc "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_court_matSm.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_court_matSm.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_long-Mat-Smloc "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_long_matSm.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_long_matSm.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__attente-Mat-Smloc "
             << "("<< std::setw(nbdigit) << (100*temps_attente_matSm.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_attente_matSm.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_court_charge "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_court_charge.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_court_charge.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_long_charge "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_long_charge.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_long_charge.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__attente_charge "
             << "("<< std::setw(nbdigit) << (100*temps_attente_charge.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_attente_charge.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_court_contact "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_court_contact.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_court_contact.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__transfert_long_contact "
             << "("<< std::setw(nbdigit) << (100*temps_transfert_long_contact.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_transfert_long_contact.Temps_CPU_User_milli()
             ;
    sort_cpu << "\n tps__attente_contact "
             << "("<< std::setw(nbdigit) << (100*temps_attente_contact.Temps_CPU_User()/total_cpu) << " % )   "
             << temps_attente_contact.Temps_CPU_User_milli()
             ;
  #endif
    sort_cpu << "\n";
 };

// mise à jour  qui sont gérées par la classe mère algo
// a priori que des choses génériques du type gestion des variables privées
void Algori::MiseAJourAlgoMere(ParaGlob * paraGlob,LesMaillages * lesMail,LesReferences* lesRef
                           ,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
                           ,VariablesExporter* varExpor
                           ,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage
                           ,Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts
                           ,Resultats* resultats)
  {
    // ---------- on initialise les conteneurs quelconques pour varExpor
    varExpor->InitialisationConteneursQuelconques(*lesMail,listeVecGlob,*lesRef);
    
    // -- modif concernant le stockage global pour volume déplacé: cas d'élément 2D dans un calcul 3D
    // on met à jour le tableau de volume déplacé en fonction du nombre de maillage effectif
    int nbMailMax = lesMail->NbMaillage();
    // normalement ne fait rien si la taille n'est pas changé
    if (vol_total2D_avec_plan_ref.Taille() != nbMailMax)
      {vol_total2D_avec_plan_ref.Change_taille(nbMailMax,Coordonnee(ParaGlob::Dimension()));
       // on remet à jour le stockage des grandeurs globales
       if (pa.CalVolTotalEntreSurfaceEtPlansRef())
           { listeVarGlob["vol_total2D_avec_plan_yz"]=&(vol_total2D_avec_plan_ref(1)(1));
             listeVarGlob["vol_total2D_avec_plan_xz"]=&(vol_total2D_avec_plan_ref(1)(2));
             listeVarGlob["vol_total2D_avec_plan_xy"]=&(vol_total2D_avec_plan_ref(1)(3));
           };
       // s'il y a plus de 1 maillage, on définit de nouvelles variables globales
       if (pa.CalVolTotalEntreSurfaceEtPlansRef())
         for (int nbMail =2; nbMail<= nbMailMax; nbMail++)
           { // l'ordre des string est fait pour que le switch ensuite soit ok
             string nom1("vol_total2D_avec_plan_xy_"+ChangeEntierSTring(nbMail));
             listeVarGlob[nom1]=&(vol_total2D_avec_plan_ref(nbMail)(3));
             TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
                (VOL_ELEM_AVEC_PLAN_REF,nom1,SCALAIRE_DOUBLE);
             string nom2("vol_total2D_avec_plan_yz_"+ChangeEntierSTring(nbMail));
             listeVarGlob[nom2]=&(vol_total2D_avec_plan_ref(nbMail)(1));
             TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
                (VOL_ELEM_AVEC_PLAN_REF,nom2,SCALAIRE_DOUBLE);
             string nom3("vol_total2D_avec_plan_xz_"+ChangeEntierSTring(nbMail));
             listeVarGlob[nom3]=&(vol_total2D_avec_plan_ref(nbMail)(2));
             TypeQuelconque_enum_etendu::Ajout_un_TypeQuelconque_enum_etendu
                (VOL_ELEM_AVEC_PLAN_REF,nom3,SCALAIRE_DOUBLE);
            
             // --- on ajoute les grandeurs au niveau de paraglob
             // si elles n'existent pas
             double titi=0.; // une grandeur de travail
             Grandeur_scalaire_double grand_courant(titi); // idem
             TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant); // idem
             switch (ParaGlob::Dimension())
                { case 3: if (ParaGlob::param->GrandeurGlobal(nom1) == NULL)
                             ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
                  case 2: if (ParaGlob::param->GrandeurGlobal(nom2) == NULL)
                             ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom2);
                  case 1: if (ParaGlob::param->GrandeurGlobal(nom3) == NULL)
                             ParaGlob::param->Ajout_grandeur_consultable(&typQ1,nom1);
                  default: break;
                };
           };
      };
    // on récupère éventuellement la modulation de précision
    if (nom_modulation_precision.length())
      {modulation_precision = lesFonctionsnD->Trouve(nom_modulation_precision);
       if (modulation_precision->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          {// on vérifie qu'en retour on a un scalaire
           modulation_precision->Valeur_pour_variables_globales(); // pour simplifier
           if (modulation_precision->NbComposante() != 1)
              {cout << "\n *** erreur parametre algorithme: la fonction nD " << nom_modulation_precision
                    << " de modulation de la precision d'equilibre globale "
                    << " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
               Sortie(1);
              };
           }
       else
         {cout << "\n *** erreur parametre algorithme: la fonction nD " << nom_modulation_precision
               << " de modulation de la precision d'equilibre globale "
               << " utilise des variables autres que globales, ce n'est pas possible ! ";
          Sortie(1);
         };
      };
    // on récupère éventuellement la fonction nD définissant la norme
    if (pa.Norme().nom1 == "fonction_nD:")
      {fct_norme = lesFonctionsnD->Trouve(pa.Norme().nom2);
       if (fct_norme->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          {// on vérifie qu'en retour on a un scalaire
           fct_norme->Valeur_pour_variables_globales(); // pour simplifier
           if (fct_norme->NbComposante() != 1)
              {cout << "\n *** erreur parametre algorithme: la fonction nD " << pa.Norme().nom2
                    << " de definition de la norme de convergence  d'equilibre globale "
                    << " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
               Sortie(1);
              };
           }
       else
         {cout << "\n *** erreur parametre algorithme: la fonction nD " << pa.Norme().nom2
               << " de definition de la norme de convergence  d'equilibre globale  "
               << " utilise des variables autres que globales, ce n'est pas possible ! ";
          Sortie(1);
         };
      };
    // on récupère éventuellement la fonction correspondant à nom_fct_nD_inter_nb_entre_relax
    if (nom_fct_nD_inter_nb_entre_relax.length())
      {fct_nD_inter_nb_entre_relax = lesFonctionsnD->Trouve(nom_fct_nD_inter_nb_entre_relax);
       if (fct_nD_inter_nb_entre_relax->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          {// on vérifie qu'en retour on a un scalaire
           fct_nD_inter_nb_entre_relax->Valeur_pour_variables_globales(); // pour simplifier
           if (fct_nD_inter_nb_entre_relax->NbComposante() != 1)
              {cout << "\n *** erreur parametre algorithme: la fonction nD " << nom_fct_nD_inter_nb_entre_relax
                    << " qui permet de cacluler la valeur du parametre inter_nb_entre_relax "
                    << " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
               Sortie(1);
              };
           }
       else
         {cout << "\n *** erreur parametre algorithme: la fonction nD " << nom_fct_nD_inter_nb_entre_relax
               << " qui permet de cacluler la valeur du parametre inter_nb_entre_relax "
               << " utilise des variables autres que globales, ce n'est pas possible ! ";
          Sortie(1);
         };
      };

    // on met à jour les repères d'anisotropie éventuelle
    lesMail->Mise_a_jour_repere_anisotropie(diversStockage,lesFonctionsnD);
    
    // on introduit au niveau des noeuds, si cela n'est pas déjà fait
    // les conteneurs pour les forces internes et externes à t
    {// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
     Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
     Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
     // def d'un type quelconque représentatif  pour un vecteur force à chaque noeud
     TypeQuelconque typQ_gene_int(FORCE_GENE_INT_t,X1,gt);
     lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
     TypeQuelconque typQ_gene_ext(FORCE_GENE_EXT_t,X1,gt);
     lesMail->AjoutConteneurAuNoeud(typQ_gene_ext);
    };

    // on initialise certaines énergies qui sont stockées au niveau de l'algo
    // mais qui sont en fait indépendantes de l'algo, donc il faut que ces énergies soient à jour
    // elles sont donc initialisées à partir des grandeurs globales qui elles mêmes ont été mise à jour
    // l'objectif est d'éviter une initialisation par défaut à 0 lorsque l'algo fait suite à un autre algo
    // du coup, avant tout calcul du nouvel algo, on utilise les grandeurs déjà calculées par le précédent algo
    //
    // --- cas des énergies internes venants des lois de comportement :
    //  ENERGIE_ELASTIQUE,ENERGIE_PLASTIQUE,ENERGIE_VISQUEUSE,
    {{void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_ELASTIQUE);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energTotal.ChangeEnergieElastique(*(gr.ConteneurDouble())) ;
     };
     {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_PLASTIQUE);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energTotal.ChangeDissipationPlastique( *(gr.ConteneurDouble()) );
     };
     {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_VISQUEUSE);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energTotal.ChangeDissipationVisqueuse(*(gr.ConteneurDouble()));
     };
    };
    // --- cas des énergies de contact :
    //  ENERGIE_PENALISATION,ENERGIE_FROT_ELAST,ENERGIE_FROT_PLAST,ENERGIE_FROT_VISQ
    {{void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_PENALISATION);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
////------- debug
//cout << "\n debug*** Algori::MiseAJourAlgoMere "
//     << "\n pt_void= " << pt_void << " gr.ContDouble()= " << gr.ContDouble()
//     << " (*(gr.ConteneurDouble())) = " << (*(gr.ConteneurDouble()))
//     << flush;
//
//// --- fin debug
      energPenalisation = *(gr.ConteneurDouble());
     };
     {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_FROT_ELAST);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energFrottement.ChangeEnergieElastique(*(gr.ConteneurDouble()));
     };
     {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_FROT_PLAST);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energFrottement.ChangeDissipationPlastique( *(gr.ConteneurDouble()) );
     };
     {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(ENERGIE_FROT_VISQ);
      TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
      Grandeur_scalaire_double& gr
                     = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
      energFrottement.ChangeDissipationVisqueuse(*(gr.ConteneurDouble()));
     };
    };

   
  };


    // gestion éventuelle d'une renumérotation, qui prend en compte les éléments de contact
    // premier_calcul: indique s'il s'agit d'un premier calcul on non
    // nouvelle_situation_contact : indique s'il y a du nouveau sur le contact
    // 1) si niveau_substitution =0 : -> mise à jour de toutes les matrices
    // 2) si niveau_substitution = i : -> uniquement mise à jour de la matrices i
    // par contre la dimension de tab_matglob est toujours mis à jour si c'est nécessaire
    // ramène true si la matrice a été changée
bool Algori::Gestion_stockage_et_renumerotation_avec_contact(bool premier_calcul
                          ,LesMaillages * lesMail, bool & nouvelle_situation_contact
                          ,LesCondLim* lesCondLim,LesReferences* lesRef
                          ,Tableau <Mat_abstraite* >& tab_mato,const Nb_assemb& nb_casAssemb
                          ,LesContacts* lescontacts,int niveau_substitution)
       {
          bool retour = false; // init pas de changement a priori au niveau des matrices
          // récup des connexions entre noeud dues aux contacts
          list <Condilineaire>& listCondLine= lescontacts->ConnectionCLL();
          int taille_listCondLine=listCondLine.size(); // init
          
       #ifdef UTILISATION_MPI
          // il faut que tous les proc effectuent la renumérotation, il faut donc transmettre les conditions linéaires de contact
//le pb est que la renumérotation ne donne pas deux fois de suite le même résultat donc il faut changer la chose
//on va demander à proc 0 de faire la renumérotation et ensuite on va répercuter le résultat sur tous les proc donc
//il va falloir intervenir dans lesmaillages ---> à faire
          int proc_en_cours = ParaGlob::Monde()->rank();
          // seule le proc 0 a récupérer la liste complète des conditions linéaires
          int taille_conteneur=0; // init
          temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
          if (proc_en_cours == 0)
            { //transmission au cpu i >0
              // pour cela on va utiliser un conteneur intermédiaire
              // on calcul la taille nécessaire pour le conteneur  (a découper éventuellement ??)
              taille_conteneur=0;
              list <Condilineaire>::iterator il,ilfin  = listCondLine.end();
              for (il = listCondLine.begin();il != ilfin;il++)
                 taille_conteneur += (*il).Taille_Pack();
              inter_transfer2.Change_taille(taille_conteneur); //  le conteneur
              //   on rempli le conteneur
              int rang  = 1; // init
              for (il = listCondLine.begin();il != ilfin;il++)
                rang  = (*il).Pack_vecteur(inter_transfer2,rang);
             };
          // on transfert
          broadcast(*ParaGlob::Monde(), taille_conteneur, 0);
          if (proc_en_cours != 0)
            inter_transfer2.Change_taille(taille_conteneur);
          // le proc 0 transfert le tableau
          inter_transfer2.Broadcast(0);
          if (proc_en_cours != 0)
            {// l'objectif ici est de récupérer  les conditions linéaires
             // pour chaque cpu i>0
             listCondLine.clear();//
             // on va  remplir la liste des  conditions  limites
             int rang  = 1; // init
             while (rang !=  0)
               { Condilineaire  condi; // une condition  intermédiaire
                 rang  = condi.UnPack_vecteur(*lesMail,inter_transfer2,rang,
                                      &LesMaillages::Noeud_LesMaille);
                 listCondLine.push_back(condi);
               };
             // on met à jour la taille de la liste, car utilisée ensuite dans des tests
             taille_listCondLine=listCondLine.size();
           };
          temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
       #endif

          TroisEntiers nevez_largeurs;
          if (premier_calcul)
              {// si demandé, renumérotation en fonction des éléments en contact
               if (ParaGlob::param->ParaAlgoControleActifs().Optimisation_numerotation())
                 { // récup des connexions entre noeud dues aux contacts
                   if (taille_listCondLine > 0) //cas où il faut en tenir compte
                     {bool calcul_ok = false; // init
                      // récup des connexions entre noeuds dues aux CLL externes
                      Tableau <Tableau <Condilineaire> > tabCLL(lesCondLim->ConnectionCLL(lesMail,lesRef));
                      int tailtabCLL = tabCLL.Taille();tabCLL.Change_taille(tailtabCLL+1);
//                      tabCLL(tailtabCLL+1) = listCondLine;
                      // ajout de la partie contact
                      Tableau <Condilineaire>& tabCLL_contact = tabCLL(tailtabCLL+1); // pour simplifier
                      tabCLL_contact.Change_taille(taille_listCondLine);
                      list <Condilineaire>::iterator il,ilfin  = listCondLine.end();
                      int i=1;
                      for (il = listCondLine.begin();il != ilfin;il++,i++)
                        tabCLL_contact(i) = (*il);
                   #ifdef UTILISATION_MPI
                      // seule le proc 0 affiche
                      if (proc_en_cours == 0)
                   #endif
                      if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 2))
                        cout << "\n -- renumerotation en tenant compte des elements de contact ";
                        
                      // appel de l'utilitaire dans lesMaillages: avec mise à jour dans la foulée de l'assemblage
                      bool sans_changement_num_noeud = true; // on ne veut pas un changement de la numérotation !
                      calcul_ok = lesMail->Renumerotation(*lesRef,tabCLL,nevez_largeurs,&nb_casAssemb,sans_changement_num_noeud);
                      if (calcul_ok) // cas où il y a eu effectivement un changement de numérotation
                        {//lesMail->MiseAJourPointeurAssemblage(nb_casAssemb);// mise a jour des pointeurs d'assemblage
//                         il faut regarder un peu partout: élément, frontière etc
                         // on met à jour le tableau indice pour LesContacts
                         lescontacts->Mise_a_jour_indice(lesMail->Indice());
//                         enfin il faut renuméroter la matrice
                         Mise_a_jour_Choix_matriciel_contact
                              (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,&nevez_largeurs);
                         retour = true;
                        }
                      else
                        { Mise_a_jour_Choix_matriciel_contact
                              (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,NULL);
                         retour = true;
                        };
                     };
                 }
               else
                 { Mise_a_jour_Choix_matriciel_contact
                              (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,NULL);
                         retour = true;
                 };
              } //-- fin du cas si premier calcul
          else
             {if (nouvelle_situation_contact)
               {if (ParaGlob::param->ParaAlgoControleActifs().Optimisation_numerotation())
                 { // récup des connexions entre noeud dues aux contacts
                   if (taille_listCondLine > 0) //cas où il faut en tenir compte
                    { bool calcul_ok = false; // init
                      // récup des connexions entre noeuds dues aux CLL externes: comme les cll ont été mises à jour
                      // on récupère directement le tableau
                      Tableau <Tableau <Condilineaire> > tabCLL(lesCondLim->Tab_CLinApplique());
                      int tailtabCLL = tabCLL.Taille();tabCLL.Change_taille(tailtabCLL+1);
                      // ajout de la partie contact
                      Tableau <Condilineaire>& tabCLL_contact = tabCLL(tailtabCLL+1); // pour simplifier
                      tabCLL_contact.Change_taille(listCondLine.size());
                      list <Condilineaire>::iterator il,ilfin  = listCondLine.end();
                      int i=1;
                      for (il = listCondLine.begin();il != ilfin;il++,i++)
                        tabCLL_contact(i) = (*il);
                   #ifdef UTILISATION_MPI
                      // seule le proc 0 affiche
                      if (proc_en_cours == 0)
                   #endif
                      if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 2))
                        cout << "\n -- renumerotation en tenant compte d'un changement de contact ";
                      // appel de l'utilitaire dans lesMaillages: avec mise à jour dans la foulée de l'assemblage
                      bool sans_changement_num_noeud = true; // on ne veut pas un changement de la numérotation !
                      calcul_ok = lesMail->Renumerotation(*lesRef,tabCLL,nevez_largeurs,&nb_casAssemb,sans_changement_num_noeud);
                      if (calcul_ok) // cas où il y a eu effectivement un changement de numérotation
                        {
                         // on met à jour le tableau indice pour LesContacts
                         lescontacts->Mise_a_jour_indice(lesMail->Indice());
                         //lesMail->MiseAJourPointeurAssemblage(nb_casAssemb);// mise a jour des pointeurs d'assemblage
                         Mise_a_jour_Choix_matriciel_contact
                                    (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,&nevez_largeurs);
                         retour = true;
                        }
                      else
                        { Mise_a_jour_Choix_matriciel_contact
                              (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,NULL);
                         retour = true;
                        };
                     };
                 }
                else
                 { Mise_a_jour_Choix_matriciel_contact
                              (tab_mato,nb_casAssemb,lescontacts,niveau_substitution,NULL);
                         retour = true;
                 };
               }
              else
               {retour  =  false; };
             }; //-- fin du cas si ce n'est pas un premier calcul

          // retour
          return retour; // correct uniquement pour le proc 0, les autres procs ne s'en servent pas à priori
      };


    // --- même chose mais sans le contact, par contre prise en compte d'un changement éventuelle
    //     imposé par exemple par les CLL
    // gestion éventuelle d'une renumérotation des pointeurs d'assemblage , qui prend en compte les CLL
    // premier_calcul : indique s'il s'agit d'un premier calcul on non
    // nouvelle_situation_CLL : indique s'il y a du nouveau sur les CLL
    //  -> la renumérotation des pointeurs s'effectue que si:
    //   a) ParaAlgoControleActifs().Optimisation_pointeur_assemblage() est ok
    //   b) soit c'est un premier calcul, soit il y a du nouveau sur les CLL

    // 1) si niveau_substitution =0 : -> mise à jour de toutes les matrices
    // 2) si niveau_substitution = i : -> uniquement mise à jour de la matrices i
    // par contre la dimension de tab_matglob est toujours mis à jour si c'est nécessaire
    // ramène true si la matrice a été changée
    // NB: lescontacts est quand même passé en paramètre, car on doit le renseigner au niveau d'un
    //     tableau d'indice (num de noeuds) lorsque les num ont changés, ceci pour être opérationnel
    //     par la suite si le contact devient actif
bool  Algori::Gestion_stockage_et_renumerotation_sans_contact(LesContacts* lescontacts,bool premier_calcul
                          ,LesMaillages * lesMail, bool & nouvelle_situation_CLL
                          ,LesCondLim* lesCondLim,LesReferences* lesRef
                          ,Tableau <Mat_abstraite* >& tab_mato,const Nb_assemb& nb_casAssemb
                          ,int niveau_substitution)
      {
        #ifdef UTILISATION_MPI
          // cas d'un  calcul //, seule la (ou les) matrices du CPU 0 sont concernées
          // donc s'il s'agit d'un CPU différent, on revient immédiatement
          if (ParaGlob::Monde()->rank() != 0)
            return false;
        #endif

          TroisEntiers nevez_largeurs;
          bool retour = false; // init pas de changement a priori au niveau des matrices
          if (premier_calcul)
              {// si demandé, renumérotation des pointeurs d'assemblage
               if (ParaGlob::param->ParaAlgoControleActifs().Optimisation_pointeur_assemblage())
                 { // récup des connexions entre noeuds dues aux CLL externes
                   Tableau <Tableau <Condilineaire> > tabCLL(lesCondLim->ConnectionCLL(lesMail,lesRef));
 //                  int tailtabCLL = tabCLL.Taille();tabCLL.Change_taille(tailtabCLL+1);
 //                  tabCLL(tailtabCLL+1) = listCondLine; // ajout de la partie contact
                   if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 2))
                     cout << "\n -- renumerotation des pointeurs d'assemblage en tenant compte des CLL ";
                   // appel de l'utilitaire dans lesMaillages: avec mise à jour dans la foulée de l'assemblage
                   bool sans_changement_num_noeud = true; // on ne veut pas un changement de la numérotation !
                   bool calcul_ok = lesMail->Renumerotation(*lesRef,tabCLL,nevez_largeurs,&nb_casAssemb,sans_changement_num_noeud);
                   if (calcul_ok) // cas où il y a eu effectivement un changement de numérotation
                     {//lesMail->MiseAJourPointeurAssemblage(nb_casAssemb);// mise a jour des pointeurs d'assemblage
//                      il faut regarder un peu partout: élément, frontière etc
                      // on met à jour le tableau indice pour LesContacts
                      lescontacts->Mise_a_jour_indice(lesMail->Indice());
//                      enfin il faut renuméroter la matrice
                      // ici on ne se sert pas du contact
                      Mise_a_jour_Choix_matriciel_contact
                           (tab_mato,nb_casAssemb,NULL,niveau_substitution,&nevez_largeurs);
                      retour = true;
                     };
                   // sinon on ne fait rien
                 };
              } //-- fin du cas si premier calcul
          else
             {if (nouvelle_situation_CLL)
               {if (ParaGlob::param->ParaAlgoControleActifs().Optimisation_pointeur_assemblage())
                 { // récup des connexions entre noeuds dues aux CLL externes: comme les cll ont été mises à jour
                   // on récupère directement le tableau
                   Tableau <Tableau <Condilineaire> > tabCLL(lesCondLim->Tab_CLinApplique());
                   if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 2))
                     cout << "\n -- renumerotation des pointeurs d'assemblage en tenant compte des CLL ";
                   // appel de l'utilitaire dans lesMaillages: avec mise à jour dans la foulée de l'assemblage
                   bool sans_changement_num_noeud = true; // on ne veut pas un changement de la numérotation !
                   bool calcul_ok = lesMail->Renumerotation(*lesRef,tabCLL,nevez_largeurs,&nb_casAssemb,sans_changement_num_noeud);
                   if (calcul_ok) // cas où il y a eu effectivement un changement de numérotation
                     {
                      // on met à jour le tableau indice pour LesContacts
                      lescontacts->Mise_a_jour_indice(lesMail->Indice());
                      //lesMail->MiseAJourPointeurAssemblage(nb_casAssemb);// mise a jour des pointeurs d'assemblage
                      Mise_a_jour_Choix_matriciel_contact
                                 (tab_mato,nb_casAssemb,NULL,niveau_substitution,&nevez_largeurs);
                      retour = true;
                     };
                   // sinon on ne fait rien
                 };
               };
             }; //-- fin du cas si ce n'est pas un premier calcul
         // retour
         return retour;
      };


// mise à jour de delta_X, var_delta_X et passage en global des maxi
void Algori::Cal_Transfert_delta_et_var_X(double& max_delta_X, double& max_var_delta_X)
 { var_delta_X = -delta_X; // sauvegarde de la dernière valeur
   // calcul du nouveau delta_X
   delta_X.Zero(); delta_X += X_tdt; delta_X -= X_t;// X_tdt - X_t
   // calcul de la variation de delta_X
   var_delta_X += delta_X;
   // calcul des maxis en valeurs absolue
   max_delta_X = delta_X.Max_val_abs();
   max_var_delta_X = var_delta_X.Max_val_abs();
   // passage au niveau global
   // dans le cas MPI, c'est ok également pour tous les cpu car les positions sont répercutées sur tous les cpu
   ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXdeltaX,max_delta_X);
   ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXvarDeltaX,max_var_delta_X);
   
 };


// ---------- static pour la création d'un algorithme particulier ---------
// ramène un pointeur sur l'algorithme spécifique correspondant aux paramètres
// IMPORTANT : il y a création de l'algorithme correspondant (utilisation d'un new)
Algori* Algori::New_Agori(EnumTypeCalcul id_TypeCalcul,const bool avec_typeDeCalcul
                         ,const list <EnumSousTypeCalcul>& soustype
                         ,const list <bool>& avec_soustypeDeCalcul
                         ,UtilLecture& entreePrinc
                         )
                         
{ // définition du pointeur de retour
  Algori* algo_specifique;
  
  switch (id_TypeCalcul)
  {case NON_DYNA :
    { algo_specifique = new AlgoriNonDyna
                        (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
      break;
    }
   case NON_DYNA_CONT :
   { algo_specifique = new ImpliNonDynaCont
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case FLAMB_LINEAIRE :
   { algo_specifique = new AlgoriFlambLineaire
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case INFORMATIONS :
   { algo_specifique = new AlgoInformations
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case UTILITAIRES :
   { algo_specifique = new AlgoUtils
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_EXP :
   { algo_specifique = new AlgoriDynaExpli
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_EXP_TCHAMWA :
   { algo_specifique = new AlgoriTchamwa
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_EXP_CHUNG_LEE :
   { algo_specifique = new Algori_chung_lee
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_EXP_ZHAI :
   { algo_specifique = new AlgoriDynaExpli_zhai
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_IMP :
   { algo_specifique = new AlgoriNewmark
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case UMAT_ABAQUS :
   { algo_specifique = new AlgoUmatAbaqus
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_RUNGE_KUTTA :
   { algo_specifique = new AlgoriRungeKutta
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case DYNA_EXP_BONELLI :
   { algo_specifique = new AlgoBonelli
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case RELAX_DYNA :
   { algo_specifique = new AlgoriRelaxDyna
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   case COMBINER :
   { algo_specifique = new AlgoriCombine
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
     break;
   }
   default :
    { cout << "\n type d\'algorithme non encore implante, desole ! \n";
      cout << " agorithme demande = " << Nom_TypeCalcul(id_TypeCalcul);
      cout << endl;
      entreePrinc.MessageBuffer("** lecture du type d\'algorithme **");
      throw (UtilLecture::ErrNouvelleDonnee(-1));
      Sortie(1);
    };
  };
  
  return algo_specifique;
};

// ramène un tableau de pointeurs sur tous les algorithmes spécifique existants
// IMPORTANT : il y a création des algorithmes (utilisation d'un new)
Tableau <Algori *> Algori::New_tous_les_Algo
                        (const bool avec_typeDeCalcul
                         ,const list <EnumSousTypeCalcul>& soustype
                         ,const list <bool>& avec_soustypeDeCalcul
                         ,UtilLecture& entreePrinc)
{ // définition du tableau de pointeurs de retour
  Tableau <Algori* > tab_algo_specifique(15);
  // la méthode ne doit pas fonctionner dans le cas d'un calcul //
 #ifndef UTILISATION_MPI
  tab_algo_specifique(1) = new AlgoriNonDyna
                        (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(2) = new ImpliNonDynaCont
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(3) = new AlgoriFlambLineaire
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(4) = new AlgoInformations
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(5) = new AlgoUtils
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(6) = new AlgoriDynaExpli
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(7) = new AlgoriTchamwa
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(8) = new Algori_chung_lee
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(9) = new AlgoriDynaExpli_zhai
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(10) = new AlgoriNewmark
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(11) = new AlgoUmatAbaqus
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(12) = new AlgoriRungeKutta
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(13) = new AlgoBonelli
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(14) = new AlgoriRelaxDyna
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
  tab_algo_specifique(15) = new AlgoriCombine
                       (avec_typeDeCalcul,soustype,avec_soustypeDeCalcul,entreePrinc);
 #else
  // c'est une erreur
  cout << "\n *** erreur: la methode Algori::New_tous_les_Algo n'est pas prevu "
       << " pour fonctionner en calcul parallele, veuillez utiliser la version "
       << " mono processeur! "<< endl;
  Sortie(1);
 #endif
  
  return tab_algo_specifique;
};

#ifdef UTILISATION_MPI
  // cas d'un calcul parallèle,  passage des indicateurs
  // calculés par le process 0 aux process de calcul
  void Algori::Passage_indicConvergenceAuxProcCalcul()
   {// seule le process 0 a fait la résolution globale
    // il gère seul également la convergence, mais il doit tenir au courant les autres process
    // on utilise un std::array pour passer en une fois les infos
    temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
    std::array<int,6> indic_convergence = {phase_de_convergence,nombre_de_bonnes_convergences
                               ,nombre_de_mauvaises_convergences,a_converge
                               ,a_converge_iterMoins1,nb_cycle_test_max_var_residu
                              };
    broadcast(*ParaGlob::Monde(), indic_convergence, 0);
//    ParaGlob::Monde()->barrier();
    if (ParaGlob::Monde()->rank() != 0)
      // on récupère les grandeurs
      {phase_de_convergence = indic_convergence[0];
       nombre_de_bonnes_convergences  = indic_convergence[1];
       nombre_de_mauvaises_convergences  = indic_convergence[2];
       a_converge = indic_convergence[3];
       a_converge_iterMoins1 = indic_convergence[4];
       nb_cycle_test_max_var_residu = indic_convergence[5];
      };
    temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
   };
  // globalisation des grandeurs globales: proc de calcul -> maitre puis transmission à ParaGlob
  // et transmission aux proc de calcul:
  // on ne demande pas à ParaGlob de faire la transmission, car il ne sait pas ce qu'il transmet
  // et les infos ne sont pas contigües, le transfert ne sera pas performant
  void Algori::Globalisation_et_transfert_auxProcCalcul_grandeurs_globales()
    { // on s'occupe tout d'abord des grandeurs directement gérées par Algori
      Vecteur inter(10); // vecteur de passage
      
 //     inter(1) =
    
    
    
//    ENERGIE_CINETIQUE -> inter(1)
//    ENERGIE_EXTERNE -> 2
//    ENERGIE_INTERNE -> 3
//    PUISSANCE_ACCELERATION);
//    PUISSANCE_INTERNE);
//    PUISSANCE_EXTERNE);
//    PUISSANCE_BILAN);
//    ENERGIE_ELASTIQUE);
//    ENERGIE_PLASTIQUE);
//    ENERGIE_VISQUEUSE);
//    ENERGIE_BILAN);
//    QUANTITE_MOUVEMENT);
//    ENERGIE_PENALISATION);
//    ENERGIE_FROT_ELAST);
//    ENERGIE_FROT_PLAST);
//    ENERGIE_FROT_VISQ);
//    ENERGIE_VISCO_NUMERIQUE);
//    ENERGIE_BULK_VISCOSITY);
//    ENERGIE_HOURGLASS_);
//    ENERGIE_STABILISATION_MEMB_BIEL);
//    VOLUME_TOTAL_MATIERE);
//    MAXPUISSEXT);
//    MAXPUISSINT);
//    MAXREACTION);
//    MAXRESIDUGLOBAL);
//    MAXdeltaX);
//    MAXvarDeltaX);
//    MAXvarDdl);


//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_CINETIQUE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_EXTERNE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_INTERNE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_ACCELERATION);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_INTERNE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_EXTERNE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,PUISSANCE_BILAN);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_ELASTIQUE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_PLASTIQUE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_VISQUEUSE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_BILAN);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,QUANTITE_MOUVEMENT);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_PENALISATION);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_ELAST);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_PLAST);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_FROT_VISQ);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_VISCO_NUMERIQUE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_BULK_VISCOSITY);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_HOURGLASS_);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,ENERGIE_STABILISATION_MEMB_BIEL);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,VOLUME_TOTAL_MATIERE);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXPUISSEXT);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXPUISSINT);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXREACTION);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXRESIDUGLOBAL);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXdeltaX);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXvarDeltaX);
//     ParaGlob::param->Ajout_grandeur_consultable(&typQ1,MAXvarDdl);


    
    };
    
  // cas d'un calcul parallèle, passage des énergies, volumes
  // a priori utilisée dans le calcul de raideur et second membres
  void Algori::Passage_energiesEtVolumes()
    { tempsRaidSmEner.Mise_en_route_du_comptage(); // fin comptage cpu
      mpi::request reqs1;
      bool premier_passage = true;

      // récupération de toutes les énergies par le cpu 0
      // on dit à tous les process d'attendre sauf le master
////------------- debug --------
//cout << "\n debug Algori::Passage_energiesEtVolumes()  "
//     << "\n barriere avant transfert énergies , proc= "<< ParaGlob::Monde()->rank() << flush;
//
////------------- fin debug --------
//      ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
      // on crée un vecteur intermédiaire pour le passage d'information
      int dim_tav_double = 0;int tail_tab = vol_total2D_avec_plan_ref.Taille();
      for (int  i=1;i<= tail_tab;i++)
         dim_tav_double += vol_total2D_avec_plan_ref(i).Dimension();
      Vecteur  v_val_inter(8+dim_tav_double);
      int num_process = ParaGlob::Monde()->rank();
      tempsRaidSmEner.Arret_du_comptage(); // fin comptage cpu
      if (num_process != 0)
        {temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
         //on rempli le vecteur de passage
         v_val_inter(1) =energTotal.EnergieElastique();
         v_val_inter(2) =energTotal.DissipationPlastique();
         v_val_inter(3) =energTotal.DissipationVisqueuse();
         v_val_inter(4)=energHourglass;
         v_val_inter(5)=energStabiliMembBiel;
         v_val_inter(6)=E_bulk;
         v_val_inter(7)=P_bulk;
         v_val_inter(8)=volume_total_matiere;
         int indice = 1;
         for (int  i=1;i<= tail_tab;i++)
          { int dim_coord = vol_total2D_avec_plan_ref(i).Dimension();
            if (dim_coord)
               for (int j=1;j<= dim_coord;j++,indice++)
                  v_val_inter(8+indice)=vol_total2D_avec_plan_ref(i)(j);
          };
//        //------------- debug --------
//        cout << "\n debug Algori::Passage_energiesEtVolumes() num_process= "<< num_process;
//        cout << "\n v_val_inter=  "<<v_val_inter;
//
//        //------------- fin debug --------
         temps_transfert_court_matSm.Arret_du_comptage();
         // on récupère un signal du process 0
         temps_attente_matSm.Mise_en_route_du_comptage(); // comptage cpu
         if (premier_passage) {premier_passage = false;}
         else // on attend que les transferts soient finis
           {if (reqs1.active()) reqs1.wait();
           };
         temps_attente_matSm.Arret_du_comptage(); // fin comptage cpu
         temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu

         // on transmet le vecteur intermédiaire
         reqs1 = v_val_inter.Ienvoi_MPI(0,27);

         temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
        }
      else // cas du proocess 0
        {int nb_process =  ParaGlob::Monde()->size();
         for (int i=1;i<nb_process;i++) // < absolu, donc le max c'est nb_process-1
           {temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
            reqs1 = v_val_inter.Irecup_MPI(mpi::any_source, 27);
            temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
            temps_attente_matSm.Mise_en_route_du_comptage(); // comptage cpu
            reqs1.wait(); // on attend que le conteneur soit rempli
            temps_attente_matSm.Arret_du_comptage(); // fin comptage cpu
            temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
            //on récupère les info via  le vecteur de passage
            EnergieMeca inter(v_val_inter(1),v_val_inter(2),v_val_inter(3));
            energTotal += inter;
            energHourglass += v_val_inter(4);
            energStabiliMembBiel += v_val_inter(5);
            E_bulk += v_val_inter(6);
            P_bulk += v_val_inter(7);
            volume_total_matiere += v_val_inter(8);
            int indice = 1;
            for (int  i=1;i<= tail_tab;i++)
             { int dim_coord = vol_total2D_avec_plan_ref(i).Dimension();
               if (dim_coord)
                  for (int j=1;j<= dim_coord;j++,indice++)
                     vol_total2D_avec_plan_ref(i)(j) += v_val_inter(8+indice);
             };
            temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
           };
        };

////------------- debug --------
//cout << "\n debug Algori::Passage_energiesEtVolumes() ";
//cout << "\n energTotal "<<energTotal
//     << " volume_total_matiere "<< volume_total_matiere;
//
////------------- fin debug --------
    };
    
  // passage des énergies liées au contact
  void Algori::Passage_energiesContact()
    { mpi::request reqs1;
      bool premier_passage = true;

      // récupération de toutes les énergies par le cpu 0
      // on dit à tous les process d'attendre sauf le master

      // on crée un vecteur intermédiaire pour le passage d'information
      Vecteur  v_val_inter(4);
      int num_process = ParaGlob::Monde()->rank();
      if (num_process != 0)
        {temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
         //on rempli le vecteur de passage
         v_val_inter(1) =energFrottement.EnergieElastique();
         v_val_inter(2) =energFrottement.DissipationPlastique();
         v_val_inter(3) =energFrottement.DissipationVisqueuse();
         v_val_inter(4)=energPenalisation;
//        //------------- debug --------
//        cout << "\n debug Algori::Passage_energiesContact() num_process= "<< num_process;
//        cout << "\n v_val_inter=  "<<v_val_inter;
//
//        //------------- fin debug --------
         temps_transfert_court_contact.Arret_du_comptage();
         // on récupère un signal du process 0
         temps_attente_contact.Mise_en_route_du_comptage(); // comptage cpu
         if (premier_passage) {premier_passage = false;}
         else // on attend que les transferts soient finis
           {reqs1.wait();
           };
         temps_attente_contact.Arret_du_comptage(); // fin comptage cpu
         temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu

         // on transmet le vecteur intermédiaire
         reqs1 = v_val_inter.Ienvoi_MPI(0,270);

         temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
        }
      else // cas du proocess 0
        {int nb_process =  ParaGlob::Monde()->size();
         for (int i=1;i<nb_process;i++) // < absolu, donc le max c'est nb_process-1
           {temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
            reqs1 = v_val_inter.Irecup_MPI(mpi::any_source, 270);
            temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
            temps_attente_contact.Mise_en_route_du_comptage(); // comptage cpu
            reqs1.wait(); // on attend que le conteneur soit rempli
            temps_attente_contact.Arret_du_comptage(); // fin comptage cpu
            temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
            //on récupère les info via  le vecteur de passage
            EnergieMeca inter(v_val_inter(1),v_val_inter(2),v_val_inter(3));
            energFrottement += inter;
            energPenalisation += v_val_inter(4);
            temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
           };
        };

////------------- debug --------
//cout << "\n debug Algori::Passage_energiesContact() ";
//cout << "\n energFrottement "<<energFrottement
//     << " energPenalisation "<< energPenalisation;
//
////------------- fin debug --------
    };

  // passage des max puissance, résidu, réaction du proc 0 aux i
  // et passage en variables globales pour les proc i
  void Algori::Passage_max_puiss_res_reac(double maxPuissExt,double maxPuissInt,double maxReaction)
    { temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
     
      // on crée un vecteur intermédiaire pour le passage d'information
      Vecteur  v_val_inter(5);
      int num_process = ParaGlob::Monde()->rank();
      if (num_process == 0)
        {//on rempli le vecteur de passage
         v_val_inter(1) = maxPuissExt;
         v_val_inter(2) = maxPuissInt;
         v_val_inter(3) = maxReaction;
         // pour le max du résidu, il faut le récupérer
         {void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(MAXRESIDUGLOBAL);
          TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
          Grandeur_scalaire_double& gr
                         = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
          v_val_inter(4)= *(gr.ConteneurDouble());
         };
         {// idem pour la norme de convergence
          void* pt_void =  ParaGlob::param->Mise_a_jour_grandeur_consultable(NORME_CONVERGENCE);
          TypeQuelconque* pt_quelc = (TypeQuelconque*) pt_void;
          Grandeur_scalaire_double& gr
                         = *((Grandeur_scalaire_double*) pt_quelc->Grandeur_pointee()); // pour simplifier
          v_val_inter(5)= *(gr.ConteneurDouble());
         };
         
//        //------------- debug --------
//        cout << "\n debug Algori::Passage_max_puiss_res_reac(...) num_process= "<< num_process;
//        cout << "\n v_val_inter=  "<<v_val_inter;
//
//        //------------- fin debug --------
        };
      v_val_inter.Broadcast(0);
      if (num_process != 0)
        {//après récup du vecteur de passage
         // on remplit les variables globales
         ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXPUISSEXT,v_val_inter(1));
         ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXPUISSINT,v_val_inter(2));
         ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXREACTION,v_val_inter(3));
         ParaGlob::param->Mise_a_jour_grandeur_consultable_Scalaire_double(MAXRESIDUGLOBAL,v_val_inter(4));
         Transfert_ParaGlob_NORME_CONVERGENCE(v_val_inter(5));
//        //------------- debug --------
//        cout << "\n debug Algori::Passage_max_puiss_res_reac(...) num_process= "<< num_process;
//        cout << "\n v_val_inter=  "<<v_val_inter;
//
//        //------------- fin debug --------
        };
      temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu

////------------- debug --------
//cout << "\n debug Algori::Passage_energiesContact() ";
//
////------------- fin debug --------
    };

#endif




