// 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 "LesContacts.h"
#include <vector>
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "CharUtil.h"



// --------------- variables statiques ---------
 MotCle LesContacts::motCle; // liste des mots clés
 Tableau <const TypeQuelconque *  > LesContacts::tqi_const_fct_nD_niveau_commentaire;
 Tableau < TypeQuelconque *  > LesContacts::tqi_fct_nD_niveau_commentaire;
 Tableau <int>  LesContacts::t_num_ordre_fct_nD_niveau_commentaire;


//------------------------- la classe ReactCont -------------  
// surcharge de l'operator de lecture
//istream & operator >> (istream & ent, LesContacts::ReactCont & a)
istream & operator >> (istream & ent, LesContacts::ReactCont & )
  { // lecture du type et vérification
    string nom_type; ent >> nom_type;
    if (nom_type != "LesContacts::ReactCont")
      Sortie(1);
    // les infos **** pb de la reconnaissance du noeud ***
    /*  EN CHANTIER 
    ent >> a.noe->Num_Mail() >> a.noe->Num_noeud() << " ";
    // la force
    sort << a.force;
    // les noeuds de la frontière maitre
    int taille = tabNoeud.Taille();
    for (int i=1;i<=taille;i++)
      sort << a.tabNoeud(i)->Num_Mail() 
           << " " << a.tabNoeud(i)->Num_noeud() << " "; 
    // les réactions de la frontière maître
    int taille2 = tabForce.Taille();
    for (int i=1;i<=taille2;i++)
      sort << a.tabForce(i); */
   return ent ;
   };
// surcharge de l'operator d'ecriture
ostream & operator << (ostream & sort , const LesContacts::ReactCont & a)
  { // écriture du type
    sort << "LesContacts::ReactCont ";
    // les infos
    sort << a.noe->Num_Mail() << " " << a.noe->Num_noeud() << " ";
    // la force
    sort << a.force;
    // les noeuds de la frontière maitre
    int taille = a.tabNoeud.Taille();
    for (int i=1;i<=taille;i++)
      sort << a.tabNoeud(i)->Num_Mail() 
           << " " << a.tabNoeud(i)->Num_noeud() << " "; 
    // les réactions de la frontière maître
    int taille2 = a.tabForce.Taille();
    for (int i=1;i<=taille2;i++)
      sort << a.tabForce(i); 
   return sort ;
   };

// constructeur par defaut
LesContacts::ReactCont::ReactCont() : force(),tabNoeud(),tabForce() { noe = NULL; };
// constructeur en fonction des datas du noeud esclave seul
LesContacts::ReactCont::ReactCont(Noeud* no,const Coordonnee& forc) :
   force(forc),tabNoeud(),tabForce() { noe = no;};
// constructeur en fonction des datas de tous les noeuds
LesContacts::ReactCont::ReactCont
     (Noeud* no,const Coordonnee& forc,Tableau <Noeud *> tN,const Tableau <Coordonnee>& tFor)
         : force(forc),tabNoeud(tN),tabForce(tFor) { noe = no;};
// constructeur de copie
LesContacts::ReactCont::ReactCont(const ReactCont& a) : force(a.force),tabNoeud(a.tabNoeud),tabForce(a.tabForce) 
          { noe = a.noe;};
// affectation
LesContacts::ReactCont& LesContacts::ReactCont::operator = (const LesContacts::ReactCont& a)
          { force =a.force;noe = a.noe;tabNoeud = a.tabNoeud;tabForce = a.tabForce;
            return *this;};
// test
bool LesContacts::ReactCont::operator == (const LesContacts::ReactCont& a) 
         { if ((force == a.force) &&(noe == a.noe) &&
               (tabNoeud == a.tabNoeud) &&(tabForce == a.tabForce))
                return true; else return false;};
bool LesContacts::ReactCont::operator != (const LesContacts::ReactCont& a)
         { if (*this == a) return false; else return true; };  
       
//------------------------- fin la classe ReactCont -------------
    // CONSTRUCTEURS :
// constructeur par defaut
LesContacts::LesContacts () :
 listCoLin(),tabReacCont(),listContact()//,numtesN()
 ,sauve_lesFonctionsnD(NULL),fct_nD_contact()
 ,fct_niveau_commentaire(NULL),li_pour_noeuds_element(),gr_pour_noeud(NULL),gr_pour_elem(NULL)
 ,listContact_nouveau_tatdt(),listContact_efface_tatdt()
 ,nom_ref_zone_contact(),lissage_de_la_normale()
 ,t_listFront(),nb_mail_Esclave(),nbmailautocontact(0),nbmailMaitre()
#ifdef UTILISATION_MPI
 ,pointe_t_listFront(),v_interProc_contact_actif()
 // pour les i/o
 ,buffer_ioBI_MPI(),tailles_buffer_ioBI_MPI(),offset_LesContacts()
 ,nb_buffer(3)
#endif
 ,tesctotal(),tesN_encontact()
 ,tesN_collant()
 ,nb_contact_actif(0),indice(),cont_solide_defor(),liQ_en_sortie()
 ,t_connectionCLL()
 ,liste_elemens_front(),tempsContact()
#ifdef UTILISATION_MPI
 ,temps_transfert_court(),temps_transfert_long(),temps_attente()
 ,inter_transfer(),inter_transfer2(),lesMaille(NULL)
#endif
  {// pour une sortie spécifique noeud et ou element
   Grandeur_scalaire_entier grand_courant_entier(0); // par défaut pour la création des conteneurs quelconques
   li_pour_noeuds_element.push_front(TypeQuelconque(NUM_NOEUD,X1,grand_courant_entier));
   gr_pour_noeud = ((Grandeur_scalaire_entier*) (*li_pour_noeuds_element.begin()).Grandeur_pointee());
   li_pour_noeuds_element.push_front(TypeQuelconque(NUM_ELEMENT,EPS11,grand_courant_entier));
   gr_pour_elem = ((Grandeur_scalaire_entier*) (*li_pour_noeuds_element.begin()).Grandeur_pointee());
#ifdef UTILISATION_MPI
   int nb_process =  ParaGlob::Monde()->size();
   taille_offset = nb_process + 1;
   buffer_ioBI_MPI.Change_taille(nb_buffer);
   tailles_buffer_ioBI_MPI.resize(nb_process,0);
   offset_LesContacts.resize(taille_offset);
#endif
};
// constructeur de copie
LesContacts::LesContacts (const LesContacts& a):
 listCoLin(a.listCoLin),tabReacCont(a.tabReacCont)
 ,sauve_lesFonctionsnD(a.sauve_lesFonctionsnD),fct_nD_contact(a.fct_nD_contact)
 ,fct_niveau_commentaire(a.fct_niveau_commentaire),li_pour_noeuds_element(a.li_pour_noeuds_element)
 ,gr_pour_noeud(a.gr_pour_noeud),gr_pour_elem(a.gr_pour_elem)
 ,listContact(a.listContact)//,numtesN(a.numtesN)
 ,listContact_nouveau_tatdt(a.listContact_nouveau_tatdt),listContact_efface_tatdt(a.listContact_efface_tatdt)
 ,nom_ref_zone_contact(a.nom_ref_zone_contact),lissage_de_la_normale(a.lissage_de_la_normale)
 ,t_listFront(a.t_listFront),nb_mail_Esclave(a.nb_mail_Esclave),nbmailautocontact(a.nbmailautocontact)
#ifdef UTILISATION_MPI
 ,pointe_t_listFront(),v_interProc_contact_actif()
 ,buffer_ioBI_MPI(),tailles_buffer_ioBI_MPI(),offset_LesContacts()
 ,nb_buffer(3)
#endif
 ,nbmailMaitre(a.nbmailMaitre),tesctotal(a.tesctotal),tesN_encontact(a.tesN_encontact)
 ,tesN_collant(a.tesN_collant)
 ,nb_contact_actif(a.nb_contact_actif),indice(a.indice),cont_solide_defor(a.cont_solide_defor)
 ,liste_elemens_front(a.liste_elemens_front),liQ_en_sortie(),tempsContact(a.tempsContact)
 ,t_connectionCLL(a.t_connectionCLL)
#ifdef UTILISATION_MPI
 ,temps_transfert_court(a.temps_transfert_court)
 ,temps_transfert_long(a.temps_transfert_long),temps_attente(a.temps_attente)
 ,inter_transfer(),inter_transfer2(),lesMaille(NULL)
#endif
  {// on réaffecte les pointeurs pour la sortie spécifique noeud et ou element
   list <TypeQuelconque>::iterator ili = li_pour_noeuds_element.begin();
   gr_pour_elem = ((Grandeur_scalaire_entier*) (*ili).Grandeur_pointee());
   ili++;
   gr_pour_noeud = ((Grandeur_scalaire_entier*) (*ili).Grandeur_pointee());
#ifdef UTILISATION_MPI
   // on redéfini le tableau pointe_t_listFront() et la numérotation unique dans les fronts stockés
   pointe_t_listFront.Change_taille(a.pointe_t_listFront.Taille());
   int nb_zone = MaX(1,nom_ref_zone_contact.size());
   int inum = 1;
   for (int i=1;i<=nbmailMaitre;i++)
    { for (int j=1;j<=nb_zone;j++)
       { LaLIST_io <Front> & list_fronta = (t_listFront(i)(j)); // pour simplifier
         LaLIST_io <Front>::iterator il,ilfin = list_fronta.end();
         for (il = list_fronta.begin();il != ilfin; il++,inum++)
           {pointe_t_listFront(inum) = &(*il);
            (*il).ChangeNumUnique(inum);
           };
       };
     };
   // pour les i-o
   int nb_process =  ParaGlob::Monde()->size();
   taille_offset = nb_process + 1;
   buffer_ioBI_MPI.Change_taille(nb_buffer);
   tailles_buffer_ioBI_MPI.resize(nb_process,0);
   offset_LesContacts.resize(taille_offset);
#endif

  };
    // DESTRUCTEUR :
LesContacts::~LesContacts ()
  { };
    
   // METHODES PUBLIQUES :
      
// initialisation des zones de contacts éventuelles à partir des éléments de frontières et des noeuds esclaves
// sauf les frontières qui sont les mêmes pendant tout le calcul
 // --- en entrée:
  // les maillages, les ref et les fonctions nD
 // -- en sortie:
  // cas du contact type 4 : on renseigne éventuellement une fonction de pilotage --> fct_pilotage_contact4
  // récup de: nb_mail_Esclave, nbmailMaitre,
  // récup du tableau "indice" : = la liste pour chaque noeud, des éléments qui contient ce noeud
  // création des conteneurs internes : tesctotal, tesN_collant, t_listFront, tesN_encontact

void LesContacts::Init_contact(LesMaillages& lesMail
                    ,const LesReferences& lesRef
                    ,LesFonctions_nD* lesFonctionsnD)
   {
     tempsContact.Mise_en_route_du_comptage(); // temps cpu
     // sauvegarde de la liste des fonctions nD
     sauve_lesFonctionsnD = lesFonctionsnD;
     // init éventuel du pilotage par fct nD du niveau de commentaire
     LesContacts::Init_fct_niveau_commentaire();
     int niveau_commentaire_lescontacts = Permet_affichage();
     // on met à jour le niveau de commentaire dans les éléments de contact
     ElContact::Mise_a_jour_niveau_commentaire(); 
   #ifdef UTILISATION_MPI
     // on sauvegarde un  pointeur sur les maillages
     lesMaille = &lesMail;

     if (ParaGlob::Monde()->rank() == 0)
   #endif
     if (niveau_commentaire_lescontacts > 4)
         cout << "\n -- LesContacts::Init_contact: ";
         
     Creation_Fct_nD_contact(); // récupération des fonctions de pilotage éventuelles

     // --- récup info maillage
     // tescin : a la dimension du nombre de maillage esclave
     //        comme les maillages esclaves sont les premiers dans le .info,
     //        tescin(i) correspond aux noeuds des frontières du maillage i
     // listFrontiere (i) : toutes les frontières des maillages, (peut-être vide pour certains maillages sans frontières)
     //                    correspond aux frontières du maillage i: dabord pour les esclaves puis les maîtres
     // nbEscla : nb de maillage esclave
     // ind : pour tous les maillages, la liste des éléments qui contiennent chaque noeud
     //       (mis à jour  lors de la création des frontières)
     Tableau < Tableau <Noeud*> *> tescin = lesMail.Tab_noeud_frontiere_esclave();
     Tableau <LaLIST <Front>*>& listFrontiere = lesMail.ListFrontiere();
     const Tableau < const Tableau <List_io < Element* > > *>&  ind = lesMail.Indice();


     // dans le cas d'un contact de type 4 on renseigne éventuellement une fonction de pilotage
     string nom_fct4 = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_bascul_contact_type_4();
     if ((ParaGlob::param->ParaAlgoControleActifs().ContactType() == 4)
         && (nom_fct4 != "_")
        )
      {// on va récupérer la fonction
       if (lesFonctionsnD->Existe(nom_fct4))
        { Fonction_nD * pt_fonct = lesFonctionsnD->Trouve(nom_fct4);
          // on vérifie pour l'instant que c'est bien une fonction de grandeurs globales
          if (pt_fonct->NbVariable_locale() != 0) // cas où il n'y a pas que des variables globales
         #ifdef UTILISATION_MPI
           {if (ParaGlob::Monde()->rank() == 0)
         #endif
            { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
                   << " du type de contact 4  : " << nom_fct4
                   << " n'utilise pas que des variables globales  !! ";
              tempsContact.Arret_du_comptage(); // fin cpu
              Sortie(1);
            }
         #ifdef UTILISATION_MPI
           }
         #endif
          else if (pt_fonct->NbComposante() > 2)
         #ifdef UTILISATION_MPI
           {if (ParaGlob::Monde()->rank() == 0)
         #endif
            { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
                   << " du type de contact 4  : " << nom_fct4
                   << " ramene plus de 2 composantes !! ";
              tempsContact.Arret_du_comptage(); // fin cpu
              Sortie(1);
            }
         #ifdef UTILISATION_MPI
           }
         #endif
          else // sinon ok
           {ElContact::Init_fct_pilotage_contact4(pt_fonct);}
        }
       else
      #ifdef UTILISATION_MPI
        {if (ParaGlob::Monde()->rank() == 0)
      #endif
        { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
               << " du type de contact 4 , le nom : " << nom_fct4
               << " ne correspond pas a une fonction nD existante !! ";
          tempsContact.Arret_du_comptage(); // fin cpu
          Sortie(1);
        };
      #ifdef UTILISATION_MPI
        };
      #endif
      };
    
   /* // ----pour le débug
   //{int nbMaillageTotal = listFrontiere.Taille();
   //for (int nbmail=1;nbmail<=nbMaillageTotal;nbmail++)
   //  {int nbfront = listFrontiere(nbmail)->size();
   //   cout << "\n maillage " << nbmail << " -------- ";
   //   LaLIST <Front>::iterator iff,iffin = listFrontiere(nbmail)->end();
   //   iff=listFrontiere(nbmail)->begin();
   ////   for (iff=listFrontiere(nbmail)->begin();iff !=iffin;iff++)
   //   Front& titi = (*iff);
   //      titi.Affiche(); cout << "\n";
   //
   //  };
   //
   // Sortie(1);
   //};
   //// fin débug */
     // dans le tableau de listes de frontière on a d'abord les elements frontieres
     // esclaves puis les elements maitres
     int ntmail = listFrontiere.Taille(); // nb maxi de maillages
     nb_mail_Esclave = lesMail.NbEsclave(); // def du nombre de maillages esclaves
     // les maillages mixtes (ou en autocontact) font partie de la liste des nbEscla
     // d'où si par exemple tous les éléments peuvent entrer en auto-contact
     // -> nbEscla == ntmail == nbmailautocontact == nbmailMaitre
     nbmailMaitre = ntmail-(nb_mail_Esclave-nbmailautocontact); // def du nombre de maillage maitres
     // dans le cas d'auto-contact, on vérifie la cohérence
   #ifdef UTILISATION_MPI
     if (ParaGlob::Monde()->rank() == 0)
   #endif
     if (nbmailautocontact != 0)
      {if ((nbmailautocontact <1) || (nbmailautocontact > nb_mail_Esclave))
             // nbmailautocontact doit etre >= 0 et < nb_mail_Esclave
        { cout << "\n ** incoherence dans le  nombre de maillage en auto contact !! "
               << ", le nombre de maillage en auto contact lu : " << nbmailautocontact
               << ", n\'est pas acceptable, il est soit negatif soit superieur au nombre de maillage esclave ( "
               << nb_mail_Esclave << " ) "
               << endl;
          if (niveau_commentaire_lescontacts >= 0)
            cout << "\n LesContacts::Init_contact(... " << endl;
          tempsContact.Arret_du_comptage(); // fin cpu
          Sortie(1);
        };
      };
     // on récupère le tableau indice
     indice = ind;
   #ifdef UTILISATION_MPI
     if (ParaGlob::Monde()->rank() == 0)
   #endif
     if (niveau_commentaire_lescontacts >2 )
          cout << "\n >>>> Information : Initialisation du contact: ";
     // dimensionnement du premier niveau des tableaux
     tesctotal.Change_taille(nb_mail_Esclave);
     tesN_collant.Change_taille(nb_mail_Esclave);
     t_listFront.Change_taille(nbmailMaitre);
     // --- on s'occupe du deuxième niveau de tesN_encontact
     // une map vide par défaut
     std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > > map_vide;
     tesN_encontact.Change_taille(nb_mail_Esclave,map_vide);
    
     // --- on s'occupe maintenant des niveaux 2 et 3 des tableaux tesctotal et tesN_collant
     // on regarde si la zone de contact est restreinte
     if (nom_ref_zone_contact.size() == 0)
      { // cas d'un contact non restreint
        // cela correspond finalement à une seule zone de contact
        // 1-- cas des noeuds esclaves
        for (int ii=1;ii<= nb_mail_Esclave;ii++)
          { int taille = tescin(ii)->Taille(); // nombre de noeuds esclave
            // tescin -> tous les noeuds possiblement en esclave donc en contact
            tesctotal(ii).Change_taille(1);tesctotal(ii)(1).Change_taille(taille);
            tesN_collant(ii).Change_taille(1);tesN_collant(ii)(1).Change_taille(taille);
            for (int itai=1;itai<=taille;itai++)
              {// ici, la seule zone c'est "tout" les noeuds esclaves, du coup le numéro d'ordre
               // de stockage c'est le numéro dans tescin(ii), c-a-d le numéro de classement des noeuds esclaves
               // pour le maillage ii
               tesctotal(ii)(1)(itai) = (*tescin(ii))(itai);
               tesN_collant(ii)(1)(itai) = 0; // pas de contact collant car le contact est non restreint
              };
          #ifdef UTILISATION_MPI
            if (ParaGlob::Monde()->rank() == 0)
          #endif
            if (niveau_commentaire_lescontacts >2 )
              cout << "\n mail. esclave "<<ii<<" : "<<taille << " noeuds esclaves pour contact ";
          };
        // 2-- pour les éléments
        int ilistfront = 1; // compteur pour le tableau t_listFront
        // on parcours les elements maitres: à cause d'un auto contact
        // éventuelle on peut avoir des maillages esclaves qui jouent le rôle également de
        // maillages maitres
        for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++,ilistfront++)
         { t_listFront(ilistfront).Change_taille(1); // une seule zone de contact
           LaLIST_io <Front> & lis_fronta = (t_listFront(ilistfront)(1));
           LaLIST <Front>::iterator iMi,iMifin=(*listFrontiere(jf)).end();
           for (iMi = (*listFrontiere(jf)).begin();iMi != iMifin; iMi++)
                lis_fronta.push_back((*iMi));
         #ifdef UTILISATION_MPI
           if (ParaGlob::Monde()->rank() == 0)
         #endif
           if (niveau_commentaire_lescontacts >2 )
            cout << "\n mail. maitre "<<ilistfront<<" : "<<lis_fronta.size()
                 << " frontieres pour contact ";
         };
      }
     else
      { // cas d'une zone restreinte de contact
        // on va iterer sur les noeuds esclaves pour savoir s'ils appartiennent à la zone de contact potentiel
        list <Quatre_string_un_entier>::iterator il,ilfin=nom_ref_zone_contact.end();
        int nb_zone = nom_ref_zone_contact.size();
      #ifdef UTILISATION_MPI
        if (ParaGlob::Monde()->rank() == 0)
      #endif
        if (niveau_commentaire_lescontacts >2 )
             cout << "\n --> nombre de zone de contact: " << nb_zone;
        // --- tout d'abord on s'occupe des noeuds esclaves
        // on va boucler sur les zones pour être sûr de définir complètement toutes les zones
        int izone=1;
        for (il=nom_ref_zone_contact.begin(); il!=ilfin;il++,izone++) // boucle sur les références de zone_contact
         { // recup de la reference correspondant au mot cle
           string * nom_mail_noe=NULL;
           string nom_inter;
           if ((*il).nom1.length())
                {nom_inter = ((*il).nom1);
                 nom_mail_noe = &nom_inter;
                }
           const Reference & ref =  lesRef.Trouve((*il).nom2,nom_mail_noe);
           // on continue que si c'est une référence de noeud
         #ifdef UTILISATION_MPI
           if (ParaGlob::Monde()->rank() == 0)
         #endif
           if (ref.Indic() != 1)
             { // ce n'est pas normal -> message d'erreur
               cout << "\n *** erreur la reference de zone de contact n'est pas "
                    << " une reference de noeud ! ";
               ref.Affiche();
               cout << "\n LesContacts::Init_contact(..." << endl;
               tempsContact.Arret_du_comptage(); // fin cpu
               Sortie(1);
             };
           // on peut maintenant utiliser de manière sûre une ref NE
           const ReferenceNE & refNE = ((ReferenceNE &) ref);
           // maintenant on va boucler sur les noeuds esclaves pour trouver
           // les noeuds de la ref
           bool zone_definie = false;
           for (int intot = 1;intot<= nb_mail_Esclave;intot++)
            {// on dimensionne le niveaux 2 des tableaux
             tesctotal(intot).Change_taille(nb_zone);
             tesN_collant(intot).Change_taille(nb_zone);
             // et maintenant le niveau 3 c-a-d le troisième niveau
             //Les zones définies sont prises telles qu'elle, elles peuvent donc
             // définir des noeuds potentiels au contact en dehors de ceux définis
             // par la construction automatique des frontières dans lesMaillages
             // -> donc ici on ne considère pas tescin (modif: 16 mai 2020)
             int nb_noe = refNE.Taille(); // init
             tesctotal(intot)(izone).Change_taille(nb_noe);
             tesN_collant(intot)(izone).Change_taille(nb_noe);
             // maintenant on va remplir
             for (int no_dans_ref = 1; no_dans_ref<= nb_noe;no_dans_ref++)
               {int num_noe_ref = refNE.Numero(no_dans_ref);
                tesctotal(intot)(izone)(no_dans_ref)= &(lesMail.Noeud_LesMaille(ref.Nbmaille(),num_noe_ref));
                tesN_collant(intot)(izone)(no_dans_ref)= (*il).n;
               }; // -- fin de la boucle sur les noeuds de la référence
           #ifdef UTILISATION_MPI
             if (ParaGlob::Monde()->rank() == 0)
           #endif
             if (niveau_commentaire_lescontacts >2 )
                  cout << "\n maillage esclave "<<intot<< " : zone de contact: " << izone
                       <<" =>  " << nb_noe << " noeuds esclaves pour contact ";
              // arrivée ici, c'est que la zone a été définie
              zone_definie = true;
            }; // -- fin de la boucle sur intot c-a-d les maillages esclave
           // message d'erreur si la zone n'a pas été définie
         #ifdef UTILISATION_MPI
           if (ParaGlob::Monde()->rank() == 0)
         #endif
           if (!zone_definie)
            { cout << "\n *** erreur dans la construction de la zone de contact "<<izone
                   << " on ne trouve pas le maillage esclave correspondant ! ";
              refNE.Affiche();
              cout << "\n LesContacts::Init_contact(..." << endl;
              tempsContact.Arret_du_comptage(); // fin cpu
              Sortie(1);
            };
         }; //-- fin de la boucle sur les zones de contact
         
        // --- maintenant  on s'occupe des frontières des maillages maîtres
        //Les zones définies sont prises telles qu'elle, elles peuvent donc
        // définir des frontières potentielles au contact en dehors de ceux définis
        // par la construction automatique des frontières dans lesMaillages
        // -> donc ici on ne considère pas "listFrontiere" (modif: 16 mai 2020)

        Tableau < int > zone_frontiere(nb_zone,0); // le nb d'elem dans chaque zone
        // on initialise la liste
        // on parcours les elements maitres
        int ilistfront = 1; // compteur pour le tableau t_listFront
        //à cause d'un auto contact  éventuelle on peut avoir des maillages esclaves qui jouent le rôle également de
        // maillages maitres
        for (int jlf=ntmail-nbmailMaitre+1;jlf<=ntmail;jlf++,ilistfront++) // boucle sur les maillages maitres
         {// on dimensionne le niveaux 2 des tableaux
          t_listFront(ilistfront).Change_taille(nb_zone);
          int izone = 1; // init compteur de zone
          for (il=nom_ref_zone_contact.begin(); il!=ilfin;il++,izone++) // boucle sur les références de zone_contact
            { // recup de la reference correspondant au mot cle
              string * nom_mail_face=NULL;
              if (((*il).nom3.length()))
                   nom_mail_face = &(*il).nom3;
              // on regarde si la référence existe
              string nom_ref = (*il).nom4;
            #ifdef UTILISATION_MPI
              if (ParaGlob::Monde()->rank() == 0)
            #endif
              if (!lesRef.Existe(nom_ref,nom_mail_face))
                 {  cout << "\n *** erreur la reference "<< nom_ref;
                    if (nom_mail_face != NULL)
                        cout << " du maillage " << *nom_mail_face;
                    cout  << "  n'existe pas !! ";
                    cout << "\n LesContacts::Init_contact(..." << endl;
                    tempsContact.Arret_du_comptage(); // fin cpu
                    Sortie(1);
                 };

              const Reference & ref =  lesRef.Trouve((*il).nom4,nom_mail_face);
              // on continue si le maillage de la ref est bien celui du maître que l'on consulte actuellement
              if (ref.Nbmaille() == jlf)
               {// --- on balaie les frontières potentielles
                LaLIST_io <Front> & list_fronta = (t_listFront(ilistfront)(izone)); // pour simplifier
                switch (ref.Indic())
                 {case 3: // cas d'une frontière de type surface,
                   {const ReferenceAF & refAF = ((ReferenceAF &) ref);
                    int nb_fr = refAF.Taille();
                    for (int i_fr = 1; i_fr <=  nb_fr;i_fr++)
                     {int num_fr = refAF.NumeroFA(i_fr); // le numéro de la frontière
                      int num_ele = refAF.NumeroElem(i_fr); // le numéro de l'élément associé
                      int num_mail = refAF.Nbmaille();
                      Element& ele = lesMail.Element_LesMaille(num_mail, num_ele);
                      // récupération ou création de la frontière
                      ElFrontiere* fro = ele.Frontiere_surfacique(num_fr);
                      // création et ajout de la frontière
                      list_fronta.push_back(Front (*fro,&ele,num_fr)) ;
                      zone_frontiere(izone)++;
                     };
                    break;
                   }
                  case 4: // cas d'une frontière de type arête
                   {const ReferenceAF & refAF = ((ReferenceAF &) ref);
                    int nb_fr = refAF.Taille();
                    for (int i_fr = 1; i_fr <=  nb_fr;i_fr++)
                     {int num_fr = refAF.NumeroFA(i_fr); // le numéro de la frontière
                      int num_ele = refAF.NumeroElem(i_fr); // le numéro de l'élément associé
                      int num_mail = refAF.Nbmaille();
                      Element& ele = lesMail.Element_LesMaille(num_mail, num_ele);
                      // récupération ou création de la frontière
                      ElFrontiere* fro = ele.Frontiere_lineique(num_fr);
                      // création et ajout de la frontière
                      list_fronta.push_back(Front (*fro,&ele,num_fr)) ;
                      zone_frontiere(izone)++;
                     };
                    break;
                   }
                  default:
                   // ici la frontière peut-être n'importe quoi: point, arête, surface
                   // on vérifie que ce ne sont pas des ref Indic  5 ou 6 ou plus ou 1 ou 2
                 #ifdef UTILISATION_MPI
                   if (ParaGlob::Monde()->rank() == 0)
                 #endif
                   { cout << "\n *** erreur la reference de zone de frontiere de contact n'est pas "
                          << " une reference acceptable ! "
                          << " seules les ref d'aretes ou de surface sont possibles " ;
                     ref.Affiche();
                     cout << "\n LesContacts::Init_contact(..." << endl;
                     tempsContact.Arret_du_comptage(); // fin cpu
                     Sortie(1);
                   };
                   break;
                 }; // fin du switch sur le type de frontière
               };
            }; //-- fin de la boucle sur zone de contact
         }; //-- fin de la boucle sur les maillages maîtres
        // petit message si nécessaire
      #ifdef UTILISATION_MPI
        if (ParaGlob::Monde()->rank() == 0)
      #endif
        if (niveau_commentaire_lescontacts >2 ) //&& (list_fronta.size() > 0))
         { for (int i=1;i<= nb_zone;i++) // boucle sur les références de zone_contact
            { cout << "\n  zone de contact: " << i << " => "
                   << zone_frontiere(i)
                   << " frontieres prises en compte pour le contact ";
              if (zone_frontiere(i) == 0)
                cout << "\n *** warning c'est un peu etrange qu'il y ait 0 frontiere, cela veut dire "
                     << " que cette zone ne sera pas utilisable !! ";
            };
         };
    
      }; //-- fin du else : cas d'une zone restreinte de contact
      
     // on définit et on ajoute les fronts des angles morts
     ElementAngleMort(lesMail);
     
     // il faut mettre à jour les mitoyens des Front: c-a-d il faut que les mitoyens
     // soient eux-même des fronts de t_listFront
     int nb_zone = MaX(1,nom_ref_zone_contact.size());
     for (int i=1;i<=nbmailMaitre;i++)
      { for (int j=1;j<=nb_zone;j++)
         { LaLIST_io <Front> & list_fronta = (t_listFront(i)(j)); // pour simplifier
           LaLIST <Front>::iterator iM,iMfin=list_fronta.end();
           for (iM = list_fronta.begin();iM != iMfin; iM++) // boucle sur les frontières enregistrées
             {Front & fronta = (*iM); // pour simplifier
              const Tableau <Front*>* ta = fronta.TabMitoyen(); // récup des mitoyens
              if (ta != NULL) // cas où il y a des éléments voisins !
                { const Tableau <Front*>& taa = *ta; // pour simplifier
                  int ta_taille = ta->Taille();
                  Tableau <Front*> inter(ta_taille);// un tableau inter de travail
                  for (int i=1; i <= ta_taille; i++)
                    // on récupère l'élément ad hoc
                    {Front* froon = Front_de_meme_origine(taa(i),j);
                     if (froon != NULL)
                       {inter(i)=froon;}
                     else // sinon c'est un pb pour la suite
                       {cout << "\n *** erreur dans la definition des mitoyens pour l'initialisation des frontieres de contact "
                             << " on n'a pas trouve dans la zone de contact une frontiere adequate : arret ";
                        Sortie(1);
                       };
                    };
                  // on peut maintenant remplacer le tableau de mitoyen
                  fronta.DefMitoyen(inter);
                };
             };
         };
      };

     // Pour diminuer le temps de recherche, et aussi les messages on va constituer une liste des éléments
     // qui contiennent les frontières
     liste_elemens_front.clear(); // init de la liste
 #ifdef UTILISATION_MPI
     int nb_total_front=0; // permet ensuite de dimensionner le tableau pointe_t_listFront
 #endif
     for (int i=1;i<=nbmailMaitre;i++)
      { for (int j=1;j<=nb_zone;j++)
         { LaLIST_io <Front> & list_fronta = (t_listFront(i)(j)); // pour simplifier
           LaLIST <Front>::iterator iM,iMfin=list_fronta.end();
           for (iM = list_fronta.begin();iM != iMfin; iM++) // boucle sur les frontières enregistrées
             {liste_elemens_front.push_back((*iM).PtEI());
         #ifdef UTILISATION_MPI
              nb_total_front++;
         #endif
             };
         };
       };
     // on ordonne la liste puis on supprime les doublons
     liste_elemens_front.sort();  // ordonne
     liste_elemens_front.unique(); // supprime les doublons
    
     // --- cas des contacts collants avec suppression des gaps ----
     // suppression du gap de contact pour les noeuds "collant avec suppression de gap"
     Suppression_gap_pour_noeud_collant();

   ////--- debug
   //{ for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++)
   //   { LaLIST <Front>::iterator    iM,iMfin=(*listFrontiere(jf)).end();
   //     for (iM = (*listFrontiere(jf)).begin();iM != iMfin; iM++) // boucle sur les fronts maitres
   //      { ElFrontiere* elemf = (*iM).Eleme(); // pour simplifier
   //        if (((*iM).Num_frontiere() == 1) && ((*iM).PtEI()->Num_elt()== 3130)
   //            && ((*iM).PtEI()->Num_maillage() == 4))
   //           { cout << "\n debug : frontiere 1 de l'element 3130";
   //           }
   //      }
   //   }
   //}
   ////-- fin debug
   
 #ifdef UTILISATION_MPI
     // on défini le tableau pointe_t_listFront et on définit le numéro associé unique dans les fronts
     pointe_t_listFront.Change_taille(nb_total_front);
     int inum = 1;
     for (int i=1;i<=nbmailMaitre;i++)
      { for (int j=1;j<=nb_zone;j++)
         { LaLIST_io <Front> & list_fronta = (t_listFront(i)(j)); // pour simplifier
           LaLIST_io <Front>::iterator il,ilfin = list_fronta.end();
           for (il = list_fronta.begin();il != ilfin; il++,inum++)
             {pointe_t_listFront(inum) = &(*il);
              (*il).ChangeNumUnique(inum);
             };
         };
       };
// //--- debug
// {cout << "\n debug : LesContacts::Init_contact ";
// for (int i=1;i<=nbmailMaitre;i++)
//  { for (int j=1;j<=nb_zone;j++)
//     { LaLIST_io <Front> & list_fronta = (t_listFront(i)(j)); // pour simplifier
//       LaLIST_io <Front>::iterator il,ilfin = list_fronta.end();
//       for (il = list_fronta.begin();il != ilfin; il++)
//         {if ((*il).NumUnique() == 0)
//            cout << "\n debug : LesContacts::Init_contact "
//                 << " ***** erreur numunique == 0 !!" ;
//          // maintenant on s'occupe des mitoyens
//          {Front & fronta = (*il); // pour simplifier
//           const Tableau <Front*>* ta = fronta.TabMitoyen(); // récup des mitoyens
//           if (ta != NULL) // cas où il y a des éléments voisins !
//             { const Tableau <Front*>& taa = *ta; // pour simplifier
//               int ta_taille = ta->Taille();
//               for (int i=1; i <= ta_taille; i++)
//                 {if (taa(i)->NumUnique() == 0)
//                  cout << "\n debug : LesContacts::Init_contact "
//                      << " ***** erreur dans  les mitoyens : numunique == 0 !!" ;
//                 };
//             };
//          };
//
//         };
//     };
//   };
// }
// //-- fin debug
 #endif


     tempsContact.Arret_du_comptage(); // fin cpu
   };

   
// verification qu'il n'y a pas de contact avant le premier increment de charge
void LesContacts::Verification()
{
  #ifdef UTILISATION_MPI
  // cas d'un  calcul //, seule le CPU 0 est concernée
  if (ParaGlob::Monde()->rank() != 0)
    return ;
  #endif
  // on va iterer sur les noeuds esclaves pour savoir s'ils sont internes
  // a un element  c-a-d a l'interieur d'un element qui contiend un element
  // frontiere 
  int nb_zone = MaX(1,nom_ref_zone_contact.size());
	 
  int niveau_commentaire_lescontacts = Permet_affichage();
  if (niveau_commentaire_lescontacts > 4)
      cout << "\n -- LesContacts::Verification: ";
  // mise à jour les boites d'encombrement des éléments frontière
   {LaLIST_io <Front>::iterator iM,iMfin;
    for (int i=1;i<=nbmailMaitre;i++)
     for (int j=1;j<= nb_zone;j++)
       { iMfin=(t_listFront(i)(j)).end();
//debug
//cout << "\n les elements frontières: " << t_listFront(jjf) << " ";
// fin debug		     
         for (iM = (t_listFront(i)(j)).begin() ; iM != iMfin; iM++)
           (*iM).Boite_encombrement_frontiere(TEMPS_t,0.); // au début pas de déplacement -> 0.
       };
    };
		 
		 
	 list  <Element *>::iterator ilfele, ilfelefin = liste_elemens_front.end();
  for (int intot = 1;intot<= nb_mail_Esclave;intot++)
   for (int j=1;j<= nb_zone;j++)
     { const Tableau <Noeud*>& tesc= tesctotal(intot)(j); // pour simplifier la notation
       const Tableau <int> tesN_col = tesN_collant(intot)(j); // pour simplifier
       int tesc_taille=tesc.Taille();
       for (int inesc = 1;inesc<= tesc_taille;inesc++)
        { Noeud* noee = tesc(inesc); // pour simplifier
		        const Coordonnee& pt_esc = noee->Coord1(); // position du noeud esclave à l'instant t
//debug
//cout << "\n pt_esc= " << pt_esc << " "<< endl ;
// fin debug	
         int num_mail_noe_esclave = noee->Num_Mail();
         // on parcours les elements maitres
		       for (ilfele = liste_elemens_front.begin(); ilfele != ilfelefin; ilfele++)
          { Element & elem = *(*ilfele); // l'element qui contiend la frontiere
			         // dans le cas où l'élément et le noeud appartienne au même maillage, on est
				        // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
				        // qui ne contiennent pas le noeud esclave
			         if (elem.Num_maillage() == num_mail_noe_esclave)
				         { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(noee->Num_noeud()); // pour simplifier
				           if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
					            break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
				         };
            // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément sauf cas particulier
            bool effectuer_verif = true; // init
            if (ParaGlob::Dimension() == 3)
             {if (Type_geom_generique(elem.Id_geometrie()) != VOLUME)
                effectuer_verif = false;
             };
            
            if ((elem.In_boite_emcombrement_elem(pt_esc)) && effectuer_verif)
            // on teste alors plus précisemment
            {//compteur++;
             int n_noee = tesc(inesc)->Num_noeud();
             *(gr_pour_noeud->ConteneurEntier()) = n_noee; // pour l'affichage
             *(gr_pour_elem->ConteneurEntier()) = 0; //pas d'élément ici
             if ((elem.Interne_t(pt_esc)==1) && (Permet_affichage(&li_pour_noeuds_element) >= 3))
              { cout << "\n attention, noeud esclave dans elem. "
                     << "avant incre. 1 charge";
//-- debug
     #ifdef MISE_AU_POINT
       cout << "\n LesContacts::Verification() ";
       elem.Interne_t(pt_esc);
     #endif
//-- fin debug
                if (Permet_affichage(&li_pour_noeuds_element) >  3)
                     cout << "\n LesContacts::Verification(..)";
                int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                cout << "\n -> noeud " << n_noee << " du maillage " << tesc(inesc)->Num_Mail()
                     << " dans l'element " <<  elem.Num_elt() << " du maillage " << num_mail_elem ;
                if (tesN_col(inesc)) cout << " (contact collant) ";
                if (Permet_affichage(&li_pour_noeuds_element) > 4)
                 {const DeuxCoordonnees& a = (*ilfele)->RecupBoite_encombre_element();
                  cout << "\n coordonnees noeud : " << tesc(inesc)->Coord0();
                  cout << "\n boite d'encombrement de l'element : "
                       << "\n premier : "<< a.Premier()
                       << "\n second  : "<< a.Second();
                 };
//elem.Interne_t(pt_esc); // debug
                //cout  << endl;
               // elem.Affiche();tesc(inesc)->Affiche();
//--- on laisse pour voir continuer                   Sortie(1);
					         }; 
					       };
			        }; // -- fin de la boucle sur ifele
		      }; // -- fin de la boucle sur inesc  
		   }; //-- fin de la boucle sur les zones   
//      cout << "\n compteur = " << compteur << endl;
//      Sortie(1); 
};


// definition des elements de contact eventuels
// dep_max : déplacement maxi des noeuds du maillage
// cette méthode est utilisée au début du calcul, ensuite c'est Nouveau()
// qui prend le relais
// ramène true s'il y a effectivement création d'élément de contact
// en parallèle seules les proc i>0 définissent des éléments de contact
// le proc 0 ne fait rien, il récupère le retour et fait le bilan
bool  LesContacts::DefElemCont(double dep_max)
  {
    tempsContact.Mise_en_route_du_comptage(); // def deb compt
    bool retour = false; // init par défaut
    int niveau_commentaire_lescontacts = Permet_affichage();
  #ifdef UTILISATION_MPI
    int proc_en_cours = ParaGlob::Monde()->rank();
  #endif

    if (niveau_commentaire_lescontacts > 4)
        {
         #ifdef UTILISATION_MPI
           cout << "\n proc " << proc_en_cours
                << " -- LesContacts::Def Elem Cont, initialement "<<listContact.size() << " elem contact ";
         #else
           cout << "\n -- LesContacts::Def Elem Cont, initialement "<<listContact.size() << " elem contact ";
         #endif
        };
    // on initialise les listes transitoires
    listContact_nouveau_tatdt.clear();
    listContact_efface_tatdt.clear();
    // on met à jour le déplacement maxi toléré pour la classe ElContact
    double coef_mult_dep_max = 2.; // comme un noeud peut se déplacer de dep_max et que l'on
	   double dep_max_pratique = coef_mult_dep_max * dep_max;
	      // peut avoir la cible "et" le noeud qui se déplace de dep_max, on doit considérer 2*dep_max
    // on met à jour le déplacement maxi pour la class 
  	 ElContact::Change_dep_max(dep_max_pratique);
    int nb_zone = MaX(1,nom_ref_zone_contact.size());
    double dist_max =  Dabs(ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete());

 #ifdef UTILISATION_MPI
    if (proc_en_cours != 0)  // seules les proc i>0 définissent des éléments de contact
     {
 #endif

    // on va iterer sur les noeuds esclaves pour savoir s'ils ont une trajectoire
    // qui cree un contact avec les elements maitres, ou l'inverse, c-a-d s'ils sont
    // dans de la matiere
    LaLIST_io <Front>::iterator iM,iMfin; // des itérator de travail

// la mise à jour des boites d'encombrement n'est pas nécessaire car elle est faite dans l'algo avant le contact
// *** si car ici on tient compte du déplacement et pas dans le prog principale
// *** à voir si on ne peut pas le faire dans le prog princ, mais il faut faire un cas mini
// car pour les points on se retrouve avec une boite de dim nulle !!

    // mise à jour les boites d'encombrement des éléments frontière

    {LaLIST_io <Front>::iterator iM,iMfin;
     for (int i=1;i<=nbmailMaitre;i++)
      for (int j=1;j<= nb_zone;j++)
        { iMfin=(t_listFront(i)(j)).end();
          for (iM = (t_listFront(i)(j)).begin() ; iM != iMfin; iM++)
              (*iM).Boite_encombrement_frontiere(TEMPS_t,dep_max_pratique); // au début pas de déplacement -> 0.
        };
    };

    LaLIST <ElContact>::iterator icont_inter; // sert pour la recherche de doublon 
//    list <TroisEntiers>::iterator inumtesN;    //            "     "       "
    for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
     for (int j_zone=1;j_zone<=nb_zone;j_zone++)
     {const Tableau <Noeud*>& tesc= tesctotal(intot)(j_zone); // pour simplifier la notation:
      const Tableau <int> tesN_col = tesN_collant(intot)(j_zone); // pour simplifier
      int tesc_taille=tesc.Taille();                   //  tab des noeuds esclaves à considérer
      for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
       {Noeud* noee = tesc(inesc); // pour simplifier
        int num_mail_noe_esclave = noee->Num_Mail();
        int n_noee = noee->Num_noeud();
         {int nb_contact=0; //au début pas de contact pour le noeud (pour gérer les doublons en contact)
          const Coordonnee pt_esc = noee->Coord2(); // position du noeud esclave
          for (int jlf=1;jlf<=nbmailMaitre;jlf++) // boucle sur les maillages maitres
          {LaLIST_io <Front>& t_listFront_jlf_j = t_listFront(jlf)(j_zone);
           iMfin= t_listFront_jlf_j.end();
           for (iM = t_listFront_jlf_j.begin() ; iM != iMfin; iM++)  // boucle sur les front
             {
              bool a_considerer = true; // init par défaut
           #ifdef UTILISATION_MPI
              // dans le cas // on ne continue que si la frontière est relative à un élément associé au cpu
              {Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
               // on ne continue que si l'élément est concerné
               if (!(ParaGlob::param->Element_concerner(elem.Num_maillage(),elem.Num_elt_const()) ))
                  a_considerer=false;
              };
           #endif
           #ifdef MISE_AU_POINT
              if (num_mail_noe_esclave > nb_mail_Esclave)
               { cout << "\n ***  erreur le noeud "<< n_noee
                      << " du maillage  " << num_mail_noe_esclave
                      << " ne fait pas partie d'un maillage declare comme esclave "
                      << " il y a sans doute une erreur dans la mise en donnees "
                      << " par exemple dans la definition des zones de contact ... "
                      << endl;
                 Sortie(1);
               };
           #endif
              std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >& tesN_encontact_ii = tesN_encontact(num_mail_noe_esclave);
              // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
              // car autrement on crée automatiquement une liste avec un élément vide
              std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >::iterator it_liste;
              if (tesN_encontact_ii.find(noee) != tesN_encontact_ii.end())
               {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[noee];
                LaLIST < LaLIST<ElContact>::iterator >::iterator pl,plfin=list_tesN.end();
                nb_contact = list_tesN.size();
                for (pl = list_tesN.begin();pl != plfin;pl++)
                  {ElContact& elc = (*(*pl));
                   if ( elc.Elfront()->MemeOrigine(*iM))
                     {a_considerer=false;break;}
                  };
               };
              
              // donc on ne continue que si la face n'est pas déjà en contact avec le noeud
              if (a_considerer)
               {// on regarde si le noeud esclave est dans la boite d'encombrement de l'élément frontière
                 Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
                 // dans le cas où l'élément et le noeud appartienne au même maillage, on est
                 // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
                 // qui ne contiennent pas le noeud esclave
                 if (elem.Num_maillage() == num_mail_noe_esclave)
                  { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(n_noee); // pour simplifier
                    if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
                      break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
                  };
                
    // ---- finalement on ne va pas considérer le point frontière comme particulier ---
    // du coup, il ne sera jamais pris en compte et on
    //             bool dans_la_boite=false; // init
    //             // on prend en compte le cas particulier de frontière point
    //             if ((*iM)->Eleme()->Type_geom_front() == POINT_G)
    //              // on utilise la boite d'encombrement de l'élément car pour l'instant
    //              // je ne vois pas de solution plus pertinente
    //              // bool In_boite_emcombrement_elem(const Coordonnee& M,double depass = 0.)
    //              { dans_la_boite = elem.In_boite_emcombrement_elem(pt_esc);}
    //             else // sinon c'est le cas normal, on test la boite de la frontière
    //              { dans_la_boite = (*iM)->In_boite_emcombrement_front(pt_esc);};
    //             if (dans_la_boite)
    
                 bool plus_en_avant = false; // init
                 if (tesN_col(inesc)) // si collant: on projete systématiquement avec de grandes bornes
                   { if ((*iM).In_boite_emcombrement_front(pt_esc,dist_max))
                        plus_en_avant = true;
                   }
                 else if ((*iM).In_boite_emcombrement_front(pt_esc)) // cas non collant
                   { plus_en_avant = true;};
                
                 if (plus_en_avant)
                  // on teste alors plus précisemment
                  {// constitution d'un element de contact intermediaire
                   ElContact elcont(&(*iM),tesc(inesc),fct_nD_contact,&(*iM),tesN_col(inesc));
                   elcont.Num_zone_contact()=j_zone; // affectation du numéro de zone
                   elcont.Change_lissage_normale(lissage_de_la_normale(j_zone)); // affectation du lissage
                 #ifdef UTILISATION_MPI
                   // on attribue au front de l'élément de contact, le numéro unique utilisable pour le tableau pointe_t_listFront
                   elcont.Elfront()->ChangeNumUnique((*iM).NumUnique());
                 #endif
                   // calcul du contact, et translation (éventuelle) du noeud sur la surface si le contact existe
                   bool init_inter = true; // on est en phase d'initialisation
//                   //--- debug
//                   cout << "\n LesContacts::DefElemCont *3* "<< flush;
//                   elcont.Affiche(1);
//                   //--- fin debug
                   bool ret = elcont.Contact(init_inter);
                   if (niveau_commentaire_lescontacts > 5)
                     { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                     #ifdef UTILISATION_MPI
                       cout << "\n proc " << proc_en_cours
                     #else
                       cout << "\n"
                     #endif
                            << " recherche du contact entre noeud " << elcont.Esclave()->Num_noeud() 
                            << " du maillage " << elcont.Esclave()->Num_Mail()
                            << " et frontiere " << (*iM).Num_frontiere()
                            << " de l'element " << elem.Num_elt() << " du maillage "
                            << num_mail_elem;
                       if (ret) cout << "\n --> contact trouve ";
                       else cout << "\n --> pas de contact ";
                       if ((niveau_commentaire_lescontacts > 6)
                           && ((*iM).In_boite_emcombrement_front(pt_esc))
                          )
                          {Noeud* noeud = tesc(inesc);
                           // --- sortie d'info pour vérifier l'appartenance  à la boite ou non
                           cout << ", coordonnee noeud esclave : " ; noeud->Coord2().Affiche();
                           cout << "\n boite d'encombrement de l'element qui contient la frontiere:\n mini -> ";
                           elem.RecupBoite_encombre_element().Premier().Affiche();
                           cout << " maxi -> ";
                           elem.RecupBoite_encombre_element().Second().Affiche();
                           cout << "\n boite d'encombrement de  la frontiere:\n mini -> ";
                           (*iM).Encom_mini_FR().Affiche();
                           cout << " maxi -> ";
                           (*iM).Encom_maxi_FR().Affiche();
                          };
                       cout <<   endl;
                     };
                   
                   if  (ret)
                     //sauvegarde éventuelle de l'element contact
                     {// on regarde s'il n'y a pas un autre élément de contact avec le même noeud
                      if (nb_contact == 0)
                       { // s'il existe déjà ce n'est pas normal
                         #ifdef MISE_AU_POINT
                         {if (Element_contact_deja_present(elcont) != NULL)
                            {
                           #ifdef UTILISATION_MPI
                             cout << "\n *** erreur: proc " << proc_en_cours;
                           #endif
                             cout << "\n*** Erreur : l'element de contact existe déjà, ce n'est pas normal "
                                 << (elcont).Esclave()->Num_noeud()
                                 << " du maillage " << (elcont).Esclave()->Num_Mail()
                                 << " la suite n'est pas possible "
                                 << " LesContacts::DefElemCont(.. \n";
                              tempsContact.Arret_du_comptage(); // fin cpu
                              Sortie(1);
                            };
                         }
                         #endif
                         // c'est le premier élément en contact, on l'enregistre
                         listContact.push_front(elcont);
                         retour = true;
                         listContact_nouveau_tatdt.push_front(listContact.begin()); // mémorisation
                         // et ajout dans la liste associé au noeud esclave
                         tesN_encontact_ii[noee].push_front(listContact.begin());
                         nb_contact++;
                         if (niveau_commentaire_lescontacts > 3)
                           { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                           #ifdef UTILISATION_MPI
                             cout << "\n proc " << proc_en_cours
                           #else
                             cout << "\n"
                           #endif
                                  << "contact entre noeud " ;
                             if (tesN_col(inesc)) cout << " collant ";
                             cout << elcont.Esclave()->Num_noeud()
                                  << " du maillage " << elcont.Esclave()->Num_Mail()
                                  << " et frontiere " << (*iM).Num_frontiere()
                                  << " de l'element " << elem.Num_elt() << " du maillage "
                                  << num_mail_elem << "(zone"<<j_zone<<")"<<  flush;
                             if (niveau_commentaire_lescontacts > 6)
                                {cout << "\n pt intersection: " << elcont.Point_intersection() ;
                                 elcont.Elfront()->Affiche();
                                 cout << flush;
                                };
                           };
                       }
                      else
                       { // on a déjà un élément en contact
                         // on peut alors utiliser une ref sur l'élément de la map, sans craindre d'en créer
                         // un nouveau
                         LaLIST < LaLIST<ElContact>::iterator >::iterator pl =
                                       tesN_encontact_ii[noee].begin(); // le pointeur du premier de la liste
                         ElContact& elc = (*(*pl));
                         // on va retenir l'élément dont le point de contact est le plus proche du point à t
                         //***: on retient ici le plus proche, mais dans nouveau on gardera tous les contacts
                         // ici il s'agit essentiellement de l'initialisation (à voir ensuite si c'est tenable !)
                         // --> permet aussi de coller sur un élément bien déterminé, s'il s'agit d'un collage
                         if ((elcont.Point_intersection()-pt_esc).Norme()
                             < (elc.Point_intersection()-pt_esc).Norme())
                          {// cas où le nouvel élément en contact est plus proche que celui enregistré
                           listContact_efface_tatdt.push_front(elc); // mémorise
                           
                           // il faut utiliser erase et non remove car il n'y a pas d'opérateur =
                           // pour les éléments de contact
                           listContact.erase(*pl); // on efface l'ancien
                           listContact_nouveau_tatdt.remove(*pl);
                           // il faut supprimer dans tesN_encontact
                           tesN_encontact_ii[noee].erase(pl);
                           // puis on met le nouveau s'il n'existe pas déjà
                           ElContact* test_existance= Element_contact_deja_present(elcont);
                           if (test_existance == NULL)
                            // s'il n'existe pas, on le rajoute
                            {listContact.push_front(elcont);
                             retour = true;
                             listContact_nouveau_tatdt.push_front(listContact.begin());
                             tesN_encontact_ii[noee].push_front(listContact.begin());
                             // on n'intervient pas sur tesN_encontact, car ça ne change pas
                             if (niveau_commentaire_lescontacts > 3)
                               { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                               #ifdef UTILISATION_MPI
                                 cout << "\n proc " << proc_en_cours
                               #else
                                 cout << "\n"
                               #endif
                                      << " --- changement d'element en contact ---";
                                 cout << "contact entre noeud " ;
                                 if (tesN_col(inesc)) cout << " collant ";
                                 cout  << elcont.Esclave()->Num_noeud()
                                      << " du maillage " << elcont.Esclave()->Num_Mail()
                                      << " et frontiere " << (*iM).Num_frontiere()
                                      << " de l'element " << elem.Num_elt() << " du maillage "
                                      << num_mail_elem << "(zone"<<j_zone<<")"<<   flush;
                               };
                             }
                           else if (!test_existance->Actif())
                            // s'il existe et est inactif on le rend actif (pour remplacer celui qui devrait être créé)
                            {test_existance->Met_actif();
                            };
                             
                          };
                         // sinon le nouvel élément est plus loin que l'ancien, on en tient pas compte
                       };

                     };
                   // sinon il n'y a pas de contact
                  }; //-- fin du test sur la boite_encombrement
                }; // -- fin du test :  if (a_considerer)
            }; // -- fin de la boucle sur iM
          }; //-- fin de la boucle sur jlf
         }; //-- fin du test  if (!tesN_encontact(intot)(n_noee)) 
       }; //-- fin de la boucle sur inesc
      }; //-- fin de la boucle sur les zones
      
 #ifdef UTILISATION_MPI
      }; // fin du cas des proc i > 0
 #endif

    // retour
 #ifdef UTILISATION_MPI
  if (proc_en_cours != 0)
   {
    if (niveau_commentaire_lescontacts > 4) //  ==> LesContacts::
 #else
    if (niveau_commentaire_lescontacts > 2) //  ==> LesContacts::
 #endif
      {
      #ifdef UTILISATION_MPI
        cout << "\n proc " << proc_en_cours
      #else
        cout << "\n"
      #endif
             << "            apres Def Elem Cont: "<< listContact.size() << " elem contact ";
        if ( listContact_nouveau_tatdt.size())
             cout <<", "<< listContact_nouveau_tatdt.size() << " nouveau(x) ";
        if (listContact_efface_tatdt.size())
             cout <<", "<<listContact_efface_tatdt.size() << " effacement(s) ";
        cout << flush;
      };
      
 #ifdef UTILISATION_MPI
   };
    if (proc_en_cours != 0) // on transmet à proc 0
      {temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
       // pour cela on va utiliser un conteneur intermédiaire
       QuatreEntiers inter_entiers(retour,listContact.size(),listContact_nouveau_tatdt.size(),listContact_efface_tatdt.size());
       // on transmet les infos au proc 0
       mpi::request reqs1 = ParaGlob::Monde()->isend(0, 61, inter_entiers);
       // on attend pas
       temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
      }
    else // cas du cpu 0
      {// l'objectif ici est de récupérer  les infos
       tempsContact.Arret_du_comptage(); // fin cpu
       int nb_contact=0;int nb_new_contact = 0;int nb_efface_contact = 0; // que l'on va cumuler
       
       int nb_proc_terminer = 0; // permettra de terminer
       while (nb_proc_terminer < (ParaGlob::Monde()->size()-1))
        { // on récupère un résultat de cpu i
          temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
          QuatreEntiers inter_entiers;
          mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 61, inter_entiers );
          reqs1.wait(); // on attend que le conteneur soit rempli
          // on cumule
          nb_contact  += inter_entiers.deux;
          nb_new_contact += inter_entiers.trois;
          nb_efface_contact += inter_entiers.quatre;

          if (inter_entiers.un) // si un seul des retour s est bon on passe à true
             retour = true;
          nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
        };

      if (niveau_commentaire_lescontacts > 2) //  ==> LesContacts::
         {cout << "\n            apres Def Elem Cont: "<< nb_contact << " elem contact ";
          if ( nb_new_contact)
               cout <<", "<< nb_new_contact << " nouveau(x) ";
          if (nb_efface_contact)
               cout <<", "<<nb_efface_contact << " effacement(s) ";
          cout << flush;
         };

      };
    // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
    broadcast(*ParaGlob::Monde(), retour, 0);
 #endif
    tempsContact.Arret_du_comptage(); // fin cpu
   
    return retour;
  };
      
// reexamen du contact pour voir s'il n'y a pas de nouveau element de contact
// ramene false s'il n'y a pas de nouveau element de contact
// true sinon
// dep_max : déplacement maxi des noeuds du maillage
bool LesContacts::Nouveau(double dep_max)
  {
    tempsContact.Mise_en_route_du_comptage(); // def deb compt
    int niveau_commentaire_lescontacts = Permet_affichage();
////--- debug
//cout << "\n debug LesContacts::Nouveau "<< " niveau_commentaire_lescontacts = "<< niveau_commentaire_lescontacts<< flush;
////--- fin debug
//    list <TypeQuelconque>  li_pour_noeuds; // pour une sortie spécifique noeud
//    Grandeur_scalaire_entier grand_courant_entier(0); // par défaut pour la création des conteneurs quelconques
//    li_pour_noeuds.push_front(TypeQuelconque(NUM_NOEUD,X1,grand_courant_entier));
//    Grandeur_scalaire_entier& gr_pour_noeud
//        = *((Grandeur_scalaire_entier*) (*li_pour_noeuds.begin()).Grandeur_pointee());
//    list <TypeQuelconque>  li_pour_elcont; // pour une sortie spécifique élément finis
//    li_pour_elcont.push_front(TypeQuelconque(NUM_ELEMENT,EPS11,grand_courant_entier));

  #ifdef UTILISATION_MPI
    int proc_en_cours = ParaGlob::Monde()->rank();
  #endif

    int nb_zone = MaX(1,nom_ref_zone_contact.size());
    bool retour = false; // init du retour

    // on sauvegarde la liste au départ
    int taille_list_contact_nouveau_au_debut = listContact_nouveau_tatdt.size();

    if (niveau_commentaire_lescontacts > 3)
    #ifdef UTILISATION_MPI
      cout << "\n proc " << proc_en_cours
    #else
      cout << "\n"
    #endif
           << " -- LesContacts::Nouveau:   temps= " << ParaGlob::Variables_de_temps().TempsCourant();
 #ifdef UTILISATION_MPI
 if (proc_en_cours != 0)  // seules les proc i>0 définissent des éléments de contact
   {
 #endif

    // on montre les noeuds actuellement en contact
    if (Permet_affichage() > 4)
     {
    #ifdef UTILISATION_MPI
      cout << "\n proc " << proc_en_cours
    #else
      cout << "\n"
    #endif
           << "   >> bilan des noeud(s) actuellement en contact: ";
      int nb_noe_en_contact = 0;
      for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
       for (int j=1;j<= nb_zone;j++)
       {const Tableau <Noeud*>& tesc= tesctotal(intot)(j); // pout simplifier la notation
        const Tableau <int> tesN_col = tesN_collant(intot)(j); // pour simplifier
        int tesc_taille=tesc.Taille();
        for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
         {Noeud* no = tesc(inesc);
          int n_noee = no->Num_noeud();
          *(gr_pour_noeud->ConteneurEntier()) = n_noee; // pour l'affichage
          *(gr_pour_elem->ConteneurEntier()) = 0; //pas d'élément ici
          if (Permet_affichage(&li_pour_noeuds_element) > 5)
             {
               int num_mail_noe_esclave = no->Num_Mail();
               // if (no->Num_noeud()==495)
               cout << "\n     noeud  " << no->Num_noeud() << " du maillage " << no->Num_Mail();
               cout << " coord2= "; no->Coord2().Affiche_1(cout);
//               #ifdef MISE_AU_POINT
//                 if (tesN_encontact(num_mail_noe_esclave).find(no)
//                       == tesN_encontact(num_mail_noe_esclave).end() )
//                  { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
//                         << n_noee << " du maillage " << num_mail_noe_esclave
//                         << " la suite n'est pas possible "
//                         << " LesContacts::Nouveau(.. \n";
//                    tempsContact.Arret_du_comptage(); // fin cpu
//                    Sortie(1);
//                  };
//               #endif
              std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >& tesN_encontact_ii = tesN_encontact(num_mail_noe_esclave);
              // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
              // car autrement on crée automatiquement une liste avec un élément vide
              std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >::iterator it_liste;
              if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
               {//LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[no];
//                LaLIST < LaLIST<ElContact>::iterator >::iterator pl,plfin=list_tesN.end();
                cout << "\n       --> noeud actuellement en contact ";
                nb_noe_en_contact++;
                if (tesN_collant(num_mail_noe_esclave)(j)(inesc)) cout << " collant ";
               }
               else {cout << "\n       --> noeud actuellement pas en contact ";};
               cout << flush;
            };
        };
      };
      #ifdef UTILISATION_MPI
        cout << "\n proc " << proc_en_cours
      #else
        cout << "\n"
      #endif
             << "   ->> bilan : " << nb_noe_en_contact << " noeud(s) actuellement en contact: ";

     };
    if (niveau_commentaire_lescontacts > 4)
        // on va lister les éléments de contact
     {
       #ifdef UTILISATION_MPI
         cout << "\n proc " << proc_en_cours
       #else
         cout << "\n"
       #endif
              << "    >> liste des Elcontact au debut de LesContacts::Nouveau: (fct du niveau de commentaire des elcontact): ";
         LaLIST<ElContact>::iterator ipp,ippfin=listContact.end();
         for (ipp=listContact.begin();ipp != ippfin; ipp++)
           {(*ipp).Affiche(2);};
         cout << "    fin liste ";
       #ifdef UTILISATION_MPI
         cout << "\n proc " << proc_en_cours
       #else
         cout << "\n"
       #endif
              << "   ->> bilan : " << listContact.size() << " element(s) de contact: ";
     };

    // on met à jour les boites des éléments qui contiennent les frontières
    // ?? on pourrait peut-être restreindre aux seuls éléments de frontières du cpu i , à voir où est utilisée la méthode ??
    Mise_a_jour_boite_encombrement_element_contenant_front();
    // on met à jour le déplacement maxi toléré pour la classe ElContact
    double coef_mult_dep_max = 3.; // comme un noeud peut se déplacer de dep_max et que l'on
    double dep_max_pratique = coef_mult_dep_max * dep_max;
	      // peut avoir la cible "et" le noeud qui se déplace de dep_max, on doit considérer 2*dep_max
			 // pour être sûr, on considère 3 fois
    ElContact::Change_dep_max(dep_max_pratique);
    // --- 1) on va tout d'abord parcourir les éléments inactifs et regarder s'ils sont en contact
	   //  si oui on les valide, sinon on les supprimes. Il faut le faire avant de prospecter car
	   // ces éléments inactifs ne vont pas être pris en compte car tesN_encontact(num_mail_noe_esclave)(inesc) = 0
	   // mais ils pourraient redevenir actifs, dans ce cas on aurait un noeud avec deux contacts
    // dans le cas //, on considère que les contacts déjà calculés sont a considérer avec le cpu en cours
    // car les tests d'appartenance on déjà été effectué au moment de la création
	   { // ++ encapsulage 
      LaLIST <ElContact>::iterator iE ;
	     // on met .end(), car cette borne peut changer au gré des suppression
      for (iE = listContact.begin(); iE != listContact.end(); iE++)
	       if (!((*iE).Actif()) // on intervient  si le contact est déclaré inactif
            && !((*iE).Collant())   // et si ce n'est pas collant: si collant, on ne change rien
           )
		        { LaLIST <ElContact>::iterator iiE = iE;
		          if ((*iE).Contact())
			           { // on valide si le contact est ok
                (*iE).Met_actif();
                *(gr_pour_noeud->ConteneurEntier()) = (*iE).Esclave()->Num_noeud();
                *(gr_pour_elem->ConteneurEntier()) = (*iE).Elfront()->PtEI()->Num_elt();
                if (Permet_affichage(&li_pour_noeuds_element) > 3)
                 { cout << "\n    reactivation (dans LesContacts::Nouveau) contact: ";
                   (*iiE).Affiche(1); cout << endl;
                 };
			           }
		          else
			           { // sinon on supprime car il n'y a pas de contact
		              iE--; // pointe sur le precedent element
                Noeud* noe_esclave = (*iiE).Esclave();
                int num_mail_esclave = noe_esclave->Num_Mail();
                int num_noeud = noe_esclave->Num_noeud();
                *(gr_pour_noeud->ConteneurEntier()) = num_noeud;
                *(gr_pour_elem->ConteneurEntier()) = (*iE).Elfront()->PtEI()->Num_elt();
                if (Permet_affichage(&li_pour_noeuds_element) > 3)
                 { cout << "\n    effacement contact (dans LesContacts::Nouveau): ";
                   (*iiE).Affiche(1);cout << endl;
                 };
                listContact_efface_tatdt.push_front(*iiE); // mémorise
                #ifdef MISE_AU_POINT
                  if (tesN_encontact(num_mail_esclave).find(noe_esclave)
                        == tesN_encontact(num_mail_esclave).end() )
                   { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
                          << num_noeud << " du maillage " << num_mail_esclave
                          << " la suite n'est pas possible " << " LesContacts::Nouveau(.. \n";
                     tempsContact.Arret_du_comptage(); // fin cpu
                     Sortie(1);
                   };
                #endif
                LaLIST < LaLIST<ElContact>::iterator >  & list_tesN
                       = tesN_encontact(num_mail_esclave)[noe_esclave];
                list_tesN.remove(iiE);
                listContact.erase(iiE); // efface l'element
              };
          };
	   }; // ++ fin encapsulage
	   // --fin 1)
	 
    // on va iterer sur les noeuds esclaves pour savoir s'ils ont une trajectoire
    // qui cree un contact avec les elements maitres, ou l'inverse, c-a-d s'ils sont
    // dans de la matiere
    retour = false; // init du retour
    LaLIST_io <Front>::iterator iM,iMfin;
    LaLIST <ElContact>::iterator icont_inter; // sert pour la recherche de doublon             
    list <TroisEntiers>::iterator inumtesN;    //            "     "       "
    // tout d'abord on met à jour les boites d'encombrement des éléments frontière
    for (int jjf=1;jjf<=nbmailMaitre;jjf++)
     for (int j=1;j<= nb_zone;j++)
      { iMfin=(t_listFront(jjf)(j)).end();
        for (iM = (t_listFront(jjf)(j)).begin() ; iM != iMfin; iM++)
           (*iM).Boite_encombrement_frontiere(TEMPS_tdt,dep_max);
      };
    // parcours des noeuds esclaves
    for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
    {for (int j_zone=1;j_zone<= nb_zone;j_zone++)
     {const Tableau <Noeud*>& tesc= tesctotal(intot)(j_zone); // pout simplifier la notation
      const Tableau <int> tesN_col = tesN_collant(intot)(j_zone); // pour simplifier
      int tesc_taille=tesc.Taille();
      for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
       // si le noeud est collant on ne fait rien
       {if (!tesN_col(inesc))
       
       {Noeud* no = tesc(inesc);
        int n_noee = no->Num_noeud();
        int num_mail_noe_esclave = no->Num_Mail();
/* /        #ifdef MISE_AU_POINT
//          if (tesN_encontact(num_mail_noe_esclave).find(no)
//                == tesN_encontact(num_mail_noe_esclave).end() )
//           { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
//                  << n_noee << " du maillage " << num_mail_noe_esclave
//                  << " la suite n'est pas possible "
//                  << " LesContacts::Nouveau(.. \n";
//             tempsContact.Arret_du_comptage(); // fin cpu
//             Sortie(1);
//           };
//        #endif */
        std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >& tesN_encontact_ii
                      =  tesN_encontact(num_mail_noe_esclave);
        // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
        // car autrement on crée automatiquement une liste avec un élément vide
        std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >::iterator it_liste;
        int nb_contact=0;
        if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
         {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[no];
          nb_contact = list_tesN.size();
         };
         
        *(gr_pour_noeud->ConteneurEntier()) = n_noee;
        *(gr_pour_elem->ConteneurEntier()) = 0; // pas de numéro d'élément à prendre en compte pour la visu
        if (Permet_affichage(&li_pour_noeuds_element) > 6)
          {
          #ifdef UTILISATION_MPI
            cout << "\n     proc " << proc_en_cours
          #else
            cout << "\n    "
          #endif
                 << " (re) examen eventuel : contact du noeud  " << n_noee << " du maillage " << num_mail_noe_esclave;
            cout << " coord2= "; no->Coord2().Affiche_1(cout);
            if (Permet_affichage(&li_pour_noeuds_element) > 7)
             {cout << " num_mail_dans_contact = " << num_mail_noe_esclave <<" inesc(num N local)= " << inesc
                 << "\n      tesN_encontact= " << nb_contact
                 << " contacts enregistres";
             };
            // on dit si un des contacts est actif
            int actif = 0;
            if (nb_contact)
             {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[no];
              LaLIST < LaLIST<ElContact>::iterator >::iterator il, ilfin = list_tesN.end();
              for (il = list_tesN.begin();il != ilfin; il++)
                if ( (*(*il)).Actif() )
                  actif++;
              if (actif)
                    {cout << "\n      noeud actuellement en contact dans " << actif << " element(s) ";
                     if (tesN_collant(num_mail_noe_esclave)(j_zone)(inesc)) cout << " collant ";
                    }
              else cout << "\n     noeud actuellement pas en contact ";
              int icont = 1;
              for (il = list_tesN.begin();il != ilfin; il++,icont++)
               {Front* elfront = (*(*il)).Elfront();
                Element * elem = elfront->PtEI(); // l'element qui contiend la frontiere
                cout  << "\n     elem_contact: "<<icont<<" avec frontiere: " << elfront->Num_frontiere()
                      << " de l'element " << elem->Geometrie() << " : " << elfront->PtEI()->Num_elt()
                      << ", type: " << Nom_type_geom(elfront->Eleme_const()->Type_geom_front())
                      << " du maillage :" << elfront->PtEI()->Num_maillage();
               };
             };
// il y a un pb, car un noeud pourrait-être collant pour une zone et non collant pour une autre
// ce n'est peut-être pas un pb, mais il faudra peut-être avoir le niveau de zone en plus dans tesN_encontact ??
//            cout << endl;
          };
 	      // on ne continue que si le noeud n'est pas entièrement bloqué
        // si c'est le cas .... à finir !
        {
          Coordonnee pt_esc = no->Coord2(); // position du noeud esclave
          // maintenant on regarde les frontieres maitres
          int num_frontiere=1; // pour le debug
          for (int jlf=1;jlf<=nbmailMaitre;jlf++)  // boucle sur les maillages maîtres
           {LaLIST_io <Front>& t_listFront_jlf_j = t_listFront(jlf)(j_zone);
            iMfin= t_listFront_jlf_j.end();
            for (iM = t_listFront_jlf_j.begin() ; iM != iMfin; iM++,num_frontiere++)  // boucle sur les front maitres
              // on parcours les elements maitres de la zone
              // si le noeud esclave est déjà en contact avec la frontière ce n'est pas la peine de tester
             {// donc on passe en revue les éléments en contact
              // si calcul // et élément déjà en contact c'est aussi vrai
              bool a_considerer = true; // init par défaut
              if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
               {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[no];
                LaLIST < LaLIST<ElContact>::iterator >::iterator pl,plfin=list_tesN.end();
                for (pl = list_tesN.begin();pl != plfin;pl++)
                  {ElContact& elc = (*(*pl));
                   Front& elfront = (*iM);
                   Front* eltest = elc.Elfront();
                   if (eltest->MemeOrigine(elfront) )
                    {a_considerer=false;
                     if (elc.Permet_affichage() > 6)
                      {cout << "\n     noeud esclave deja en contact "; elc.Affiche(1);
                      };
                    break;}
                  };
               };
           #ifdef UTILISATION_MPI
              // dans le cas // on ne continue que si la frontière est relative à un élément associé au cpu
              {Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
               // on ne continue que si l'élément est concerné
               if (!(ParaGlob::param->Element_concerner(elem.Num_maillage(),elem.Num_elt_const()) ))
                  a_considerer=false;
              };
           #endif
              // donc on ne continue que si la face n'est pas déjà en contact avec le noeud
              // et dans le cas // que c'est ok
              if (a_considerer)
               {// on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
                // qui contient l'élément frontière (car l'élément frontière à une épaisseur nulle!)
                Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
                Front& elfront = (*iM);
                
                *(gr_pour_noeud->ConteneurEntier()) = no->Num_noeud();
                *(gr_pour_elem->ConteneurEntier()) = elem.Num_elt();
                if (Permet_affichage(&li_pour_noeuds_element) > 7)
                  {// --- sortie d'info pour vérifier l'appartenance  à la boite ou non
                    #ifdef UTILISATION_MPI
                      cout << "\n proc " << proc_en_cours
                    #else
                      cout << "\n"
                    #endif
                           << " rappel: coordonnee noeud esclave : " ; no->Coord2().Affiche_1(cout);
                      cout << "\n boite d'encombrement de l'element maitre qui contient la frontiere:\n mini -> ";
                      elem.RecupBoite_encombre_element().Premier().Affiche();
                      cout << " maxi -> ";
                      elem.RecupBoite_encombre_element().Second().Affiche();
                  };

                // dans le cas où l'élément et le noeud appartienne au même maillage, on est
                // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
                // qui ne contiennent pas le noeud esclave

                if (elem.Num_maillage() == num_mail_noe_esclave)
                 { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(n_noee); // pour simplifier
                   if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
                     break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
                 };
       
                if (Permet_affichage(&li_pour_noeuds_element) > 6)
                  {
                   #ifdef UTILISATION_MPI
                     cout << "\n     proc " << proc_en_cours
                   #else
                     cout << "\n    "
                   #endif
                          << " frontiere: " << elfront.Num_frontiere() << " (nb loc: "<<num_frontiere<<") "
                          << ", type: " << Nom_type_geom(elfront.Eleme_const()->Type_geom_front())
                          << " de l'element " << elem.Geometrie() << " : "
                          << elfront.PtEI()->Num_elt()
                          << " du maillage :"
                          << elfront.PtEI()->Num_maillage() ;
                  };

                if (elem.In_boite_emcombrement_elem(pt_esc,dep_max_pratique))
                  // on teste alors plus précisemment
                  // on regarde si cela pourrait conduire à un élément de contact identique
                  // à un élément que l'on vient juste d'effacer, si oui, on ne crée pas d'élément et
                  // on attend un prochain incrément, si effectivement l'élément doit se créer, il sera alors créé
   // *** non, ça pose pb, on commente pour l'instant
                 {//LaLIST <ElContact>::iterator ila,ilafin=listContact_efface_tatdt.end();
                  bool vraiment_nouveau_element=true; // par défaut
/* //                  for (ila = listContact_efface_tatdt.begin();ila != ilafin;ila++)
//                   { if (((*ila).Esclave()->Num_noeud() == n_noee)
//                         && ((*((*ila).Elfront()->Eleme())) == (*((*iM).Eleme())))
//                         && ((*ila).Esclave()->Num_Mail() == num_mail_noe_esclave))
//                       { vraiment_nouveau_element = false;
//                         if ((*ila).Permet_affichage() > 5)
//                           {cout << "\n element de contact venant juste d'etre supprime, on arrete la creation ";
//                            (*ila).Affiche(1);
//                           };
//                         break;};
//                   };
*/
                  *(gr_pour_noeud->ConteneurEntier()) = n_noee;
                  *(gr_pour_elem->ConteneurEntier()) = 0; // pas de filtre sur les nb elem
                  if (Permet_affichage(&li_pour_noeuds_element) > 7)
                    {cout << "\n    liste des contacts sur le noeud " << n_noee
                          << " qui est prevu en effacement sur l'increment " ;
                     LaLIST <ElContact>::iterator ila,ilafin=listContact_efface_tatdt.end();
                     for (ila = listContact_efface_tatdt.begin();ila != ilafin;ila++)
                        { cout << "\n     " << n_noee << " " << (*ila).Esclave()->Num_noeud()
                               << " " ;
                          (*ila).Elfront()->Affiche();
                          (*iM).Affiche();
                          cout << "\n     ((*ila).Esclave()->Num_noeud() == noee->Num_noeud()) "
                               << ((*ila).Esclave()->Num_noeud() == n_noee);
                          cout << "\n     ((*((*ila).Elfront()->Eleme())) == (*((*iM)->Eleme()))) "
                               << ((*((*ila).Elfront()->Eleme())) == (*((*iM).Eleme())));
                          cout << "\n     ((*ila).Esclave()->Num_Mail() == noee->Num_Mail()) "
                               << ((*ila).Esclave()->Num_Mail() == n_noee);
                          cout << "\n     vraiment_nouveau_element= " << vraiment_nouveau_element << endl;
                        };
                    };
                  // on ne continue que si c'est un vrai nouvel élément
                  if (vraiment_nouveau_element)
                    { // on passe en revue les frontières de contact déjà existantes associées
                      // et s'il y a déjà un élément qui correspond, on arête la création
                      bool creation = true; // init

                      if (nb_contact)
                       {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[no];
                        LaLIST < LaLIST<ElContact>::iterator >::iterator il, ilfin = list_tesN.end();
                        for (il = list_tesN.begin();il != ilfin; il++)
                         { ElContact& con = (*(*il));
                           if (con.Elfront()->MemeOrigine(elfront))
                             {creation = false;
                              if (con.Permet_affichage() > 5)
                               {
                               #ifdef UTILISATION_MPI
                                 cout << "\n     proc " << proc_en_cours
                               #else
                                 cout << "\n    "
                               #endif
                                      << " frontiere en contact deja existante , on arrete la creation ";
                                 elfront.Affiche(1);
                               };
                             }
                         };
                       };
                      // on ne continue que s'il n'existe pas d'élément de contact du même type
                      if (creation)
                        { ElContact elcont(&(*iM),tesc(inesc),fct_nD_contact,&(*iM));
                          elcont.Num_zone_contact()=j_zone; // affectation du numéro de zone
                          elcont.Change_lissage_normale(lissage_de_la_normale(j_zone)); // affectation du lissage
                        #ifdef UTILISATION_MPI
                          // on attribue au front de l'élément de contact, le numéro unique utilisable pour le tableau pointe_t_listFront
                          elcont.Elfront()->ChangeNumUnique((*iM).NumUnique());
                        #endif

                          // vérification que l'on a bien les frontières bien connectées
                          if ((niveau_commentaire_lescontacts > 5)
                              || (elcont.Permet_affichage() > 5))
                            { Front* elfront = elcont.Elfront();
                            #ifdef UTILISATION_MPI
                              cout << "\n     proc " << proc_en_cours
                            #else
                              cout << "\n    "
                            #endif
                                   << "     test nouveau contact: examen plus precis:  frontiere: " << elfront->Num_frontiere()
                                   << ", type: " << Nom_type_geom(elfront->Eleme_const()->Type_geom_front())
                                   << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
                                   << elfront->PtEI()->Num_maillage() ;
                              *(gr_pour_elem->ConteneurEntier()) = elfront->PtEI()->Num_elt();
                              if (Permet_affichage(&li_pour_noeuds_element) > 7)
                                 elcont.Affiche();
                            };
                
                          // calcul du contact, et translation éventuelle du noeud sur la surface
                          // si le contact existe, ceci en fonction de la méthode de contact
                          bool ret = elcont.Contact();
                          if (elcont.Permet_affichage() > 5)
                           {cout << "\n     retour de Contact: ret= " << ret;
                           }
                          if  (ret)
                           {//sauvegarde éventuelle de l'element contact
                            ElContact* test_existance= Element_contact_deja_present(elcont);
                            if (test_existance == NULL)
                             { listContact.push_front(elcont);
                               //numtesN.push_front(TroisEntiers(num_mail_noe_esclave,j,n_noee));
                               tesN_encontact_ii[no].push_front(listContact.begin());
                               listContact_nouveau_tatdt.push_front(listContact.begin());
                                // à ce stade le nouveau contact est actif
                               retour=true; // on valide le retour
                               if ((niveau_commentaire_lescontacts > 3)
                                   || (elcont.Permet_affichage() > 3))
                                 {
                                 #ifdef UTILISATION_MPI
                                   cout << "\n     proc " << proc_en_cours
                                 #else
                                   cout << "\n    "
                                 #endif
                                        << " newcontact: " ;
                                   if (tesN_col(inesc)) cout << " collant ";
                                   elcont.Affiche(1);
                                 };
                             }
                            else if (!test_existance->Actif())
                             // s'il existe et est inactif on le rend actif (pour remplacer celui qui devrait être créé)
                             {test_existance->Met_actif();
                              if ((niveau_commentaire_lescontacts > 5)
                                 || (elcont.Permet_affichage() > 5))
                                 {cout << " remis en actif:  ";
                                  elcont.Affiche(2);
                                 };
                             }
                            else
                             { if ((niveau_commentaire_lescontacts > 5)
                                   || (elcont.Permet_affichage() > 5))
                                  cout << "     --> contact deja enregistre " ;
                             } ;
                           }
                          else
                           { if ((niveau_commentaire_lescontacts > 5)
                                || (elcont.Permet_affichage() > 5))
                                cout << "     --> pas de contact " ;
                           } ;
             
      //                   listContact.push_back(elcont);numtesN.push_back(DeuxEntiers(intot,inesc));
      //                     if (niveau_commentaire_lescontacts >= 6)
      //                       { Enum_type_geom type_front; Element & elem = *elcont.Elfront()->PtEI();
      //                         int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
      //                         cout << "\nnewcontact entre noeud " << elcont.Esclave()->Num_noeud()
      //                              << " du maillage " << elcont.Esclave()->Num_Mail()
      //                              << " et frontiere " << (*iM)->Num_frontiere()
      //                              << " de l'element " << elem.Num_elt() << " du maillage "
      //                              << num_mail_elem <<   flush;
      //                         }
      //                     retour = true;
      //                   break; // on arrête la boucle sur les fronts car on a trouvé un contact

                         }; // fin du test if creation
                          // sinon il n'y a pas de contact
                      } // -- fin du test sur examen if (vraiment_nouveau_element)
                 }; //-- fin du test sur la boite_encombrement
                }; // -- fin du test :  if (a_considerer)
			          }; // -- boucle sur iM
			        }; // -- boucle sur jlf
        }; // -- fin du test tesN_encontact(intot)(inesc)
        } //-- fin du test non collant: if (!tesN_col(inesc))
       };// -- boucle sur inesc
     }// -- fin de la boucle sur les zones for (int j=1;j<= nb_zone;j++)
    };// -- boucle sur intot

 #ifdef UTILISATION_MPI
   // affichage pour les proc != 0
    if (niveau_commentaire_lescontacts > 4)
 #else
    if (niveau_commentaire_lescontacts > 3) //  ==> LesContacts::
 #endif
      {
      #ifdef UTILISATION_MPI
        cout << "\n    proc " << proc_en_cours
      #else
        cout << "\n   "
      #endif
             << " en fin de  LesContacts::Nouveau: bilan: "<< listContact.size() << " elem(s) contact ";
        if ( listContact_nouveau_tatdt.size())
             cout <<", "<< (listContact_nouveau_tatdt.size()-taille_list_contact_nouveau_au_debut)
                  << " nouveau(x) ";
        if (listContact_efface_tatdt.size())
             cout <<", "<<listContact_efface_tatdt.size() << " effactement(s) ";
      };
    if (niveau_commentaire_lescontacts > 4)
          // on va lister les éléments de contact
      {
      #ifdef UTILISATION_MPI
        cout << "\n proc " << proc_en_cours
      #else
        cout << "\n"
      #endif
             << " liste des Elcontact a la fin de LesContacts::Nouveau: (fct du niveau de commentaire des elcontact): ";
        LaLIST<ElContact>::iterator ipp,ippfin=listContact.end();
        for (ipp=listContact.begin();ipp != ippfin; ipp++)
          {(*ipp).Affiche(2);};
        cout << " fin liste ";
      };
    if (niveau_commentaire_lescontacts > 3)
      {
      #ifdef UTILISATION_MPI
        cout << "\n    proc " << proc_en_cours
      #else
        cout << "\n    "
      #endif
             << " <== fin LesContacts::Nouveau " ;
      };
 #ifdef UTILISATION_MPI
   }; // fin de la recherche de nouveaux contact pour proc != 0
      
 #endif

 #ifdef UTILISATION_MPI
    if (proc_en_cours != 0) // on transmet à proc 0
      {temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
      
       // pour cela on va utiliser un conteneur intermédiaire
       QuatreEntiers inter_entiers(retour,listContact.size(),listContact_nouveau_tatdt.size(),listContact_efface_tatdt.size());
       // on transmet les infos au proc 0
       mpi::request reqs1 = ParaGlob::Monde()->isend(0, 62, inter_entiers);
       // on attend pas
       temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
      }
    else // cas du cpu 0
      {// l'objectif ici est de récupérer  les infos
       tempsContact.Arret_du_comptage(); // fin cpu
       int nb_contact=0;int nb_new_contact = 0;int nb_efface_contact = 0; // que l'on va cumuler

       int nb_proc_terminer = 0; // permettra de terminer
       while (nb_proc_terminer < (ParaGlob::Monde()->size()-1))
        { // on récupère un résultat de cpu i
          temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
          QuatreEntiers inter_entiers;
          mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 62, inter_entiers );
          reqs1.wait(); // on attend que le conteneur soit rempli
          // on cumule
          nb_contact  += inter_entiers.deux;
          nb_new_contact += inter_entiers.trois;
          nb_efface_contact += inter_entiers.quatre;

          if (inter_entiers.un) // si un seul des retour s est bon on passe à true
             retour = true;
          nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
        };
        
       if (retour)
         if (niveau_commentaire_lescontacts > 3) //  ==> LesContacts::
            {cout << "\n   en fin de  LesContacts::Nouveau: bilan: "<< nb_contact << " elem(s) contact ";
             if ( nb_new_contact)
                  cout <<", "<< nb_new_contact << " nouveau(x) ";
             if (nb_efface_contact)
                  cout <<", "<<nb_efface_contact << " effacement(s) ";
             cout << flush;
            };
      };
    // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
    broadcast(*ParaGlob::Monde(), retour, 0);
 #endif


    tempsContact.Arret_du_comptage(); // fin cpu
//cout << "\n tempsContact.Temps_CPU_User = " << tempsContact.Temps_CPU_User() << flush;
    return retour;
  };
 
		
// suppression définitive, si le contact à disparu, des éléments inactifs
// ramène false si aucun élément n'est finalement supprimé
bool LesContacts::SuppressionDefinitiveElemInactif()
{
  tempsContact.Mise_en_route_du_comptage(); // def deb compt
  int niveau_commentaire_lescontacts = Permet_affichage();
  bool change = false;
  int nb_effacement=0;
#ifdef UTILISATION_MPI
  int proc_en_cours = ParaGlob::Monde()->rank();
  if (proc_en_cours != 0)  // seules les proc i>0 définissent des éléments de contact
    {

#endif
  if (niveau_commentaire_lescontacts > 4)
      {
     #ifdef UTILISATION_MPI
       cout << "\n proc " << proc_en_cours
     #else
       cout << "\n"
     #endif
            << " -- LesContacts::SuppressionDefinitiveElemInactif: ";
      };
  LaLIST <ElContact>::iterator iE ;
  for (iE = listContact.begin(); iE != listContact.end(); iE++)//,iden++)
  {if (!((*iE).Actif()) // on intervient  si le contact est déclaré inactif
         && ((*iE).Collant())   // et si c'est collant: ce n'est pas normal, on le remet actif
      )
     {(*iE).Met_actif(); // on valide l'activation
     }
   else if (!((*iE).Actif()) // on intervient  si le contact est déclaré inactif
            && !((*iE).Collant())   // et si ce n'est pas collant: si collant, on ne change rien
      )
		  {  LaLIST <ElContact>::iterator iiE = iE;
//		     list <TroisEntiers>::iterator iiden = iden;
       int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
       int num_noeud = (*iiE).Esclave()->Num_noeud();
       if (niveau_commentaire_lescontacts > 3)
          { Element & elem = *(*iiE).Elfront()->PtEI();
            int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
            cout << "\neffacement contact:";(*iiE).Affiche(1);
          };
		     iE--; // pointe sur le precedent element
       listContact_efface_tatdt.push_front(*iiE);
       #ifdef MISE_AU_POINT
         if (tesN_encontact(num_mail_esclave).find((*iiE).Esclave())
               == tesN_encontact(num_mail_esclave).end() )
          { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
                 << (*iiE).Esclave()->Num_noeud() << " du maillage " << num_mail_esclave
                 << " la suite n'est pas possible "
                 << " LesContacts::SuppressionDefinitiveElemInactif(.. \n";
            tempsContact.Arret_du_comptage(); // fin cpu
            Sortie(1);
          };
       #endif
       LaLIST < LaLIST<ElContact>::iterator >  & list_tesN
               = tesN_encontact(num_mail_esclave)[(*iiE).Esclave()];
////--- debug
//{cout << "\n debug LesContacts::SuppressionDefinitiveElemInactif: ";
// (*iiE).Affiche(1);
// }
// //--- fin debug

       list_tesN.remove(iiE);
//       tesN_encontact(num_mail_esclave)(num_noeud).remove(iiE); // mise à jour de l'indicateur
       listContact.erase(iiE); // efface l'element
////--- debug
//{cout << "\n liste restante des elements de contact ";
// LaLIST <ElContact>::iterator iE ;
// for (iE = listContact.begin(); iE != listContact.end(); iE++)
//   {cout << "\n";(*iE).Affiche(1);}
//}
////--- fin debug
       
       nb_effacement++;
			    change = true;
//			    iden--;
//			    numtesN.erase(iiden);
    }
//**** j'ai l'impression que la ligne qui suit ne sert à rien, car le if précédent était uniquement pour les inactifs, donc si on va à la ligne qui suit
// c'est que l'élément est actif, donc cela ne sert à rien de le réactiver ???? ceci dit cela ne génère pas   une erreur a priori
   else {/*(*iE).Met_actif();*/};  // on valide l'activation
 };
  // info
  if (niveau_commentaire_lescontacts > 2)
    { if (nb_effacement)
       {
      #ifdef UTILISATION_MPI
        cout << "\n proc " << proc_en_cours
      #else
        cout << "\n"
      #endif
             << " sup: "<< nb_effacement << " effacement(s) definitif(s) de contact ";
       };
    };
  if ((niveau_commentaire_lescontacts > 6) && (nb_effacement==0))
       cout << " aucun effacement ";
       
 #ifdef UTILISATION_MPI
    temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
     mpi::request reqs1 = ParaGlob::Monde()->isend(0, 610, change);
     // on attend pas
     temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
    }
  else // cas du cpu 0
    {// l'objectif ici est de récupérer  les infos
     tempsContact.Arret_du_comptage(); // fin cpu
     int nb_proc_terminer = 0; // permettra de terminer
     while (nb_proc_terminer < (ParaGlob::Monde()->size()-1))
      { // on récupère un résultat de cpu i
        temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
        bool change_i;
        mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 610, change_i );
        reqs1.wait(); // on attend que le conteneur soit rempli
        if (change_i) // si un seul des retour s est bon on passe à true
           change = true;
        nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
      };

    };
  // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
  broadcast(*ParaGlob::Monde(), change, 0);
 #endif

  tempsContact.Arret_du_comptage(); // fin cpu
  // retour du tableau
  return change;
};
      		
// relachement des noeuds collés
// ramène true s'il y a des noeuds qui ont été relachés
bool LesContacts::RelachementNoeudcolle()
{
  tempsContact.Mise_en_route_du_comptage(); // def deb compt
  int niveau_commentaire_lescontacts = Permet_affichage();
  
  bool change = false;
#ifdef UTILISATION_MPI
  int proc_en_cours = ParaGlob::Monde()->rank();
  if (proc_en_cours != 0)  // seules les proc i>0 définissent des éléments de contact
    {
#endif
  if (niveau_commentaire_lescontacts > 4)
   #ifdef UTILISATION_MPI
     cout << "\n proc " << proc_en_cours
   #else
     cout << "\n"
   #endif
          << " -- LesContacts::RelachementNoeudcolle(): ";
//    return change; //------- pour le débug
  LaLIST <ElContact>::iterator iE ;
//	 list <TroisEntiers>::iterator iden = numtesN.begin();
	 // on met .end(), car cette borne peut changer au gré des suppression
  for (iE = listContact.begin(); iE != listContact.end(); iE++)//,iden++)
   // on ne test que les éléments actifs, pour lesquels les calculs sont à jour
   if (    ((*iE).Actif()) // on intervient  si le contact est déclaré actif
       && !((*iE).Collant())   // et si ce n'est pas collant: si collant, on ne fait rien
      )
		  if ((*iE).Decol())
      // le décolement est testé soit sur la réaction, qui a été calculée
      //  au pas précédent, ou soit sur une position géométrique en dehors d'une zone d'accostage.
      //S'il y a décolement on ne doit plus tenir compte du contact et donc on inactive l'élément de contact			
       {  LaLIST <ElContact>::iterator iiE = iE;
//          list <TroisEntiers>::iterator iiden = iden;
          if (niveau_commentaire_lescontacts > 2)
                 {
                 #ifdef UTILISATION_MPI
                   cout << "\n proc " << proc_en_cours
                 #else
                   cout << "\n"
                 #endif
                        << "inactivation (relachement) pour cause de decollement du contact";
                   (*iiE).Affiche(1); cout << endl;
////------ debug
//{cout << "\n debug: LesContacts::RelachementNoeudcolle() ";
// (*iE).Decol();
//}
//// ------- fin debug
                 };
          change = true;
          (*iE).Met_Inactif();
       };
  if ((!change)&& (niveau_commentaire_lescontacts > 6))
      cout << " aucun noeud relache ";
 #ifdef UTILISATION_MPI
    temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
     mpi::request reqs1 = ParaGlob::Monde()->isend(0, 6100, change);
     // on attend pas
     temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
    }
  else // cas du cpu 0
    {// l'objectif ici est de récupérer  les infos
     tempsContact.Arret_du_comptage(); // fin cpu
     int nb_proc_terminer = 0; // permettra de terminer
     while (nb_proc_terminer < (ParaGlob::Monde()->size()-1))
      { // on récupère un résultat de cpu i
        temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
        bool change_i;
        mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 6100, change_i );
        reqs1.wait(); // on attend que le conteneur soit rempli
        if (change_i) // si un seul des retour s est bon on passe à true
           change = true;
        nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
      };

    };
  // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
  broadcast(*ParaGlob::Monde(), change, 0);
 #endif

  tempsContact.Arret_du_comptage(); // fin cpu
  // retour
  return change;
};

// definition des conditions lineaires de contact
// casAssemb : donne le cas d'assemblage a prendre en compte
// et marquage des ddl imposé par le contact
// Dans le cas d'un   calcul  parallèle, il y a transfert des conditions au  cpu 0
// seules les cpu i calculent les conditions linéaires
// NB: on ne met pas la liste en const car on  a besoin de pouvoir modifier les infos à l'intérieur
// des CL pour les utiliser, mais l'idée est la  liste elle, reste  constante
list <Condilineaire>&  LesContacts::ConditionLin(const Nb_assemb& casAssemb)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
 #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
   if (proc_en_cours != 0)
    {
 #endif
   // on crée des conditions linéaires dans le cas du type 1: contact cinématique
   // mais aussi dans les autres cas pour l'optimisation de largeur de bande par exemple
     {Calcul_Nb_contact_actif();
      listCoLin.clear();// Change_taille(nb_contact_actif);
//cout << "\n nb actif pour condlin = " << nb_contact_actif;
      // on boucle sur les elements de contact
      LaLIST <ElContact>::iterator iE,iEfin=listContact.end() ;
      for (iE = listContact.begin(); iE != iEfin; iE++)
	     if ((*iE).Actif()) // on n'intervient que si le contact est actif
       // appel de la fonction de construction de condition lineaire dans l'element de contact
       {listCoLin.push_front((*iE).ConditionLi(casAssemb.n));
       };
      tempsContact.Arret_du_comptage(); // fin cpu
     }
 #ifdef UTILISATION_MPI
     temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
     // maintenant on va  les transmettres au cpu 0
     // pour cela on va utiliser un conteneur intermédiaire
     // on calcul la taille nécessaire pour le conteneur  (a découper éventuellement ??)
     int taille_conteneur=0;
     list <Condilineaire>::iterator il,ilfin  = listCoLin.end();
     for (il = listCoLin.begin();il != ilfin;il++)
        taille_conteneur += (*il).Taille_Pack();
     inter_transfer.Change_taille(taille_conteneur); //  le conteneur
     //   on rempli le conteneur
     int rang  = 1; // init
     for (il = listCoLin.begin();il != ilfin;il++)
       rang  = (*il).Pack_vecteur(inter_transfer,rang);
     temps_attente.Arret_du_comptage();
     // on transfert
     mpi::request reqs1 = ParaGlob::Monde()->isend(0, 40, taille_conteneur);

     mpi::request reqs2 = inter_transfer.Ienvoi_MPI(0,41);
     // on attend pas
     temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
    }
   else // cas du cpu 0
    {// l'objectif ici est de récupérer  les conditions linéaires
     tempsContact.Arret_du_comptage(); // fin cpu
     temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
     int nb_proc_terminer = 0; // permettra de terminer
     listCoLin.clear();// Change_taille(nb_contact_actif);
     while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
        { // on récupère un résultat de cpu i
          int  taille_transfert;
          mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 40, taille_transfert);
          mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
          inter_transfer.Change_taille(taille_transfert); //  le conteneur
          int source = stat.source(); // récupération du numéro de la source
          //   on récupère
          mpi::request reqs2 = inter_transfer.Irecup_MPI(source, 41);
          reqs2.wait(); // on attend que le conteneur soit rempli
          nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
          // 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(*lesMaille,inter_transfer,rang,
                                   &LesMaillages::Noeud_LesMaille);
              listCoLin.push_back(condi);
            };
        };
     temps_transfert_long.Arret_du_comptage();
    };
 #endif

//   tempsContact.Arret_du_comptage(); // fin cpu
	  // retour du tableau
	  return listCoLin;
 };
      
// effacement du marquage de ddl bloque du au conditions lineaire de contact
void LesContacts::EffMarque()
  {
    tempsContact.Mise_en_route_du_comptage(); // def deb compt
    // on parcours la liste des conditions lineaires
    list <Condilineaire>::iterator il,ilfin  = listCoLin.end();
    for (il = listCoLin.begin();il != ilfin;il++)
      { // on libere la condition
        Condilineaire& C = (*il);
        C.Noe()->Change_fixe(C.Tab_Enum()(1),false);
      };
    tempsContact.Arret_du_comptage(); // fin cpu
  };

// indique si les surfaces des maillages maîtres ont des déplacements fixés
// c-a-d sont de type solide imposé
// retourne true si les déplacements des maîtres sont imposés
bool LesContacts::Maitres_avec_deplacement_imposer() const
 { bool retour = true; // init par défaut
   int dim = ParaGlob::Dimension();
   int nb_zone = MaX(1,nom_ref_zone_contact.size());
   // seule sont disponibles les zones de contact (restreintes éventuellement)
   // on passe en revue tous les noeuds des frontières
   for (int i=1; i<= nbmailMaitre;i++)
    for (int j=1;j<= nb_zone;j++)
    {LaLIST_io <Front>::const_iterator il,ilfin = t_listFront(i)(j).end();
     for (il = t_listFront(i)(j).begin(); il != ilfin; il++)
      {const Tableau <Noeud *>& tn = (*il).Eleme_const()->TabNoeud_const();
       int nb_noe = tn.Taille();
       for (int n = 1;n<= nb_noe;n++)
        { const Noeud& noe = *tn(n); // pour simplifier
          switch(dim)
            {case 3:  if (!(noe.Ddl_fixe(X3))) {retour=false; break;};
             case 2:  if (!(noe.Ddl_fixe(X2))) {retour=false; break;};
             case 1:  if (!(noe.Ddl_fixe(X1))) {retour=false; break;};
            };
          if (!retour) break;
        };
       if (!retour) break;
      };
     if (!retour) break;
    };
   // retour
   return retour;
 };


// def de la largeur de bande des elements contacts
// casAssemb : donne le cas d'assemblage a prendre en compte
// les condi linéaires ne donnent pas des largeurs de bande sup et inf égales !!! 
// demi = la demi largeur de bande maxi , 
// total = le maxi = la largeur sup + la largeur inf +1
// cumule = la somme des maxis, ce qui donnera la largeur finale, due à des multiples multiplications: une par conditions linéaires
//          ceci dans le cas de la prise en compte par rotation (et uniquement dans ce cas)
//  = true : si la largeur de bande en noeud est supérieure à 1 (cas d'un contact avec une surface déformable)
//  = false : si non, ce qui signifie dans ce cas qu'il n'y a pas d'augmentation de la largeur
//            en noeud (cas d'un contact avec une surface rigide)
//  dans  le cas d'un calcul // seule  le cpu  0 effectue   la résolution,  par contre tous les cpu i   contribuent
//  ils vont donc transmettre  les  informations  au cpu   0
bool LesContacts::Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb,int& cumule)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   bool retour = false; // par défaut on se met dans le cas le plus simple : contact avec surface rigide
   // dans le cas d'un contact avec surface déformable, le contact modifie la largeur de bande
   demi = 0;
   total = 0; // c'est le plus important, car la bande sup réelle est en général différente
              // de la bande inf, mais ce qui sera utilisé pour le dimensionnement de la bande de la matrice
      // c'est le total: inf + sup + 1  (le 1 est pour la diagonale, il ne sert à rien)
   cumule = 0;

 #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
   if (proc_en_cours != 0)
    {
 #endif
     // encapsulage  de la  partie hors calcul  parallèle
     {
      LaLIST <ElContact>::iterator iE,iEfin=listContact.end();
      int nb_Assemb = casAssemb.n; // récup du numéro d'assemblage
   //------ debug
   //        cout << "\n LesContacts::Largeur_Bande ";
   // ------ fin debug
      // on boucle sur les elements de contact
      for ( iE = listContact.begin(); iE !=iEfin; iE++)
        {
   //------ debug
   //        (*iE).Affiche();
   // ------ fin debug
     
         // on n'intervient que si le contact est actif et que ce n'est pas un contact solide déformable
         if (((*iE).Actif()) && ((*iE).Cas_solide() == 0))
           { //on boucle sur les noeuds de l'element de contact
             const Tableau <Noeud*>& tabnoeud = (*iE).TabNoeud();
             int maxiPourLeContact=0; // stocke le maxi pour chaque condition linéaire
             retour = true; // ici la largeur de bande en noeud est augmenté, car le noeud en contact
                            // est en relation avec des noeuds d'une surface déformable
       
             for (int noe=1; noe<= tabnoeud.Taille();noe++)
               for ( int no=noe+1; no<=tabnoeud.Taille();no++)
               { Noeud & nne = *tabnoeud(noe);
                 Noeud & nno = *tabnoeud(no);
                 int di;
                 if (nne.PosiAssemb(nb_Assemb) >= nno.PosiAssemb(nb_Assemb))
                    di = nne.PosiAssemb(nb_Assemb) - nno.PosiAssemb(nb_Assemb)
                         + nne.NB_ddl_actif_casAssemb(nb_Assemb);
                 else
                    di = nno.PosiAssemb(nb_Assemb) - nne.PosiAssemb(nb_Assemb)
                         + nno.NB_ddl_actif_casAssemb(nb_Assemb);
                 if ( di > demi)  demi = di;
                 if ( di > maxiPourLeContact) maxiPourLeContact = di;
                 if ( 2*di > total) total = 2*di;
               };
             cumule += maxiPourLeContact;
           };
        };
      total += 1;
      demi += 1;
     tempsContact.Arret_du_comptage(); // fin cpu
    }
   #ifdef UTILISATION_MPI
     temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
     // maintenant on va   transmettre au cpu 0
     // pour cela on va utiliser un conteneur intermédiaire
     QuatreEntiers inter_entiers(demi,total,cumule,retour);
     // on transmet les infos au proc 0
     mpi::request reqs1 = ParaGlob::Monde()->isend(0, 44, inter_entiers);
     // on attend pas
     temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
   }
else // cas du cpu 0
   {// l'objectif ici est de récupérer  les infos
    tempsContact.Arret_du_comptage(); // fin cpu
    int nb_proc_terminer = 0; // permettra de terminer
    while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
     { // on récupère un résultat de cpu i
       temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
       QuatreEntiers inter_entiers;
       mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 44, inter_entiers);
       reqs1.wait(); // on attend que le conteneur soit rempli
       temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
       tempsContact.Mise_en_route_du_comptage(); // def deb compt
       if (inter_entiers.un  > demi) demi = inter_entiers.un;
       if (inter_entiers.deux  > total) total = inter_entiers.deux;
       cumule += inter_entiers.trois;
       retour = (retour || ((bool)inter_entiers.quatre));
       nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
       tempsContact.Arret_du_comptage();
     };
   };
 // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
 broadcast(*ParaGlob::Monde(), retour, 0);
#endif

// retour de l'indicateur
   return retour;
 }; 
      
// actualisation du contact, on examine que les elements de contact, dont on
// actualise la projection du noeud esclave en fonction de la position de l'element
// maitre frontiere (mais la position finale du noeud n'est pas forcément changée, cela dépend du
// modèle de contact (cinématique, pénalisation etc.)
// ramène true si quelque chose à changé, false sinon
// choix == 1 : les éléments actifs sont maintenu en contact même si l'intersection est hors frontière
//              si l'intersection n'est pas calculable, l'élément de contact est laissè inchangé
// choix == 0 : les éléments actifs sont inactivés si l'intersection est hors frontière ou
//              si l'intersection n'est pas calculable,
// NB: pour les deux choix, s'il y a doublon d'élément de contact, due à un changement de frontière
//     en cours d'actualisation, on inactive le(s) doublon(s)
//  dans  le cas d'un calcul // chaque proc i effectue son actualisation, s'il y a changement de surface avec sortie
//  de la surface gérée par le proc i, cela sera vérifié au niveau de l'élément de contact
// Le proc 0 se contente de récupérer et globaliser les retours des proc  i

bool LesContacts::Actualisation(int choix)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   bool retour = false; // init par défaut
   #ifdef UTILISATION_MPI
     int proc_en_cours = ParaGlob::Monde()->rank();
     if (proc_en_cours != 0)
      {
   #endif
       {
        // on boucle sur les elements de contact
        int i;
        LaLIST <ElContact>::iterator iE,iEfin=listContact.end();
       
        int niveau_commentaire_lescontacts = Permet_affichage();

        if (niveau_commentaire_lescontacts >  4)
        #ifdef UTILISATION_MPI
           cout << "\n proc " << proc_en_cours << ":  -- LesContacts::Actualisation: choix: "<< choix;
        #else
           cout << "\n -- LesContacts::Actualisation: choix: "<< choix;
        #endif
        if (niveau_commentaire_lescontacts > 4)
           // on va lister les éléments de contact
          {
            #ifdef UTILISATION_MPI
               cout << "\n proc " << proc_en_cours
                    << ":  liste des Elcontact avant actualisation (fct du niveau de commentaire des elcontact): ";
            #else
               cout << "\n liste des Elcontact avant actualisation (fct du niveau de commentaire des elcontact): ";
            #endif
            
            LaLIST<ElContact>::iterator ipp,ippfin=listContact.end();
            for (ipp=listContact.begin();ipp != ippfin; ipp++)
              {(*ipp).Affiche(2);};
            cout << " fin liste ";
          };

        for (i=1, iE = listContact.begin(); iE !=iEfin; iE++,i++)//,iden++)
          // appel de la fonction d'actualisation de chaque element de contact
          if ((*iE).Actif()) // on intervient  si le contact est déclaré actif
           // on intervient également si c'est collant, car il faut quand même actualiser
           // le contact,
           { int test=0; // init
              {
/*                // Si le retour est négatif et que l'élément est actif, cela signifie que l'on ne peut pas calculer le contact
                // là on on se contente d'inactiver l'élément
                // si le retour == 0: on peut calculer mais on sort de l'élément et même des mitoyens
                // là aussi on se contente d'inactiver l'élément
                // durant l'actualisation, on peut changer d'élément frontière, du coup l'élément de contact résultant
                // peut être égale à un élément déjà existant, et cela va faire double emploi
                // dans ce cas précis on ne va pas valider l'actualisation, mais on se contente d'inactiver l'élément
                
                // actualisation de  la projection du noeud esclave en fonction de la position de l'element
                // maitre frontiere. Lorsque le noeud change d'element fontiere, on change l'element
                // frontiere de l'element de contact en consequence
                // retourne:
                // 0 : dans le cas ou on ne trouve pas d'intersection, cas d'une intersection  qui n'est pas calculable
                // 1  : contact ok, sur l'élément
                // -1 : contact ok, mais hors de l'élément (là, on a parcouru tous les mitoyens et aucun ne convient
                //      du coup on utilise l'élément initial pour la projection
                // 2  : changement de frontière, et contact ok sur la nouvelle frontière
                // NB: sauf pour le cas 0, dans tous les autres cas, les grandeurs locales sont correctement calculées
                //     c-a-d : la projection, la normale
                // en fonction de la méthode de contact, le noeud est ramené éventuellement sur la frontière
*/
                
                test = (*iE).Actualisation();
                ElContact* test_existance=NULL;
                if (test == 2)
                 {// on a changé de frontière, on regarde si l'élément de contact avec la nouvelle frontière n'est pas
                  //identique à un élément existant
                  test_existance= Element_contact_deja_present(iE);
                 };
                if ( ((test < 0) && (choix == 0) && !((*iE).Collant())) // si c'est collant, on maintient le contact arbitrairement sauf si on
                     // est arrivé sur un élément existant
                    || (test == 0) // ou que l'on ne peut pas calculer une intersection ... ce qui fait que le
                                                   // calcul des second membre et raideur ne sera pas possible
                   )
                 // on inactive l'element de contact
                   { LaLIST <ElContact>::iterator iiE = iE;
                     if (niveau_commentaire_lescontacts >= 3)
                       {
                         #ifdef UTILISATION_MPI
                           cout << "\n proc " << proc_en_cours<<": "
                         #else
                           cout << "\n"
                         #endif
                                << "  inactivation contact (les_contacts) pour cause de perte de contact:";
                         #ifdef MISE_AU_POINT
                         if (niveau_commentaire_lescontacts > 4)
                           cout << " test= "<<test;
                         #endif

                         (*iiE).Affiche(1);
                       };
                     (*iiE).Met_Inactif(); // inactive l'élément
                     retour = true; // on signale le changement
                   }
                else if (test_existance != NULL)
                // cas où test est forcément == 2 (car on a calculé test_existance) et on est arrivé sur un élément existant qui est actif
                // on inactive l'element de contact
                  {if (test_existance->Actif())
                    { LaLIST <ElContact>::iterator iiE = iE;
                      if (niveau_commentaire_lescontacts >= 3)
                        {
                          #ifdef UTILISATION_MPI
                            cout << "\n proc " << proc_en_cours<<": "
                          #else
                            cout << "\n"
                          #endif
                                 << "inactivation contact apres chgt de frontiere (les_contacts) pour cause de duplication:";
                          (*iiE).Affiche(1);
                        };
                      (*iiE).Met_Inactif(); // inactive l'élément
                      retour = true; // on signale le changement
                    };
                   }

                else // arrivée ici cela veut dire que test > 0 ou que c'est collant et test n'est pas négatif
                  // ou alors que test < 0 mais on a choix == 1, c-a-d que l'on veut maintenir le contact même en dehors de l'élément actuel
                  // (c'est par exemple une situation transitoire pendant les itérations en implicite)
                   { if (niveau_commentaire_lescontacts >= 7)
                       {
                       #ifdef UTILISATION_MPI
                         cout << "\n proc " << proc_en_cours<<": "
                       #else
                         cout << "\n"
                       #endif
                              << " contact maintenu: ";(*iE).Affiche(1);
                       };
                   };
                // si on a inactivé l'élément, on regarde s'il n'y a pas un autre contact, utilisant le même noeud
                // que l'on pourrait activer
                if (!(*iE).Actif())
                 {Noeud* noe = (*iE).Esclave();
                  int num_mail_noe_esclave = noe->Num_Mail();
                  std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >& tesN_encontact_ii
                                        =  tesN_encontact(num_mail_noe_esclave); // pour simplifier
                  // la liste doit exister ! car au moins (*iE) y appartient
     //            Tableau < std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > > > tesN_encontact;
                 // tesN_encontact(numMail_esclave)[*pt_noeud] -> la liste des iterators d'élément en contact
                 // avec le noeud
                  // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
                  // car autrement on crée automatiquement une liste avec un élément vide
                  std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > >::iterator it_liste;
                  if (tesN_encontact_ii.find(noe) != tesN_encontact_ii.end())
                   {LaLIST < LaLIST<ElContact>::iterator >  & list_tesN = tesN_encontact_ii[noe];
                    LaLIST < LaLIST<ElContact>::iterator >::iterator pl,plfin=list_tesN.end();
                    for (pl = list_tesN.begin();pl != plfin;pl++)
                     if ((*pl) != iE) // on évite celui qu'on vient d'inactiver !!
                      {ElContact& elc = (*(*pl));
                       // on ne continue que si l'élément est inactif, sinon il est étudié dans la boucle globale
                       if (!(elc.Actif()))
                         {// là on va faire une actualisation simplifiée: le cas collant n'est pas à prendre en compte
                          // car on n'arrive jamais ici en collant
                          elc.Met_actif(); // on doit activer l'élément pour utiliser Actualisation
                          // cela veut dire que systématiquement on calcule comme si le noeud esclave se déplace en contact
                          // (ce n'est pas une initialisation )
                          test = elc.Actualisation();
                          test_existance = NULL ; // init
                          if (test == 2)
                            {// on a changé de frontière, on regarde si l'élément de contact avec la nouvelle frontière n'est pas
                             //identique à un élément existant
                             test_existance= Element_contact_deja_present(iE);
                            };
                          if ((test_existance == NULL) && (test > 0))
                            // arrivée ici cela veut dire que le contact est valide
                            // on conserve  l'élément actif
                            { if (niveau_commentaire_lescontacts > 2)
                                {
                                 #ifdef UTILISATION_MPI
                                   cout << "\n proc " << proc_en_cours<<": "
                                 #else
                                   cout << "\n"
                                 #endif
                                        <<  "reactivation contact :";elc.Affiche(1);
                                 };
                            }
                          else // sinon on inactive l'élément  pour le ramener à l'état initial
                           {elc.Met_Inactif();
                            if (elc.Permet_affichage() > 2)
                              cout << " ===>> inactivation car element doublon ";
                           
                           };
                         };
                      };
                   };

                 }
              };
           }
     //		   else
     //		    {nb_contact_actif++; }; // on sauvegarde l'activité
        if (niveau_commentaire_lescontacts > 4)
           // on va lister les éléments de contact
          {
            #ifdef UTILISATION_MPI
              cout << "\n proc " << proc_en_cours<<": "
            #else
              cout << "\n"
            #endif
                   << " liste des Elcontact apres actualisation (fct du niveau de commentaire des elcontact): ";
            LaLIST<ElContact>::iterator ipp,ippfin=listContact.end();
            for (ipp=listContact.begin();ipp != ippfin; ipp++)
              {(*ipp).Affiche(2);};
            cout << " fin liste ";
            // on calcule et affiche le nombre de contact actif
            Calcul_Nb_contact_actif();
            #ifdef UTILISATION_MPI
              cout << "\n proc " << proc_en_cours<<": "
            #else
              cout << "\n"
            #endif
                   << " nb_contact_actif= " << nb_contact_actif << endl;
          };
          
        }
        #ifdef UTILISATION_MPI
          temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
          // maintenant on va   transmettre au cpu 0
          mpi::request reqs1 = ParaGlob::Monde()->isend(0, 45, retour);
          // on attend pas
          temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
        }
     else // cas du cpu 0
        {// l'objectif ici est de récupérer  les infos
         tempsContact.Arret_du_comptage(); // fin cpu
         int nb_proc_terminer = 0; // permettra de terminer
         while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
          { // on récupère un résultat de cpu i
            temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
            bool inter_retour;
            mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 45, inter_retour);
            reqs1.wait(); // on attend que le conteneur soit rempli
            temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
            tempsContact.Mise_en_route_du_comptage(); // def deb compt
            retour = (retour || (inter_retour));
            nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
            tempsContact.Arret_du_comptage();
          };
        };
     #endif
  #ifdef UTILISATION_MPI
   // il faut que tous les proc aient le retour global, car le retour sert dans l'algo général
   broadcast(*ParaGlob::Monde(), retour, 0);
  #endif

   // retour
   tempsContact.Arret_du_comptage(); // fin cpu
  return retour;
 };

// ramène une liste de noeuds dont la position a été perturbé par le contact
// (dépend du type de contact : ex cas contact = 4)
// la liste passée en paramètre est supprimée et remplacée par la liste résultat
// dans le cas d'un calcul  // chaque proc i calcule   une liste et la transmet au  proc  0
// Le proc 0 globalise toutes les liste
void LesContacts::Liste_noeuds_position_changer(list <Noeud * >& li_noe)
 { tempsContact.Mise_en_route_du_comptage(); // def deb compt
   // récup du type de contact
   int contact_type = ElContact::Recup_et_mise_a_jour_type_contact();
   li_noe.clear(); // on vide la liste
   int niveau_commentaire_lescontacts = Permet_affichage();
   #ifdef UTILISATION_MPI
     int proc_en_cours = ParaGlob::Monde()->rank();
     if (proc_en_cours != 0)
      {
   #endif
       {
        if (contact_type== 4) // pour l'instant c'est le seul type de contact qui est concerné
         { // on boucle sur les elements de contact
           int i;
           LaLIST <ElContact>::iterator iE,iEfin=listContact.end();
          
         #ifndef UTILISATION_MPI
           if (niveau_commentaire_lescontacts >= 7)
              cout << "\n -- LesContacts::Liste_noeuds_position_changer: ";
         #endif

           for (i=1, iE = listContact.begin(); iE !=iEfin; iE++,i++)//,iden++)
             if ((*iE).Actif()) // on intervient  si le contact est déclaré actif
               {// récup du noeud esclave
                Noeud* noe = (*iE).Esclave();
                li_noe.push_back(noe);
               };
         };
        tempsContact.Arret_du_comptage(); // fin cpu
       }
      #ifdef UTILISATION_MPI
        temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
        // maintenant on va   transmettre au cpu 0
        int taille_list  = li_noe.size();
        mpi::request reqs1 = ParaGlob::Monde()->isend(0, 46, taille_list);
        // on attend pas
        temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
        temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
        // maintenant on va   transmettre au cpu 0
        // on va se servir d'un  conteneur intermédiaire
        union double_int
          {  double  x;
             int     n[2];
          } ;
        double_int xinter;
        Vecteur v_inter(taille_list);
        list <Noeud * >::iterator  il,ilfin=li_noe.end();
        int i=1;
        for (il = li_noe.begin();il !=ilfin;il++,i++)
         {xinter.n[0]  = (*il)->Num_Mail(); xinter.n[1]  = (*il)->Num_noeud();
          v_inter(i)=xinter.x;
         };
        // envoi
        v_inter.Ienvoi_MPI(0,47);
        // on attend pas
        temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
      }
   else // cas du cpu 0
      {// l'objectif ici est de récupérer  les infos
       union double_int
         {  double  x;
            int     n[2];
         } ;
       double_int xinter;
       int nb_proc_terminer = 0; // permettra de terminer
       while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
        { // on récupère un résultat de cpu i
          temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
          int taille_list ;
          mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 46, taille_list );
          mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
          int source = stat.source(); // récupération du numéro de la source
          temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
          temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
          Vecteur v_inter(taille_list);
          mpi::request reqs2 = v_inter.Irecup_MPI(source, 47);
          reqs2.wait(); // on attend que le conteneur soit rempli
          temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
          tempsContact.Mise_en_route_du_comptage(); // def deb compt
          // maintenant  on abonde la liste
          for (int i=1;i<= taille_list;i++)
            {xinter.x = v_inter(i);
             li_noe.push_back(&(lesMaille->Noeud_LesMaille(xinter.n[0],xinter.n[1])));
            };
          nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
          tempsContact.Arret_du_comptage();
        };
       if (niveau_commentaire_lescontacts >= 7)
             cout << "\n proc 0: -- LesContacts::Liste_noeuds_position_changer: ";
      };
   #endif

   tempsContact.Arret_du_comptage(); // fin cpu
 };

// calcul des reactions de contact et stockage des valeurs
// solution : le vecteur residu
// test d'un decollement eventuelle, pour un noeud en contact
// Dans le cas d'un  calcul   parallèle, tous les cpu calculent, mais seule le cpu 0
// affiche les messages normaux, mais tous les cpu affichent les messages d'erreur éventuels
// et les messages pour les niveaux de commentaires > 4

void LesContacts::CalculReaction(Vecteur& residu,bool& decol,const Nb_assemb& casAssemb
                                 ,bool affiche)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
  #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
  #endif
   int niveau_commentaire_lescontacts = Permet_affichage();
  #ifdef UTILISATION_MPI
   if (proc_en_cours == 0)
  #endif
    if (niveau_commentaire_lescontacts > 4)
   #ifdef UTILISATION_MPI
     cout << "\n proc " << proc_en_cours
   #else
     cout << "\n"
   #endif
          << " -- LesContacts::CalculReaction: \n";
   int nb_Assemb = casAssemb.n; // récup du numéro d'assemblage
   // récup du type de contact
   int contact_type = ElContact::Recup_et_mise_a_jour_type_contact();
  
   // mise a dimension du tableau de stockage
//     tabReacCont.Change_taille((int)listContact.size());
   // on recalcule le nombre de contact actif car c'est mal géré, je ne sais pas pourquoi et ou
   Calcul_Nb_contact_actif();
	  tabReacCont.Change_taille(nb_contact_actif);
   int itab ; // indice du tableau     
   decol = false;
   bool axi = false; // cas particulier de l'axi
   if (ParaGlob::AxiSymetrie())
     axi = true;
  
   LaLIST <ElContact>::iterator iE,iEfin = listContact.end();
  
 
   // on boucle sur les elements de contact
   for ( itab=1,iE = listContact.begin(); iE != iEfin; iE++)
		  {if ((*iE).Actif())
		    { Noeud* noe = (*iE).Esclave(); // le noeud esclave
        int posi = noe->Pointeur_assemblage(X1,nb_Assemb); // position du ddl X1
        #ifdef MISE_AU_POINT	 	 
	         if ( posi == -1 )
			        {
           #ifdef UTILISATION_MPI
             cout << "\n proc " << proc_en_cours
           #else
             cout << "\n"
           #endif
                  << "Erreur : ddl X1 "
			               << " inexistant  pour le cas de charge " << nb_Assemb <<  '\n'
			               << " LesContacts::CalculReaction( (1)\n";
             tempsContact.Arret_du_comptage(); // fin cpu
			          Sortie(1);
           };
        #endif  
        int dim = noe->Dimension(); // dimension
        // dans le cas où on est en axi-symétrie, le vecteur réaction est en 2D car le calcul au niveau de l'équilibre
        // global n'est fait qu'en x et y
        // donc on ne peut récupérer que du x et du y
        int nb_ddl_en_var =  dim; // init
        if (axi)
          nb_ddl_en_var -= 1;
        Coordonnee force(dim); // on dimensionne à  dim au cas où
        for (int i=1;i<=nb_ddl_en_var;i++)
           // je crois qu'il faut un - pour la force (??) 20 avril 2018
          force(i) = -residu(posi+i-1); // si le type de contact est de type 1 -> c'est la réaction
        if ((contact_type==1)||(contact_type==3))
            (*iE).Change_force(force); // mise à jour de la force dans l'élément de contact
       
        if (niveau_commentaire_lescontacts > 5)
          {if ((contact_type==1)||(contact_type==3))
            {cout << "\n LesContacts::CalculReaction >> Details: residu totale = contact + CL + F_int (noeud:" << noe->Num_noeud()
                 << " maillage:"<< noe->Num_Mail() << ")\nR=" << force << " gapTDT= " << (*iE).Gaptdt()
                 << "\n dont F_contact= "<< (*iE).Force_contact() ;
             cout << "\n noeud: coor_tdt: "<<noe->Coord2() <<"\n delta: "<<(noe->Coord2()-noe->Coord1());
            }
           else if ((contact_type == 2) || (contact_type == 4)|| (contact_type == 41)|| (contact_type == 42))
            {cout << "\n LesContacts::CalculReaction >> Details: F_contact  (noeud:" << noe->Num_noeud()
// 19 juin 2018                 << " maillage:"<< noe->Num_Mail() << ")\nF=" << force << " gapTDT= " << (*iE).Gaptdt() ;
                  << " maillage:"<< noe->Num_Mail() << ")\nForce= " << (*iE).Force_contact()
                  << " gapTDT= " << (*iE).Gaptdt() ;
             cout << "\n noeud: coor_tdt: "<<noe->Coord2() <<"\n delta: "<<(noe->Coord2()-noe->Coord1());
             if (niveau_commentaire_lescontacts > 7)
               (*iE).Affiche();
              
            }
           else {cout << "\n *** erreur, cas de type de contact= " << contact_type << " pas encore pris en compte " ;
                 tempsContact.Arret_du_comptage(); // fin cpu
                 Sortie(1);
                };
          };
        // on regarde si le noeud decolle
        if ((*iE).Decol()) decol = true;
        // puis les noeuds de l'element maitre
//!!!!! il faudra prevoir un cas ou on ne sauvegarde pas les maitres         
         
        Tableau <Noeud *>& tabNoeud = (*iE).Elfront()->Eleme()->TabNoeud(); // le tableau
        // on cree un tableau de sauvegarde des forces
        int tail = tabNoeud.Taille();
        // Dans le cas du type 1 de contact, c'est le retour du résidu qui permet de construire des
        // réaction, alors que dans le cas du type 2 c'est au contraire dans l'élément de contact
        // que les grandeurs ont déjà été calculées
        if ((contact_type==1)||(contact_type==3))
          {Coordonnee ex(dim); // une position à la bonne dimmension
           Tableau <Coordonnee> tabForce(tail,ex); // dimmensionnement du tableau avec alocation
           for (int it=1;it<= tail;it++)
             { posi = tabNoeud(it)->Pointeur_assemblage(X1,nb_Assemb) ; // position du ddl X1
               #ifdef MISE_AU_POINT	 	 
               if ( posi == -1 )
                {
                #ifdef UTILISATION_MPI
                  cout << "\n proc " << proc_en_cours
                #else
                  cout << "\n"
                #endif
                       << "Erreur : ddl X1 "
                       << " inexistant  pour le cas de charge " << nb_Assemb <<  '\n'
                       << " LesContacts::CalculReaction( (2)\n";
                  tempsContact.Arret_du_comptage(); // fin cpu
                  Sortie(1);
                };
               #endif  
               for (int i=1;i<=nb_ddl_en_var;i++)
                 tabForce(it)(i) = residu(posi+i-1); // la reaction
             };
           tabReacCont(itab) = ReactCont(noe,force,tabNoeud,tabForce);
          }
        else
          {tabReacCont(itab) = ReactCont(noe,(*iE).Force_contact(),tabNoeud,(*iE).TabForce_cont());
          };
			     itab++;
      };
		  };  
   // affichage éventuelle de la force maxi de contact
   Forces_contact_maxi(affiche);
   // idem pour les gap N et T
   Gap_contact_maxi(affiche);
   
   tempsContact.Arret_du_comptage(); // fin cpu
 };
      
// affichage des reactions de contact sur la sortie
// il s'agit ici d'une sortie sur fichier : seule le cpu 0 l'effectue
void LesContacts::Affiche(ostream& sort) const 
  {
  #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
   if (proc_en_cours == 0)
  #endif
// on balaie le tableau de reaction
    for (int i= 1; i<= tabReacCont.Taille();i++)
      { ReactCont & R = tabReacCont(i);
        sort << "\n================= noeud esclave ==================";
        sort << "\nmaillage " << (R.noe)->Num_Mail()
             <<", noeud " << (R.noe)->Num_noeud()
             << ", force = " << R.force ; 
        sort << "\n---------------- noeuds de la frontiere maitre -------------";
        int tail = R.tabNoeud.Taille();
        for (int it=1;it<= tail;it++)
         { Noeud & no = *(R.tabNoeud(it));
           Coordonnee& coor = R.tabForce(it);
           sort << "\nmaillage " << no.Num_Mail()
                <<", noeud " << no.Num_noeud()
                << ", force = " << coor << ", de norme =" << coor.Vect().Norme() ;
         };
      };
  };
      
// affichage à l'écran des informations liées au contact
// cas d'un  calcul parallèle, on considère qu'il s'agit d'un affichage volontaire
// donc tous les cpu peuvent l'utiliser: on affiche en + le num du cpu
void LesContacts::Affiche() const      
  {
  #ifdef UTILISATION_MPI
    int proc_en_cours = ParaGlob::Monde()->rank();
    cout << "\n proc " << proc_en_cours
  #else
    cout << "\n"
  #endif
           << "\n ---- affichage des informations liees au contact --------";
    cout << "\n 1) liste des elements en contact";
    LaLIST <ElContact>::const_iterator il,ilfin=listContact.end();
    for (il=listContact.begin();il != ilfin; il++)
       (*il).Affiche();
    cout << "\n 2) reactions aux contact";
    // on balaie le tableau de reaction
    for (int i= 1; i<= tabReacCont.Taille();i++)
      { ReactCont & R = tabReacCont(i);
        cout << "\n================= noeud esclave ==================";
        cout << "\nmaillage " << (R.noe)->Num_Mail()
             <<", noeud " << (R.noe)->Num_noeud()
             << ", force = " << R.force ; 
        cout << "\n---------------- noeuds de la frontiere maitre -------------";
        int tail = R.tabNoeud.Taille();
        for (int it=1;it<= tail;it++)
         { Noeud & no = *(R.tabNoeud(it));
           Coordonnee& coor = R.tabForce(i);
           cout << "\nmaillage " << no.Num_Mail()
                <<", noeud " << no.Num_noeud()
                << ", force = " << coor << ", de norme =" << coor.Vect().Norme() ;
         };
      };
    cout << "\n 3) liste des references de zones succeptibles d'entrer en contact";

    list <Quatre_string_un_entier>::const_iterator ill,illfin=nom_ref_zone_contact.end();
    cout << "\n";
    for (ill=nom_ref_zone_contact.begin();ill != illfin; ill++)
       { if ((*ill).nom1.length()) cout << " mail= " << (*ill).nom1 << " ";
         cout << "ref de noeud esclave: " << (*ill).nom2;
         if ((*ill).n ==1)
           cout << " (contact collant) ";
         cout << ",  ";
         if ((*ill).nom3.length()) cout << " mail= " << (*ill).nom3 << " ";
         cout << "ref des frontieres maitres : " << (*ill).nom4;
       };
  };      
  
// affichage et definition interactive des commandes
void LesContacts::Info_commande_LesContacts(UtilLecture & entreePrinc)
{
   #ifdef UTILISATION_MPI
     cout << "\n *** erreur , la methode LesContacts::Info_commande_LesContacts "
          << " n'est  pas utilisable en exécution MPI !!! ";
     Sortie(1);
   #endif

   ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
   //On va proposer un menu
   string rep=" ";
   sort << "\n#    --- les contact -------       ";
   while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
    {
      try
       {
        cout << "\n -- definition de : --- "
           << "\n (0 ou f)  (fin)               "
           << "\n (1)  auto_contact    "
           << "\n (2)  zone particuliere de contact "
           << "\n (3)  contact solide-deformable "
           << "\n (4)  contact collant "
           << "\n (5)  contact collant avec suppression du gap"
           << "\n (6 ou ? ) informations  "
           << "\n  ";
        
        // procédure de lecture avec prise en charge d'un retour chariot
        rep = lect_return_defaut(false,"f");
        if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
          break;
        int num = ChangeEntier(rep);
        if (Minuscules(rep) == "?")
          num = 6;
        bool choix_valide=false;
        if ((num >= 0)&&(num<=6))
             { choix_valide=true; }
        else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
                    << "\n redonnez une bonne valeur"
                    << "\n ou taper f ou 0 pour arreter le programme"; 
               choix_valide=false;
             }
        string grandeur=" "; // init
        
        switch (num)
         { case 0:  // sortie
             { break;} // normalement cela a déjà été filtré avant
           case 1: // auto_contact 
             { sort << "\n auto_contact   \n";
               sort << "\n#--------------------------------------------------------------------------------";
               sort << "\n#  definition du nombre de domaine esclave  en auto-contat   |";
               sort << "\n#--------------------------------------------------------------------------------";
               cout << "\n nombre de maillage en autocontact (un entier) ? ";
               string nb_str;
               //int nb =0;
               nb_str = (int) lect_double();
               if ((Minuscules(nb_str) == "f") || (Minuscules(nb_str) == "0"))// sortie directe
                  break;
               int nb = ChangeEntier(nb_str);
               cout << " nom lu = "<< nb_str << " c-a-d le nombre "<<nb ;
               sort << "\n "<< nb <<endl ;
               break;
             }
           case 2: // zone particuliere de contact
             { cout << "\n def d'une ref de noeuds esclave ";
               string nom_mail1="";
               cout << "\n nom du maillage ? ";
               nom_mail1= lect_chaine(); cout << " nom lu = "<< nom_mail1;
               
               cout << "\n nom de la reference de noeud ? ";
               string nom_ref=" ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
              
               cout << "\n def d'une ref de faces maitres ";
               string nom_mail_face="";
               cout << "\n nom du maillage ? ";
               nom_mail_face= lect_chaine(); cout << " nom lu = "<< nom_mail_face;
               cout << "\n nom de la reference de face ? ";
               string nom_ref_face="";
               nom_ref_face= lect_chaine();cout << " nom lu = "<< nom_ref_face;
               if (nom_ref_face.at(0) != 'F')
                {cout << "\n *** erreur, la premiere lettre de la ref de face "
                      << " doit etre F et non "<< nom_ref_face.at(0)<< " !!";
                 break;
                };
              
               sort << "\n\n  zone_contact #------------- ";
               sort << "\n#----------------------------------------------------"
                    << "\n# ref noeuds            |      ref face             |"
                    << "\n#----------------------------------------------------";
               sort << "\n  nom_mail= "<< nom_mail1<< "  "<< nom_ref << " "
                    << " nom_mail= "<< nom_mail_face << "  "<< nom_ref_face <<endl;
               break;
             }
           case 3: // contact solide-deformable
             { cout << "\n def de contact de type solide-deformable ";
               sort << "\n\n  contact_solide_deformable #------------- ";
               sort << "\n#----------------------------------------------------"
                    << "\n#  maillage solide   |   maillage deformable        |"
                    << "\n#----------------------------------------------------";
               sort << "\n debut_liste_des_couples_de_noms_solide_deformable ";
               string nom_mailsolide="";
               do {
                   cout << "\n nom du maillage considere solide ? (ou f pour finir) ";
                   nom_mailsolide= lect_chaine(); cout << " nom lu = "<< nom_mailsolide;
                   if (Minuscules(nom_mailsolide) == "f")
                     break;
                   cout << "\n nom du maillage considere deformable ";
                   string nom_maildeformable="";
                   cout << "\n nom du maillage ? ";
                   nom_maildeformable= lect_chaine(); cout << " nom lu = "<< nom_maildeformable;
                   sort << "\n  solide= "<< nom_mailsolide<< "  "
                    << " deformable= "<< nom_maildeformable << "  " <<endl;
                  } while (Minuscules(nom_mailsolide) != "f");
               sort << "\n fin_liste_des_couples_de_noms_solide_deformable ";
               break;
             }
           case 4: case 5: // zone contact collant
             { cout << "\n def d'une ref de noeuds esclave ";
               string nom_mail1="";
               cout << "\n nom du maillage ? ";
               nom_mail1= lect_chaine(); cout << " nom lu = "<< nom_mail1;
              
               cout << "\n nom de la reference de noeud ? ";
               string nom_ref=" ";
               nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
               if (nom_ref.at(0) != 'N')
                {cout << "\n *** erreur, la premiere lettre de la ref de noeud "
                      << " doit etre N et non "<< nom_ref.at(0)<< " !!";
                 break;
                };
              
               cout << "\n def d'une ref de faces maitres ";
               string nom_mail_face="";
               cout << "\n nom du maillage ? ";
               nom_mail_face= lect_chaine(); cout << " nom lu = "<< nom_mail_face;
               cout << "\n nom de la reference de face ? ";
               string nom_ref_face="";
               nom_ref_face= lect_chaine();cout << " nom lu = "<< nom_ref_face;
               if (nom_ref_face.at(0) != 'F')
                {cout << "\n *** erreur, la premiere lettre de la ref de face "
                      << " doit etre F et non "<< nom_ref_face.at(0)<< " !!";
                 break;
                };
               if (num==4)
                    {sort << "\n\n  glue_contact #------------- ";}
               else {sort << "\n\n  glue_contact_init_gap_zero #------------- ";};
               sort << "\n#----------------------------------------------------"
                    << "\n# ref noeuds            |      ref face             |"
                    << "\n#----------------------------------------------------";
               sort << "\n  nom_mail= "<< nom_mail1<< "  "<< nom_ref << " "
                    << " nom_mail= "<< nom_mail_face << "  "<< nom_ref_face <<endl;
               break;
             }
           case 6: // information
             { cout << "\n -- Concernant l'auto-contact, le nombre demande indique "
                    << "\n le nombre de maillages en auto-contact, compte parmi les maillages"
                    << "\n esclaves, donc doit etre <= au nombre de maillages esclaves ! "
                    << "\n -- Concernant les zones de contact, indique les ref de noeuds esclaves"
                    << "\n qui doivent etre consideres potentiellement en contact avec les ref "
                    << "\n de faces. Si un (ou les deux) des deux mots cles zone_contact et/ou glue_contact "
                    << "\n existe, seules les zones definies sont prises en compte."
                    << "\n -- Concernant le contact solide deformable "
                    << "\n le maillage indique comme solide doit etre un maillage maitre "
                    << "\n ou un maillage en auto-contact "
                    << "\n le maillage deformable doit-etre un maillage esclave ou en auto-contact "
                    << "\n le noeud en contact du solide deformable est systematiquement deplace  "
                    << "\n sur la surface du solide deformable, cette condition se substitue donc "
                    << "\n a une condition de penalisation si celle-ci est en oeuvre "
                    << "\n -- Concernant les zones de contact collant, indique les ref de noeuds esclaves"
                    << "\n qui seront imposes en contact avec les ref "
                    << "\n de faces. Si un (ou les deux) des deux mots cles zone_contact et/ou glue_contact "
                    << "\n existe, seules les zones definies sont prises en compte."
                    << "\n "<<endl ;
             }
           default:
             cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
         };
       }
      catch (ErrSortieFinale)
           // cas d'une direction voulue vers la sortie
           // on relance l'interuption pour le niveau supérieur
         { ErrSortieFinale toto;
           throw (toto);
         }
      catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
    }; //-- fin du while
   sort << flush;

};

// lecture éventuelle des zones où le contact doit être recherché, à l'exclusion de tout
// autre zone, ainsi que la définition de l'auto-contact éventuel
// ainsi que des contacts solide-deformables éventuel
// cas d'un  calcul parallèle, tous  les proc utilisent la méthode, seule le proc  0 affiche
void LesContacts::Lecture_zone_contact(UtilLecture & entreePrinc,const LesReferences& lesRef)
{
 #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
 #endif

  list <int> li_lissage_de_la_normale; // stockage intermédiaire pour créer le tableau lissage_de_la_normale
  int niveau_commentaire_lescontacts = Permet_affichage();
	 while (   (strstr(entreePrinc.tablcar,"auto_contact")!=NULL)
         || (strstr(entreePrinc.tablcar,"zone_contact")!=NULL)
         || (strstr(entreePrinc.tablcar,"contact_solide_deformable")!=NULL)
         || (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
         || (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
        )
   {// on regarde si la zone de contact est avec lissage de la normale
    int avec_lissage_de_la_normale = 0;
    if (strstr(entreePrinc.tablcar,"avec_lissage_de_la_normale")!=NULL)
        avec_lissage_de_la_normale = 1;
 
    // --- on examine le cas où il y a un marquage d'auto-contact
    if (strstr(entreePrinc.tablcar,"auto_contact")!=NULL)
     // cas ou l'on a des domaines esclaves en auto-contact, lecture du nombre
     { entreePrinc.NouvelleDonnee(); 
       if (niveau_commentaire_lescontacts >= 4)
        #ifdef UTILISATION_MPI
         if (proc_en_cours == 0)
        #endif
            cout << " lecture du nombre de domaines esclaves en auto-contact "  << endl;
       *(entreePrinc.entree) >> nbmailautocontact; // lecture du nombre
       if (niveau_commentaire_lescontacts >= 5) cout << nbmailautocontact  << endl;
       if (niveau_commentaire_lescontacts >= 4)
       #ifdef UTILISATION_MPI
        if (proc_en_cours == 0)
       #endif
           cout << " fin de la lecture du nombre de domaines esclaves en auto-contact " << endl;
       entreePrinc.NouvelleDonnee(); // positionnement sur une nouvelle info
     };
       // --- cas des zones particulières de contact
    if (   (strstr(entreePrinc.tablcar,"zone_contact")!=NULL)
        || (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
        || (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
       )
     {
       int indic_glue = 0; // init de non glue a priori
       if (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
         {indic_glue = 2; }// cas particulier d'un contact collant avec suppression du gap
       else if (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
         {indic_glue = 1; }// cas particulier d'un contact collant

       // lecture  tant qu'il n'y a pas de nouveau mot clé
       entreePrinc.NouvelleDonnee();
       if (niveau_commentaire_lescontacts >= 4)
          #ifdef UTILISATION_MPI
           if (proc_en_cours == 0)
          #endif
             cout << " debut de la lecture des zones de contact possibles " << endl;
       while (!motCle.SimotCle(entreePrinc.tablcar))
        { // on lit 2 par deux: une ref de noeud + une ref de frontière
          Quatre_string_un_entier quatre_inter; // une grandeur de travail
          quatre_inter.n = indic_glue; // on stocke la glue éventuelle
          for (int nr=1;nr<=2;nr++)
           {// on commence par regarder si le nom du maillage est définit pour la référence
            string nom_ref; // variables de travail
            string* nom_mail=NULL; string nom("");
            if (strstr(entreePrinc.tablcar,"nom_mail=")!=NULL)
              { *(entreePrinc.entree) >> nom >> nom; nom_mail = & nom;}
            // lecture du nom d'une référence
            *(entreePrinc.entree) >> nom_ref;
            #ifdef ENLINUX
            if ((entreePrinc.entree)->rdstate() == 0)
            #else
            if (((entreePrinc.entree)->rdstate() == 0)||((entreePrinc.entree)->eof()))
            #endif
            // pour mémoire ici on a
             /*       enum io_state
                      {  badbit   = 1<<0, // -> 1 dans rdstate()
                         eofbit   = 1<<1, // -> 2
                         failbit  = 1<<2, // -> 4
                         goodbit  = 0     // -> O
                       };*/
            // lecture normale, vérification que la référence existe bien
            {
              if (!(lesRef.Existe(nom_ref,nom_mail)))
               {
              #ifdef UTILISATION_MPI
                if (proc_en_cours == 0)
              #endif
                  cout << "\n erreur le nom de reference de zone de contact : " << nom_ref
                       << " , n'existe pas !!"
                       << "\n LesContacts::Lecture_zone_contact(..";
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie (1);
                }
              else // enregistrement du nom de référence
                { if (nr==1)
                    // premier passage on stocke
                    {quatre_inter.nom1=nom;quatre_inter.nom2=nom_ref;}
                  else // cas du deuxième passage on enregistre
                    {quatre_inter.nom3=nom;quatre_inter.nom4=nom_ref;
                     nom_ref_zone_contact.push_back(quatre_inter);
                     li_lissage_de_la_normale.push_back(avec_lissage_de_la_normale);
                    };
                }
              #ifndef ENLINUX
              if ((entreePrinc.entree)->eof())   // on arrive à la fin de la ligne
                entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
              #endif
            }
           //sinon il y a un pb ou, l'on est à la fin de la ligne et on passe à l'enregistrement suivant
           #ifdef ENLINUX
           else  if ((entreePrinc.entree)->fail())
              // on a atteind la fin de la ligne et on appelle un nouvel enregistrement 
              { entreePrinc.NouvelleDonnee(); }  // lecture d'un nouvelle enregistrement
           #endif
           else // cas d'une erreur de lecture
              {
               #ifdef UTILISATION_MPI
                if (proc_en_cours == 0)
               #endif
                { cout << "\n erreur de lecture inconnue  au niveau des references de zone de contact";
                  entreePrinc.MessageBuffer("** LesContacts::Lecture_zone_contact(.. **");
                  Affiche();
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie (1);
                 };
              };
          }; // -- fin for (int nr=1;nr<=2;nr++)
        }; //-- fin du while (!motCle.SimotCle(entreePrinc.tablcar))
       if (niveau_commentaire_lescontacts >= 4)
       #ifdef UTILISATION_MPI
        if (proc_en_cours == 0)
       #endif
          cout << " fin de la lecture des zones de contact " << endl;
     };
       // --- cas des contacts solide-deformable
    if (strstr(entreePrinc.tablcar,"contact_solide_deformable")!=NULL)
     { if (niveau_commentaire_lescontacts >= 4)
        #ifdef UTILISATION_MPI
         if (proc_en_cours == 0)
        #endif
           cout << " debut de la lecture des contacts solide-deformable " << endl;
       string toto; // variables de travail
       while (strstr(entreePrinc.tablcar,"fin_liste_des_couples_de_noms_solide_deformable")==NULL)
//              && (!motCle.SimotCle(entreePrinc.tablcar)))
         { Deux_String ie; // une variable de travail
           *(entreePrinc.entree) >> toto >> ie.nom1 >> toto >> ie.nom2;
           cont_solide_defor.push_back(ie);
           entreePrinc.NouvelleDonnee();
         };
       // on passe le mot clé de fin
       entreePrinc.NouvelleDonnee();
       if (niveau_commentaire_lescontacts >= 4)
       #ifdef UTILISATION_MPI
        if (proc_en_cours == 0)
       #endif
          cout << " fin de la lecture des contacts solide-deformable " << endl;
     };
   };
  // création du tableau lissage_de_la_normale
  int nb_zone_lue = li_lissage_de_la_normale.size();
  if (nb_zone_lue != 0)
    {lissage_de_la_normale.Change_taille(nb_zone_lue); // init
     list <int>::iterator il,ilfin=li_lissage_de_la_normale.end();
     int iii=1;
     for (il = li_lissage_de_la_normale.begin();il != ilfin;il++,iii++)
         lissage_de_la_normale(iii) = (*il);
    }
  else // sinon on définie une seule zone et sans lissage
   {lissage_de_la_normale.Change_taille(1); lissage_de_la_normale(1)=0;};
};