
// 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"

#include "Enum_TypeQuelconque.h"
#include "TypeQuelconqueParticulier.h"


// --------------- variables statiques ---------
 MotCle LesContacts::motCle; // liste des mots clés

//------------------------- 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 () :
 tabCoLin(),tabReacCont(),listContact()//,numtesN()
 ,sauve_lesFonctionsnD(NULL),fct_nD_contact()
 ,listContact_nouveau_tatdt(),listContact_efface_tatdt()
 ,nom_ref_zone_contact(),lissage_de_la_normale()
 ,t_listFront(),nb_mail_Esclave(),nbmailautocontact(0),nbmailMaitre()
 ,tesctotal(),tesN_encontact()
 ,tesN_collant()
 ,nb_contact_actif(0),indice(),cont_solide_defor(),liQ_en_sortie()
 ,t_connectionCLL()
 ,liste_elemens_front(),tempsContact()
  {};
// constructeur de copie
LesContacts::LesContacts (const LesContacts& a):
 tabCoLin(a.tabCoLin),tabReacCont(a.tabReacCont)
 ,sauve_lesFonctionsnD(a.sauve_lesFonctionsnD),fct_nD_contact(a.fct_nD_contact)
 ,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)
 ,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)
  {};
    // 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
     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(); 
     if (niveau_commentaire_lescontacts > 4)
         cout << "\n -- LesContacts::Init_contact: ";
         
     // sauvegarde de la liste des fonctions nD
     sauve_lesFonctionsnD = lesFonctionsnD;
     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
            { 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);
            }
          else if (pt_fonct->NbComposante() > 2)
            { 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);
            }
          else // sinon ok
           {ElContact::Init_fct_pilotage_contact4(pt_fonct);}
        }
       else
        { 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);
        };
      };
    
   /* // ----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
     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;
     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
              };
            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));
           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();
        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
           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
             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
           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;
              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
                   { 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
        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);
    
     // Pour diminuer le temps de recherche, et aussi les messages on va constituer une liste des éléments
     // qui contiennent les frontières
     int nb_zone = MaX(1,nom_ref_zone_contact.size());
     liste_elemens_front.clear(); // init de la liste
     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());
         };
       };
     // 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

     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
            if (elem.In_boite_emcombrement_elem(pt_esc))
            // on teste alors plus précisemment
            {//compteur++;
             if ((elem.Interne_t(pt_esc)==1) && (niveau_commentaire_lescontacts >= 3))
              { cout << "\n attention, noeud esclave dans elem. "
                     << "avant incre. 1 charge";
                if (niveau_commentaire_lescontacts > 2)
                     cout << "\n LesContacts::Verification(..)";
                int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                cout << "\n -> noeud " << tesc(inesc)->Num_noeud() << " du maillage " << tesc(inesc)->Num_Mail()
                     << " dans l'element " <<  elem.Num_elt() << " du maillage " << num_mail_elem ;
                if (tesN_col(inesc)) cout << " (contact collant) ";
//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
bool  LesContacts::DefElemCont(double dep_max)
  {
    #ifdef UTILISATION_MPI
    // cas d'un  calcul //,
    // pour l'instant seule le CPU 0 est concernée
    if (ParaGlob::Monde()->rank() != 0)
      return false;
    #endif
    
    tempsContact.Mise_en_route_du_comptage(); // def deb compt
    bool retour = false; // init par défaut
    int niveau_commentaire_lescontacts = Permet_affichage();
    if (niveau_commentaire_lescontacts > 4)
        cout << "\n ==> LesContacts::Def Elem Cont, initialement "<<listContact.size() << " elem contact ";
    // 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());

   
    // 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
          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
             {
              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;
              bool a_considerer = true; // init par défaut
              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,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
                   // 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();
                       cout << "\n 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)
                            { 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();
                             cout << "\ncontact 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 > 2)
                               { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                                 cout << "\n --- changement d'element en contact ---";
                                 cout << "\ncontact 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
    // retour
    if (niveau_commentaire_lescontacts > 2) //  ==> LesContacts::
      { cout << "\n            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;
      };
    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();
    int nb_zone = MaX(1,nom_ref_zone_contact.size());
   
    // on sauvegarde la liste au départ
    int taille_list_contact_nouveau_au_debut = listContact_nouveau_tatdt.size();

    if (niveau_commentaire_lescontacts > 3)
        cout << "\n ==> LesContacts::Nouveau:   temps= " << ParaGlob::Variables_de_temps().TempsCourant();
    // on montre les noeuds actuellement en contact
    if (niveau_commentaire_lescontacts > 5)
     {cout << "\n >> bilan des noeud(s) actuellement en contact: ";
      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
         {if (niveau_commentaire_lescontacts > 4)
             { Noeud* no = tesc(inesc);
//               int n_noee = no->Num_noeud();
               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 ";
                if (tesN_collant(num_mail_noe_esclave)(j)(inesc)) cout << " collant ";
               }
               else {cout << "\n --> noeud actuellement pas en contact ";};
               cout << flush;
            };
        };
      };
     };
    if (niveau_commentaire_lescontacts > 4)
        // on va lister les éléments de contact
       { cout << "\n 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);};
       };

    // on met à jour les boites des éléments qui contiennent les frontières
    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	 
	   { // ++ 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
//                int num_mail = (*iE).Esclave()->Num_Mail();
//                int num_noeud = (*iE).Esclave()->Num_noeud();
//                tesN_encontact(num_mail)(num_noeud) += 1; // mise à jour de l'indicateur
                (*iE).Met_actif();
                if (niveau_commentaire_lescontacts > 3)
                 { Element & elem = *(*iiE).Elfront()->PtEI();
                   int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                   cout << "\nreactivation (dans newcontact) contact: ";
                   (*iiE).Affiche(1); cout << endl;
                 };
			           }
		          else
			           { // sinon on supprime car il n'y a pas de contact
		              iE--; // pointe sur le precedent element
                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 (dans newcontact): ";
                   (*iiE).Affiche(1);cout << endl;
                 };
                listContact_efface_tatdt.push_front(*iiE); // mémorise
                #ifdef MISE_AU_POINT
                  if (tesN_encontact((*iiE).Esclave()->Num_Mail()).find((*iiE).Esclave())
                        == tesN_encontact((*iiE).Esclave()->Num_Mail()).end() )
                   { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
                          << (*iiE).Esclave()->Num_noeud()
                          << " du maillage " << (*iiE).Esclave()->Num_Mail()
                          << " 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((*iiE).Esclave()->Num_Mail())[(*iiE).Esclave()];
//                tesN_encontact(num_mail_esclave)(num_noeud).remove(iiE);
                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
    bool 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;    //            "     "       "
    for (int jjf=1;jjf<=nbmailMaitre;jjf++)
     for (int j=1;j<= nb_zone;j++)
      { iMfin=(t_listFront(jjf)(j)).end();
        // tout d'abord on met à jour les boites d'encombrement des éléments frontière
        for (iM = (t_listFront(jjf)(j)).begin() ; iM != iMfin; iM++)
           (*iM).Boite_encombrement_frontiere(TEMPS_tdt,dep_max);
      };       
    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];
//          LaLIST < LaLIST<ElContact>::iterator >::iterator pl,plfin=list_tesN.end();
          nb_contact = list_tesN.size();
         };
        if (niveau_commentaire_lescontacts > 5)
          { cout << "\n (re) examen eventuel : contact du noeud  " << n_noee << " du maillage " << num_mail_noe_esclave;
            cout << " coord2= "; no->Coord2().Affiche_1(cout);
            if (niveau_commentaire_lescontacts > 5)
             {cout << " num_mail_dans_contact = " << num_mail_noe_esclave <<" inesc(num N local)= " << inesc
//                 << "\n  tesN_encontact= " << tesN_encontact(num_mail_noe_esclave)(n_noee).size()
                 << "\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;
          };
 	
        {
          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

              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() > 5)
                      {cout << "\n noeud esclave deja en contact "; elc.Affiche(1);
                      };
                    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
                // 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);
                if (niveau_commentaire_lescontacts > 5)
                  {// --- sortie d'info pour vérifier l'appartenance  à la boite ou non
                     cout << "\n 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 (niveau_commentaire_lescontacts > 5)
                  { cout  << "\n 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;};
//                   };

                  if (niveau_commentaire_lescontacts > 5)
                    {//cout << "\n 2debug LesContacts::Nouveau( " ;
                     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)
                               { cout << "\n 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);
                          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

                          // 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();
                              cout  << "\n 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() ;
                              if (niveau_commentaire_lescontacts > 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))
                                 { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                                   cout << "\n 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
    if (niveau_commentaire_lescontacts > 3)
      { cout << "\nbilan: "<< listContact.size() << " elem 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) ";
        cout << "\n <== fin LesContacts::Nouveau " ;
      };
    if (niveau_commentaire_lescontacts > 4)
          // on va lister les éléments de contact
         { cout << "\n 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);};
         };

      
    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();
  if (niveau_commentaire_lescontacts > 4)
      cout << "\n -- LesContacts::SuppressionDefinitiveElemInactif: ";
  bool change = false;
  int nb_effacement=0;
//    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 suppressions
  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)
       cout << "\n sup: "<< nb_effacement << " effacement(s) definitif(s) de contact ";
   };
 if ((niveau_commentaire_lescontacts > 6) && (nb_effacement==0))
      cout << " aucun effacement ";

  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();
  if (niveau_commentaire_lescontacts > 4)
      cout << "\n -- LesContacts::RelachementNoeudcolle(): ";
  bool change = false;
//    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;
          int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
          int num_noeud = (*iiE).Esclave()->Num_noeud();
          if (niveau_commentaire_lescontacts > 2)
                 { Element & elem = *(*iiE).Elfront()->PtEI();
                   int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                   cout << "\ninactivation (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 ";
 
  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
const Tableau <Condilineaire>&  LesContacts::ConditionLin(const Nb_assemb& casAssemb)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   // 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
//	  if (ParaGlob::param->ParaAlgoControleActifs().ContactType() == 1)
// definition du tableau
//     int tail =  listContact.size();//(int) listContact.size();
//     tabCoLin.Change_taille(tail);
     {Calcul_Nb_contact_actif();
      tabCoLin.Change_taille(nb_contact_actif);
//cout << "\n nb actif pour condlin = " << nb_contact_actif;
      // on boucle sur les elements de contact
      int i=1;
      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
       {tabCoLin(i) = (*iE).ConditionLi(casAssemb.n);i++;
//cout << " i="<<i;			
       };
     }
//   else
//     { tabCoLin.Change_taille(0);};

   tempsContact.Arret_du_comptage(); // fin cpu
	  // retour du tableau
	  return tabCoLin;		 
 };
      
// 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 le tableau des conditions lineaires
    int tailletabcolin = tabCoLin.Taille();
    for (int i=1;i<=tailletabcolin;i++)
      { // on libere la condition
        Condilineaire& C = tabCoLin(i); 
        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 nb_maitre = t_listFront.Taille(); // le nombre de maîtres
   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)
bool LesContacts::Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb,int& cumule)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   // 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;
   bool retour = false; // par défaut on se met dans le cas le plus simple : contact avec surface rigide
   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
   // 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)
bool LesContacts::Actualisation(int choix)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   bool retour = false; // init par défaut
   // 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)
      cout << "\n -- LesContacts::Actualisation: choix: "<< choix;
   if (niveau_commentaire_lescontacts > 4)
      // on va lister les éléments de contact
     { cout << "\n liste des Elcontact avant 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);};
     };

   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;
                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 << "\ninactivation 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) il 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;
                 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 << "\ninactivation 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)
                  { Element & elem = *(*iE).Elfront()->PtEI();
                    int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                    cout << "\n 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();
               int nb_contact = list_tesN.size();
               for (pl = list_tesN.begin();pl != plfin;pl++)
                 {ElContact& elc = (*(*pl));
                  // 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
                  bool actif_transitoire = true;
                  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
                    { actif_transitoire=false; // active l'élément
                      if (niveau_commentaire_lescontacts > 2)
                        { Element & elem = *(*iE).Elfront()->PtEI();
                          int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
                          cout << "\nreactivation contact :";elc.Affiche(1);
                          
                        };
                    }
                  else // sinon on inactive l'élément   ;
                   elc.Met_Inactif();
                 };
              };

            }
         };
		    }
//		   else
//		    {nb_contact_actif++; }; // on sauvegarde l'activité
   if (niveau_commentaire_lescontacts > 4)
      // on va lister les éléments de contact
     { cout << "\n 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);};
       // on calcule et affiche le nombre de contact actif
       Calcul_Nb_contact_actif();
       cout << "\n nb_contact_actif= " << nb_contact_actif << endl;
     };
   // 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
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
  
   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();
     
      int niveau_commentaire_lescontacts = Permet_affichage();
      if (niveau_commentaire_lescontacts >= 7)
         cout << "\n -- LesContacts::Liste_noeuds_position_changer: ";

      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
 };

// calcul des reactions de contact et stockage des valeurs
// solution : le vecteur residu
// test d'un decollement eventuelle, pour un noeud en contact
void LesContacts::CalculReaction(Vecteur& residu,bool& decol,const Nb_assemb& casAssemb
                                 ,bool affiche)
 {
   tempsContact.Mise_en_route_du_comptage(); // def deb compt
   int niveau_commentaire_lescontacts = Permet_affichage();
   if (niveau_commentaire_lescontacts > 4)
      cout << "\n -- LesContacts::CalculReaction: ";
   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 )
			        { cout << "\nErreur : 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 )
                { cout << "\nErreur : 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
void LesContacts::Affiche(ofstream& sort) const 
  { // 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
void LesContacts::Affiche() const      
  { cout << "\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)
{  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
void LesContacts::Lecture_zone_contact(UtilLecture & entreePrinc,const LesReferences& lesRef)
{ 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)
            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)
         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) 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)))
               { 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
              { 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) 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) 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) 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;};
};



