
// 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"
#include "FrontPointF.h"




// récupération des ddl ou des grandeurs actives de tdt vers t 
void LesContacts::TdtversT()
	{  LaLIST <ElContact>::iterator il,ilfin=listContact.end();
    for (il=listContact.begin();il != ilfin; il++)
          (*il).TdtversT();
    // on nettoie les indicateurs transitoires
    listContact_nouveau_tatdt.clear();
    listContact_efface_tatdt.clear();
	};

// actualisation des ddl et des grandeurs actives de t vers tdt      
void LesContacts::TversTdt()
	{  // on essaie de mettre la situation de contact comme elle était à t
    // a) on supprime les nouveaux contacts
    {LaLIST <LaLIST <ElContact>::iterator>::iterator al,alfin=listContact_nouveau_tatdt.end();
     for (al=listContact_nouveau_tatdt.begin();al != alfin; al++)
       { ElContact& elc = (*(*al));
         Noeud* no = elc.Esclave();
         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::TversTdt(.. \n";
              Sortie(1);
            };
         #endif
         LaLIST < LaLIST<ElContact>::iterator >  & list_tesN
                            = tesN_encontact(num_mail_noe_esclave)[no];
         list_tesN.remove(*al);
//         tesN_encontact(num_mail_noe_esclave)(n_noee).remove(*al);
         listContact.erase(*al);
// cout << "\n debug toto ";
        };
    };
    // b) on rajoute les contacts supprimés
    {LaLIST <ElContact>::iterator al,alfin=listContact_efface_tatdt.end();
     for (al=listContact_efface_tatdt.begin();al != alfin; al++)
       { ElContact& elc = (*al);
         Noeud* no = elc.Esclave();
         int n_noee = no->Num_noeud();
         int num_mail_noe_esclave = no->Num_Mail();
         #ifdef MISE_AU_POINT
          if (Element_contact_deja_present(*al))
            { cout << "\n*** Erreur : l'element de contact existe déjà, ce n'est pas normal "
                 << (*al).Esclave()->Num_noeud()
                 << " du maillage " << (*al).Esclave()->Num_Mail()
                 << " la suite n'est pas possible "
                 << " LesContacts::TversTdt(.. \n";
              tempsContact.Arret_du_comptage(); // fin cpu
              Sortie(1);
            };
         #endif
         listContact.push_front(*al);
         // on met à jour le tableau tesN_encontact
         #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::TversTdt(.. \n";
              Sortie(1);
            };
         #endif
         tesN_encontact(num_mail_noe_esclave)[no].push_front(listContact.begin());
        };
    };
    // c) on nettoie les indicateurs transitoires
    listContact_nouveau_tatdt.clear();
    listContact_efface_tatdt.clear();
    // d) on revient à t pour les éléments en contact
    {LaLIST <ElContact>::iterator il,ilfin=listContact.end();
     for (il=listContact.begin();il != ilfin; il++)
          (*il).TversTdt();
    };
    Calcul_Nb_contact_actif();
    if ((ParaGlob::NiveauImpression() > 4)  || (Permet_affichage() > 4 ))
        cout << "\n >> LesContacts::TversTdt : nb contact actif = "<< nb_contact_actif  << endl ;
	};
	 
		
// cas d'une méthode avec pénalisation: calcul éventuel d'un pas de temps idéal, 
// si oui retour de la valeur delta_t proposé
// sinon dans tous les autres cas retour de 0.
// le calcul se fait en fonction du pas de temps courant et de la pénétration
// donc nécessite que le contact ait déjà été étudié 
double LesContacts::Pas_de_temps_ideal()const
{ double delta_optimal=ConstMath::tresgrand;
  // on passe en revue tous les contacts
  LaLIST <ElContact>::const_iterator il,ilfin=listContact.end();
	 for (il=listContact.begin();il != ilfin; il++)
	   { double dtelem_optimal = (*il).Pas_de_temps_ideal();
		    if (dtelem_optimal != 0.)
		      delta_optimal = MiN(delta_optimal, dtelem_optimal);		
		  };
  // retour du temps proposé
  if (delta_optimal==ConstMath::tresgrand)
    // cela veut dire qu'il n'a pas été modifié, on le met à 0 pour indiquer que l'on a rien
	 // n'a proposer
	 delta_optimal = 0.; 
  return delta_optimal;
};

//   écriture base info   
// cas donne le niveau de sauvegarde
void LesContacts::Ecri_base_info_LesContacts(ofstream& sort)
  { // globalement on sauvegarde toujours tout, car les éléments de contact peuvent apparaître à tout moment
    // tout d'abord on indique le type
    sort << "\n LesContacts: taille " << listContact.size() << "  " ;
		  // NB: le nombre de maillages esclave et en auto-contact, peut-être redéfinit lors d'un restart
		  // donc n'est pas sauvegardé
    // ensuite on sauvegarde la liste des éléments de contact: en fait tout d'abord les infos
	   // qui permettent de construire un élément ad hoc, et ensuite les infos spécifiques internes à l'élément
    for (LaLIST <ElContact>::iterator ic = listContact.begin();ic != listContact.end(); ic++)
      {// les infos permettants de contruire l'élément de contact: on considère que les numéros des noeuds, maillages, éléments
       // restent identiques, par contre on peut avoir un échange des zones de restriction de contact d'une sauvegarde à un restart
       sort << "\nN_es " << (*ic).Esclave()->Num_Mail() <<" " << (*ic).Esclave()->Num_noeud();  // le noeud esclave
       Front * elfront = (*ic).Elfront();
       sort << " El " << elfront->NumMail() << " " << elfront->PtEI()->Num_elt_const() << " "
            <<  elfront->Eleme()->Type_geom_front()  << " "<< elfront->Num_frontiere() ; // la frontière
       // les infos spécifiques éventuelles
       (*ic).Ecri_base_info_ElContact(sort);
      };
    sort << "\n tps_rech_contact: "<<tempsContact;
  };


  // Il s'agit ici de mettre à jour les conteneurs stockés aux noeuds et/ou aux éléments
  // qui servent à récupérer les infos liés aux contact correspondant à liTQ
  // actuellement les conteneurs passés en paramètre ne servent que pour
  // les énumérés, et les informations résultantes sont stockées au niveau des noeuds
  // constituant les éléments de contact
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  //--> important : les conteneurs sont supposés initialisés avec l'appel
void LesContacts::Mise_a_jour_Pour_Grandeur_particuliere(
                                List_io < TypeQuelconque >& li_restreinte_TQ
                               )
{
   LaLIST<ElContact>::iterator ili_deb= listContact.begin();
   LaLIST<ElContact>::iterator ilifin= listContact.end();
   LaLIST<ElContact>::iterator ili;

   // on passe en revue la liste de quelconque
  {List_io<TypeQuelconque>::iterator itq,itqfin=li_restreinte_TQ.end();
   for (itq=li_restreinte_TQ.begin();itq!=itqfin;itq++)
     {const TypeQuelconque_enum_etendu& enuTypeQuelconque = (*itq).EnuTypeQuelconque();
      if (enuTypeQuelconque.Nom_vide()) // veut dire que c'est un enum pur
       switch (enuTypeQuelconque.EnumTQ())
       {  case NOEUD_PROJECTILE_EN_CONTACT:
           {//  ----- cas des noeuds projectiles en contact
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              // on attribue une grandeur arbitraire de 100 aux noeuds pour un  contact actif
              // pour les éléments de contact inactif -> -0.1
              // un noeud peut être plusieurs fois en contact -> les nombres sont cumulées
              // on fait l'hypothèse qu'un ne sera jamais inactif plus de 99 fois, du coup
              // en regardant le nombre modulo 100 on peut en déduire le nombre d'inactivité
              // et en regardant le nombre de centaine on en déduit le nombre de contact
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += 100.; }
              else
               {*(tyTQ.ConteneurDouble()) -= 0.1; }
             };
            break;
           }
          case NOEUD_FACETTE_EN_CONTACT:
           {//  ----- cas des noeuds facettes en contact
            // on parcours la liste des éléments de contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              // on attribue une grandeur arbitraire de 100 aux noeuds pour un  contact actif
              // pour les éléments de contact inactif -> -0.1
              // un noeud peut être plusieurs fois en contact -> les nombres sont cumulées
              // on fait l'hypothèse qu'un ne sera jamais inactif plus de 99 fois, du coup
              // en regardant le nombre modulo 100 on peut en déduire le nombre d'inactivité
              // et en regardant le nombre de centaine on en déduit le nombre de contact
              Tableau <Noeud*>& tablN = elcont.TabNoeud();
              int NBNF=tablN.Taille();
              // on boucle sur les noeuds de la facette (le premier noeud = noeud esclave)
              if (elcont.Actif())
               {for (int i=2;i<=NBNF;i++)
                 {TypeQuelconque& tyqN = tablN(i)->ModifGrandeur_quelconque(enuTypeQuelconque);
                  Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
                  *(tyTQ.ConteneurDouble()) += 100.;
                 }
               }
              else
               {for (int i=2;i<=NBNF;i++)
                 {TypeQuelconque& tyqN = tablN(i)->ModifGrandeur_quelconque(enuTypeQuelconque);
                  Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
                  *(tyTQ.ConteneurDouble()) -= 0.1;
                 }
               };
             };
            break;
           }
          case PENETRATION_CONTACT:
           {//  ----- cas des noeuds projectiles en contact
            // on parcours la liste des élément en contact
            //  on cumule s'il y a plusieurs contacts
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {// on définit un vecteur au niveau du noeud en contact, qui part du noeud
                // projectile et va au point d'impact
                const Coordonnee& Mtdt = elcont.Point_intersection();
                *(tyTQ.ConteneurCoordonnee()) += Mtdt - elcont.Esclave()->Coord2();
               }; // sinon on ne fait rien
             };
            break;
           }
          case GLISSEMENT_CONTACT:
           {//  ----- cas des noeuds projectiles en contact
            // on parcours la liste des élément en contact
            //  on cumule s'il y a plusieurs contacts
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {// on définit un vecteur au niveau du noeud en contact, qui part du noeud
                // projectile et va au point d'impact
                *(tyTQ.ConteneurCoordonnee()) += elcont.Dep_tangentiel();
               }; // sinon on ne fait rien
             };
            break;
           }
          case NORMALE_CONTACT:
           {//  ----- cas des noeuds projectiles en contact
            // on parcours la liste des élément en contact
            //  on cumule s'il y a plusieurs contacts
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {// on définit un vecteur au niveau du noeud en contact, qui part du noeud
                // projectile et va au point d'impact
                *(tyTQ.ConteneurCoordonnee()) += elcont.Normale_actuelle();
               }; // sinon on ne fait rien
             };
            break;
           }
//          case N_FRONT:
//           {//  ----- cas des noeuds projectiles en contact
//            // on parcours la liste des élément en contact
//            //  on cumule s'il y a plusieurs contacts
//            for (ili=ili_deb;ili!=ilifin;ili++)
//             {ElContact & elcont = (*ili); // pour simplifier
//              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
//              Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
//                                                     tyqN.Grandeur_pointee());
//              // on récupère la normale au noeud projectile
//              *(tyTQ.ConteneurCoordonnee()) = elcont.Normale_actuelle();
//             };
//            break;
//           }
          case FORCE_CONTACT:
           {//  ----- cas des noeuds projectiles en contact
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_coordonnee& tyTQ= *((Grandeur_coordonnee*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {// on récupère la force de contact
                *(tyTQ.ConteneurCoordonnee()) += elcont.Force_contact();
               }; // sinon on ne fait rien
             };
            break;
           }
          case CONTACT_PENALISATION_N:
           {//  ----- on attribue la pénalisation au noeud projectile
            //  on met la pénalisation totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Penalisation(); };
             };
            break;
           }
          case CONTACT_PENALISATION_T:
           {//  ----- on attribue la pénalisation au noeud projectile
            //  on met la pénalisation totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Penalisation_tangentielle(); };
             };
            break;
           }
          case CONTACT_ENERG_PENAL:
           {//  ----- on attribue l'énergie de pénalisation au noeud projectile
            //  on met l'énergie totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.EnergiePenalisation(); };
             };
            break;
           }
          case CONTACT_ENERG_GLISSE_ELAS:
           {//  ----- on attribue l'énergie de pénalisation au noeud projectile
            //  on met l'énergie totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().EnergieElastique(); };
             };
            break;
           }
          case CONTACT_ENERG_GLISSE_PLAS:
           {//  ----- on attribue l'énergie de pénalisation au noeud projectile
            //  on met l'énergie totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().DissipationPlastique(); };
             };
            break;
           }
          case CONTACT_ENERG_GLISSE_VISQ:
           {//  ----- on attribue l'énergie de pénalisation au noeud projectile
            //  on met l'énergie totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.EnergieFrottement().DissipationVisqueuse(); };
             };
            break;
           }
          case CONTACT_NB_DECOL:
           {//  ----- on attribue le nombre de décolement au noeud projectile
            //  on met le totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Nb_decol(); };
             };
            break;
           }
          case CONTACT_COLLANT:
           {//  ----- on attribue le fait d'être collant ou pas au noeud projectile
            //  on met le totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Collant(); };
             };
            break;
           }
          case NUM_ZONE_CONTACT:
           {//  ----- on attribue le numéro de zone de contact au noeud projectile
            //  on met le totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Num_zone_contact(); };
             };
            break;
           }
          case CONTACT_NB_PENET:
           {//  ----- on attribue le nombre de décolement au noeud projectile
            //  on met le totale s'il y a plusieurs contacts
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) += elcont.Nb_pene(); };
             };
            break;
           }
          case CONTACT_CAS_SOLIDE:
           {//  ----- on attribue le nombre au noeud projectile
            // =0 contact bi déformable, =1 le noeud est libre et la frontière est bloqué (solide)
            // = 2 le noeud est bloqué (solide) la frontière est libre
            // = 3 tout est solide

            //  ici on ne met pas le totale s'il y a plusieurs contacts !!
            // c'est le dernier élément qui contient le noeud projectile, qui donne le résultat
            
            // on parcours la liste des élément en contact
            for (ili=ili_deb;ili!=ilifin;ili++)
             {ElContact & elcont = (*ili); // pour simplifier
              TypeQuelconque& tyqN = elcont.Esclave()->ModifGrandeur_quelconque(enuTypeQuelconque);
              Grandeur_scalaire_double& tyTQ= *((Grandeur_scalaire_double*)
                                                     tyqN.Grandeur_pointee());
              if (elcont.Actif())
               {*(tyTQ.ConteneurDouble()) = elcont.Cas_solide(); };
             };
            break;
           }

          default: ;// on ne fait rien
       };

	    };
   };
 

};
   
// récupération de la liste de tous les grandeurs particulières disponibles avec le contact
// cette liste est identique quelque soit le maillage: il n'y a donc pas de tableau indicé du num de maillage
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
List_io<TypeQuelconque> LesContacts::ListeGrandeurs_particulieres(bool absolue) const
 {
  // def de la liste de retour
  List_io <TypeQuelconque> liTQ;
  
  // on ne ramène les infos que si le contact est actif
  if (ParaGlob::param->ParaAlgoControleActifs().ContactType()!= 0)
    {
      // grandeurs de travail
      int dim = ParaGlob::Dimension();
     
      // ici on est en 3D et les grandeurs sont par principe en absolue, donc la variable absolue ne sert pas
      Grandeur_scalaire_double grand_courant(0.);
      
      Coordonnee  inter(dim);
      Grandeur_coordonnee   grand_coor_courant(inter);
      
      // def d'un type quelconque représentatif à chaque grandeur
      // a priori ces grandeurs sont défini aux noeuds
      //on regarde si ce type d'info existe déjà: si oui on augmente la taille du tableau, si non on crée
      // $$$  cas de la visualisation des noeuds projectiles en contact
      {TypeQuelconque typQ1(NOEUD_PROJECTILE_EN_CONTACT,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      // $$$  cas de la visualisation des noeuds des facettes en contact
      {TypeQuelconque typQ1(NOEUD_FACETTE_EN_CONTACT,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      // $$$  cas de la visualisation du glissement des noeuds projectiles actifs
      {TypeQuelconque typQ1(GLISSEMENT_CONTACT,X1,grand_coor_courant);
       liTQ.push_back(typQ1);
      };
      // $$$  cas de la visualisation de la normale de contact (moyenne)
      {TypeQuelconque typQ1(NORMALE_CONTACT,X1,grand_coor_courant);
       liTQ.push_back(typQ1);
      };
//      // $$$  cas de la visualisation de la normale aux noeuds frontières
//      {TypeQuelconque typQ1(N_FRONT,X1,grand_coor_courant);
//       liTQ.push_back(typQ1);
//      };
      // $$$  cas de la visualisation de la pénétration en contact
      {TypeQuelconque typQ1(PENETRATION_CONTACT,X1,grand_coor_courant);
       liTQ.push_back(typQ1);
      };
      // $$$  cas de la visualisation des forces de contact
      {TypeQuelconque typQ1(FORCE_CONTACT,X1,grand_coor_courant);
       liTQ.push_back(typQ1);
      };
      //  $$$ nombre de pénétration
      {TypeQuelconque typQ1(CONTACT_NB_PENET,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      //  $$$ nombre de décolement
      {TypeQuelconque typQ1(CONTACT_NB_DECOL,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      //  $$$ cas_solide
      {TypeQuelconque typQ1(CONTACT_CAS_SOLIDE,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_ENERG_PENAL,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_ELAS,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_PLAS,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_ENERG_GLISSE_VISQ,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_PENALISATION_N,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_PENALISATION_T,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
      {TypeQuelconque typQ1(CONTACT_COLLANT,X1,grand_courant);
       liTQ.push_back(typQ1);
      };
     {TypeQuelconque typQ1(NUM_ZONE_CONTACT,X1,grand_courant);
      liTQ.push_back(typQ1);
     };
    };
  
  // retour
  return liTQ;

 };


  // concernant les grandeurs gérées par le contact:
  // ramène une liste d'enuméré correspondant aux List_io<TypeQuelconque> passé en paramètre
  // idem pour une List_io < Ddl _enum_etendu >
void LesContacts::List_reduite_aux_contact(const List_io<TypeQuelconque>& liTQ
                                            ,List_io < TypeQuelconque >& li_restreinte_TQ
                                           )
  {
   // initialisation des listes de retour
   li_restreinte_TQ.clear();
   // on passe en revue la liste
   List_io<TypeQuelconque>::const_iterator itq,itqfin=liTQ.end();
   for (itq=liTQ.begin();itq!=itqfin;itq++)
     {const TypeQuelconque& tipParticu = (*itq); // pour simplifier
      const TypeQuelconque_enum_etendu& enuTypeQuelconque = tipParticu.EnuTypeQuelconque();
      if (enuTypeQuelconque.Nom_vide()) // veut dire que c'est un enum pur
       switch (enuTypeQuelconque.EnumTQ())
       {  case NOEUD_PROJECTILE_EN_CONTACT:  case NOEUD_FACETTE_EN_CONTACT:
          case PENETRATION_CONTACT:          case FORCE_CONTACT:
          case CONTACT_PENALISATION_N:       case CONTACT_PENALISATION_T:
          case CONTACT_ENERG_PENAL:          case NORMALE_CONTACT:
          case GLISSEMENT_CONTACT:           case CONTACT_ENERG_GLISSE_ELAS:
          case CONTACT_ENERG_GLISSE_VISQ:    case CONTACT_ENERG_GLISSE_PLAS:
          case CONTACT_NB_DECOL:             case CONTACT_NB_PENET:
          case CONTACT_CAS_SOLIDE:           case CONTACT_COLLANT:
          case NUM_ZONE_CONTACT:             //case N_FRONT :
           {//  ----- cas des noeuds projectiles en contact
            li_restreinte_TQ.push_front(TypeQuelconque(tipParticu));
            break;
           }
          default: ;// on ne fait rien
       };
     };
  };

// initialisation des listes de grandeurs qu'ils faudra transférérer aux niveaux des noeuds des élements
// de contact, on définit si besoin, les conteneurs ad hoc au niveau des noeuds
void LesContacts::Init_Grandeur_particuliere (bool absolue,List_io<TypeQuelconque>& liTQ)
  {liQ_en_sortie = liTQ; // on récupère la liste --> sans doute que cela ne sert à rien

   LaLIST<ElContact>::iterator ili_deb= listContact.begin();
   LaLIST<ElContact>::iterator ilifin= listContact.end();
   LaLIST<ElContact>::iterator ili;

   // on passe en revue la liste
   List_io<TypeQuelconque>::iterator itq,itqfin=liTQ.end();
   //    on part du principe qu'il y a plus de noeuds en contact que de grandeur donc on fait une
   //    boucle externe sur les noeuds en contact:  on parcours la liste des noeuds en contact
   for (ili=ili_deb;ili!=ilifin;ili++)
    {ElContact& elcont = (*ili); // pour simplifier
     for (itq=liTQ.begin();itq!=itqfin;itq++)
      {TypeQuelconque& tipParticu = (*itq); // pour simplifier
       EnumTypeQuelconque enuTQ = tipParticu.EnuTypeQuelconque().EnumTQ();

       switch (enuTQ)
          { case NOEUD_PROJECTILE_EN_CONTACT:  case NOEUD_FACETTE_EN_CONTACT:
            case GLISSEMENT_CONTACT:           case PENETRATION_CONTACT:
            case FORCE_CONTACT:                case CONTACT_NB_PENET:
            case CONTACT_PENALISATION_N:       case CONTACT_PENALISATION_T:
            case CONTACT_NB_DECOL:             case CONTACT_CAS_SOLIDE:
            case CONTACT_ENERG_PENAL:          case CONTACT_COLLANT:
            case NUM_ZONE_CONTACT:             //case N_FRONT :
            case NORMALE_CONTACT:              case CONTACT_ENERG_GLISSE_ELAS:
            case CONTACT_ENERG_GLISSE_VISQ:    case CONTACT_ENERG_GLISSE_PLAS:
            
             {//  ----- cas des noeuds projectiles en contact
              elcont.Esclave()->AjoutUnTypeQuelconque(*itq); // ajout du conteneur
              break;
             }
            default: ; // sinon rien
          };
       };
    };

  } ;

//==========================  fonction protegee =============================

// mise à jour des boites d'encombrement pour les éléments qui contiennent une frontière
void LesContacts::Mise_a_jour_boite_encombrement_element_contenant_front()
 {
   list  <Element *>::iterator il,ilfin = liste_elemens_front.end();
   for (il = liste_elemens_front.begin();il!=ilfin;il++)
      (*il)->Boite_encombre_element(TEMPS_tdt);

 };

// suppression du gap de contact pour les noeuds "collant avec suppression de gap"
void LesContacts::Suppression_gap_pour_noeud_collant()
  {
    int niveau_commentaire_lescontacts = Permet_affichage();
    // on passe en revue les zones de contact et si nécessaire on supprime les gaps
    // sinon retour
    bool continuer = false; // init par défaut
    //     list <quatre_string_un_entier> nom_ref_zone_contact; // liste des noms de références des zones de contact
    list <quatre_string_un_entier>::iterator iu,iufin = nom_ref_zone_contact.end();
    for (iu = nom_ref_zone_contact.begin();iu != iufin; iu++)
     if ((*iu).n == 2)
       {continuer = true; break;};
    if (!continuer)
      return;
   
    // sinon il faut effectivement faire une suppression de gap
    if (niveau_commentaire_lescontacts > 2)
     cout << "\n >>>> Suppression_gap_pour_noeud_collant : ";
    // on va iterer sur les noeuds esclaves collants dont on veut supprimer le gap
    LaLIST_io <Front>::iterator iM,iMfin; // des itérator de travail
    int nb_zone = MaX(1,nom_ref_zone_contact.size());
    double dist_max =  Dabs(ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete());
   
    int tout_projeter = true; // init
    int boucle_maxi = 10; // 10 boucle maxi
    int boucle = 1;
    do
     { if (niveau_commentaire_lescontacts >2 )
           cout << "\n boucle : "<<boucle << flush;
       for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
        for (int j=1;j<=nb_zone;j++) // boucle sur les zones de contact
         {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();                   //  tab des noeuds esclaves à considérer
          int compteur_noeuds_projecte=0; // le nombre de noeuds qui sont projetés
          double le_maxi_des_distances_trouve = 0.;
          for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
           if (tesN_col(inesc) == 2 ) // cas noeud collant avec volonté de supprimer le gap
            { Noeud* noee = tesc(inesc); // pour simplifier
    //--- debug
   //if (noee->Num_noeud() == 5)
   // {cout << "\n arrivée au bon element ";
   // }
              const Coordonnee pt_esc = noee->Coord0(); // position du noeud esclave initial
              list <Coordonnee > list_P; // la liste des projetés
              list <LaLIST_io <Front>::iterator> li_pt_front_P; // liste sur les faces pour le debug
              for (int jlf=1;jlf<=nbmailMaitre;jlf++) // boucle sur les maillages maitres
               {//Tableau < Tableau < LaLIST_io <Front> > >  t_listFront;
                LaLIST_io <Front>& t_l_front = t_listFront(jlf)(j);
                iMfin=t_l_front.end();
                for (iM = t_l_front.begin() ; iM != iMfin; iM++) // boucle sur les front maitres
                 {// si c'est dans le volume de la frontière augmenté de la distance ad hoc on test
                  // plus précisément
                  if ((*iM).In_boite_emcombrement_front(pt_esc,dist_max))
                   {// on projete le noeud sur la frontière
                    Coordonnee P;
   ////--- debug
   //if ((noee->Num_noeud() == 5) && ((*iM).PtEI()->Num_elt()==367))
   // {cout << "\n arrivée au bon element ";
   //
   // }
   //{double Ndis = (P-pt_esc).Norme();
   // if (Ndis > 20)
   //   (*iM).Eleme()->Projection_normale(pt_esc,P);
   //}
   //-- fin debug

   // //----debug
   //{if ((noee->Num_noeud() == 12)
   //     && ((*iM).Num_frontiere() == 1) && ((*iM).PtEI()->Num_elt() == 3130))
   //    { cout << "\n debug : frontiere 1 de l'element 3130";}
   //}
   ////----fin debug

                    // si la projection est valide on enregistre
                    if ((*iM).Eleme()->Projection_normale(pt_esc,P))
                      { list_P.push_back(P);
                        li_pt_front_P.push_back(iM);
                      };
   //--- debug
   //{double Ndis = (P-pt_esc).Norme();
   // if (Ndis > 20)
   //   (*iM).Eleme()->Projection_normale(pt_esc,P);
   //}
   //-- fin debug
                  
                   };
                 };
               };
              // maintenant on va garder le plus proche
              bool projection_ok = false; // init
              if (list_P.size() != 0)
               {list <Coordonnee >::iterator il,ilfin=list_P.end();
                if (niveau_commentaire_lescontacts >5 )
                  {cout << "\n " << list_P.size() << " proj trouvees   "
                        << " Noe: "<<noee->Num_noeud()
                        << " mail: " <<  noee->Num_Mail() << " (zone"<<j<<")";
                  };
                Coordonnee M = pt_esc;  // init
                Coordonnee P(M); // la projection
                double distance =  dist_max;
                LaLIST_io <LaLIST_io <Front>::iterator>::iterator iface = li_pt_front_P.begin();
                LaLIST_io <LaLIST_io <Front>::iterator>::iterator iface_maxi ;
                for (il=list_P.begin(); il!= ilfin;il++,iface++)
                 { double Ndis = (M-(*il)).Norme();
                   if (niveau_commentaire_lescontacts >5 )
                     cout << " dist: "  << Ndis ;
                   if (Ndis < distance)
                    {P = (*il); distance = Ndis;
                     projection_ok = true; // au moins un nouveau point
                     iface_maxi = iface;
                    };
                 };
                // si la distance == 0., il n'y a pas à changer les coordonnées
                // car le point projeté == le point initial 
                if (distance > ConstMath::petit)
                 {// on change les coordonnées du noeud
                  noee->Change_coord0(P);
                  noee->Change_coord1(P);
                  noee->Change_coord2(P);
                  compteur_noeuds_projecte++;
                  tout_projeter=false;
                  if (distance > le_maxi_des_distances_trouve)
                    le_maxi_des_distances_trouve = distance;
                  if (niveau_commentaire_lescontacts >3 )
                     cout << "\n suppression gap=("<<distance<<") du noeud "<<noee->Num_noeud()
                          << " du maillage " <<  noee->Num_Mail() << " (zone "<<j<<")";
                  if (niveau_commentaire_lescontacts >4 )
                    {cout << "\n ancienne coordonnee "<< pt_esc
                          << " nouvelle " << P;
                     // dans le cas où iface_maxi a été attribué
                     if (projection_ok)
                       (*(*iface_maxi)).Affiche();
               
   ////--- debug
   //{
   //const Coordonnee pt_esc  = noee->Coord0();
   //Coordonnee PP;
   //(*(*iface_maxi)).Eleme()->Projection_normale(pt_esc,PP);
   //cout << "\n $$$ nouvelle coordonnees projetee "<< PP;
   //}
   ////-- fin debug

                    };
                 }
                else if (projection_ok)
                  // si on n'a pas de projection avec changement de position
                  // mais par contre on a quand même trouvé un projeté on enregistre
                 {compteur_noeuds_projecte++;};
               };
              if ((!projection_ok) && (boucle==1)) // au premier passage
               { if (niveau_commentaire_lescontacts >3 )
                   cout << "\n pas de projection trouvee donc de suppression gap du noeud "<<noee->Num_noeud()
                        << " du maillage" <<  noee->Num_Mail() << " (zone "<<j<<")";
               } ;
            }; //-- fin de la boucle sur inesc
          if (niveau_commentaire_lescontacts >2 )
           {if (compteur_noeuds_projecte)
                 cout << "\n zone: " << j <<", " << compteur_noeuds_projecte << " suppression(s) de gap, maxi_distance= "
                      << le_maxi_des_distances_trouve << "( passage"<<boucle<<")" ;
            int non_gap = tesc_taille-compteur_noeuds_projecte;
            if ((non_gap)&& (boucle==1)) // au premier passage
              cout << "\n  zone: " << j <<", *** attention pour "<<non_gap
                   << " noeud(s) pas de projection trouvee !! ";
           };
        }; //-- fin de la boucle sur intot
       boucle++;
     }
    while ((!tout_projeter) && (boucle < boucle_maxi));
//     Sortie(1);
  };

// récupération de la zone de contact d'un élément de contact existant
// c'est un peu lourdinge, mais l'avantage c'est que cela s'adapte à une situation qui
// a par exemple changé
// si en retour le numéro de zone = 0, cela signifie que le contact ne peut plus exister
int LesContacts::Recup_ref( ElContact& al)
 { int nb_zone = MaX(1,nom_ref_zone_contact.size());
   const Tableau <Noeud*>& tn = al.TabNoeud();
   int num_mail_esclave = tn(1)->Num_Mail();
   int num_mail_maitre = tn(2)->Num_Mail();
   int num_noe = tn(1)->Num_noeud();
  
   // on parcours la liste des frontières succeptibles d'entrer en contact
   // pour repérer la zone
   int num_zone = 0; // init
   int nb_maitre = t_listFront.Taille();
   int nb_esclave = tesctotal.Taille();
   for (int i=1;i<=nb_maitre;i++)
    {for (int j=1;j<=nb_zone;j++)
      {LaLIST_io <Front> & list_fronta = t_listFront(i)(j); // pour simplifier
       LaLIST_io <Front>::iterator il,ilfin = list_fronta.end();
       for (il = list_fronta.begin();il != ilfin; il++)
         {if ((*il)==(*al.Elfront()))
           // les deux pointeurs pointent sur la même frontière, donc
           // maintenant on regarde du coté des noeuds esclaves
           { for (int ie = 1; ie<=nb_esclave;ie++)
              {const Tableau <Noeud*>& tesc= tesctotal(i)(j); // pour simplifier la notation:
               int tesc_taille=tesc.Taille();                   //  tab des noeuds esclaves à considérer
               for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
                {if (tesc(inesc) == al.Esclave())
                  // les deux pointeurs pointent sur le même noeud, c'est ok
                  {num_zone = j; break;};
                };
               if (num_zone)
                 break;
              };
           };
          if (num_zone)
             break;
         };
       if (num_zone)
          break;
      };
     if (num_zone)
        break;
    };
   // retour des infos
   return num_zone;
 };


  // création d'un tableau de condition linéaire, correspondant à tous les éléments de contact en cours
  // qu'ils soient actifs ou pas (a prior cette méthode est conçu pour donner des infos relativement à la largeur
  // de bandes en noeuds due aux CLL)
  // chacune des condition ne contient "d'exploitable" que le tableau de noeuds associés à la CLL,
const Tableau <Condilineaire>&   LesContacts::ConnectionCLL()
   {
     // on boucle sur le tableau et pour chaque element on crée une condition lineaire
     int tabTaille = listContact.size();
     t_connectionCLL.Change_taille(tabTaille);
     // un tableau servant à la def de la CLL
     Tableau <Enum_ddl > t_enu(1); t_enu(1)=X1 ;
     LaLIST <ElContact>::const_iterator il,ilfin=listContact.end();
     int posi=1; // init pour le tableau
     for (il=listContact.begin();il != ilfin;il++,posi++)
      { const Tableau < Noeud *>& t_n = (*il).Const_TabNoeud();
        // on est dans le cas ou l'on connait les infos relatives uniquements aux noeuds, aux enum ddl
        t_connectionCLL(posi) = Condilineaire(t_enu, t_n);
      };

     // retour
     return t_connectionCLL;
   };


// récupère le nombre de contact actif et met à jour ce nombre
// normalement devrait toujours être correct mais ?? il y a quelque chose d'incorrecte quelque part
int LesContacts::Calcul_Nb_contact_actif()
  {  LaLIST <ElContact>::iterator il,ilfin = listContact.end();
     nb_contact_actif = 0; // init
     for (il = listContact.begin();il != ilfin; il++)
       if ((*il).Actif())
          nb_contact_actif++;
     return nb_contact_actif;
  };


// création du conteneur Fct_nD_contact
void LesContacts::Creation_Fct_nD_contact()
 {

  {// cas de la penalisation normale
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penalisationPenetration();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_penalisationPenetration = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la penalisation normale "
              << " le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_penalisationPenetration=NULL;};
  };

  {// cas fct_nD_penetration_contact_maxi
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penetration_contact_maxi();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_penetration_contact_maxi = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la  "
              << " penetration maxi, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_penetration_contact_maxi=NULL;};
  };
  
  {// cas Fct_nD_penetration_borne_regularisation
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penetration_borne_regularisation();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_penetration_borne_regularisation = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la "
              << " borne de regularisation, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_penetration_borne_regularisation=NULL;};
  };
  
  {// cas fct_nD_force_contact_noeud_maxi
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_force_contact_noeud_maxi();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_force_contact_noeud_maxi = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la "
              << " force de contact normale, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_force_contact_noeud_maxi=NULL;};
  };
  
  {// cas fct_nD_penalisationTangentielle
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_penalisationTangentielle();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_penalisationTangentielle = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la penalisation tangentielle "
              << " le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_penalisationTangentielle=NULL;};
  };
  
  {// cas fct_nD_tangentielle_contact_maxi
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_tangentielle_contact_maxi();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_tangentielle_contact_maxi = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage du "
              << " deplacement tangentiel maxi, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_tangentielle_contact_maxi=NULL;};
  };
  
  {// cas fct_nD_tangentielle_borne_regularisation
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_tangentielle_borne_regularisation();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_tangentielle_borne_regularisation = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la  "
              << " borne de regularisation tangentielle, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_tangentielle_borne_regularisation=NULL;};
  };
  
  {// cas fct_nD_force_tangentielle_noeud_maxi
   string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_force_tangentielle_noeud_maxi();
   if (nom_fct != "_")
     {// on va récupérer la fonction
      if (sauve_lesFonctionsnD->Existe(nom_fct))
       { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
         // sauvegarde
         fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi = pt_fonct;
       }
      else
       { cout << "\n *** erreur dans la definition de la fonction nD de pilotage de la  "
              << " force tangentielle maxi, le nom : " << nom_fct
              << " ne correspond pas a une fonction nD existante !! ";
         Sortie(1);
       };
     }
   else
     {fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi=NULL;};
  };
 
 {// cas fct_niveau_commentaire
  string nom_fct = ParaGlob::param->ParaAlgoControleActifs().Fct_niveau_commentaire_contact();
  if (nom_fct != "_")
    {// on va récupérer la fonction
     if (sauve_lesFonctionsnD->Existe(nom_fct))
      { Fonction_nD * pt_fonct = sauve_lesFonctionsnD->Trouve(nom_fct);
        // sauvegarde
        fct_nD_contact.fct_niveau_commentaire = pt_fonct;
      }
     else
      { cout << "\n *** erreur dans la definition de la fonction nD de pilotage du  "
             << " niveau de commentaire en contact, le nom : " << nom_fct
             << " ne correspond pas a une fonction nD existante !! ";
        Sortie(1);
      };
    }
  else
    {fct_nD_contact.fct_niveau_commentaire=NULL;};
 };
 
 // initialisation des conteneurs statique des fonction nD
 fct_nD_contact.Init_conteneur_statique();


 };

/*// mise à jour du stockage inter, pour prendre en
// compte une nouvelle numérotation des noeuds
void LesContacts::Prise_en_compte_nouvelle_numerotation_noeud()
 { //on va reconstruire ta_inverse
   int nb_zone = MaX(1,nom_ref_zone_contact.size());
   // on garde en mémoire les anciens numéros pour faire le pontage
   Tableau < Tableau < Tableau <int> > >  ta_inverse_old(ta_inverse);
  
   // on recherche les maxi des numéros de noeuds esclave, pour dimensionner ta_inverse !!
   Tableau < Tableau <int> > maxi_num_noe_esclave(nb_mail_Esclave); // init à 0
   for (int i=1;i<=nb_mail_Esclave;i++)
    {maxi_num_noe_esclave(i).Change_taille(nb_zone);
     for (int j=1;j<=nb_zone;j++)
      {const Tableau <Noeud*>& tesc= tesctotal(i)(j); // pour simplifier la notation:
       int tesc_taille=tesc.Taille();                   //  tab des noeuds esclaves à considérer
       int& max_num_esclave = maxi_num_noe_esclave(i)(j); // pour simplifier
       for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
           { Noeud* noee = tesc(inesc); // pour simplifier
             int num_noeud = noee->Num_noeud();
             if (num_noeud > max_num_esclave)
                 max_num_esclave = num_noeud;
           };
      };
    };
   // Maintenant on peut dimensionner ta_inverse
   for (int i=1;i<=nb_mail_Esclave;i++)
    {ta_inverse(i).Change_taille(nb_zone);
     for (int j=1;j<=nb_zone;j++)
      ta_inverse(i)(j).Change_taille(maxi_num_noe_esclave(i)(j),0);
    };

   // ensuite on va remplir  ta_inverse
   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:
        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
             ta_inverse(intot)(j)(noee->Num_noeud()) = inesc;
           };
       };
    };
  
   // on va créer un tableau de changement des numéros de noeuds
   Tableau < Tableau <int> > nouveau_Noe(nb_mail_Esclave);
   // on cherche la taille maxi
   Tableau <int>  maxi_maxi_num_noe_esclave(nb_mail_Esclave); // les maxis pour chaque maillage
   for (int i=1;i<=nb_mail_Esclave;i++)
    {int& max_max_esclave = maxi_maxi_num_noe_esclave(i) = 0; // init
     for (int j=1;j<=nb_zone;j++)
      {int& max_num_esclave = maxi_num_noe_esclave(i)(j); // pour simplifier
       if (max_num_esclave > max_max_esclave)
         max_max_esclave = max_num_esclave;
      };
    };
   // on balaie les anciens noeuds
   for (int i=1;i<=nb_mail_Esclave;i++)
    {nouveau_Noe(i).Change_taille(maxi_maxi_num_noe_esclave(i));
     Tableau <int>& nouveau_Noe_i = nouveau_Noe(i);
     for (int j=1;j<=nb_zone;j++)
      { Tableau <int> & ta_inverse_old_ij = ta_inverse_old(i)(j);
        Tableau <int> & ta_inverse_ij = ta_inverse(i)(j);
        int nbN = ta_inverse_old_ij.Taille();
        for (int k=1;k<= nbN;k++) // k c'est le numéro de l'ancien noeud
         {if (ta_inverse_old_ij(k) != 0)
           {for (int k2=1;k2<= nbN;k2++)
             { if (ta_inverse_old_ij(k) == ta_inverse_ij(k2))
                 {nouveau_Noe_i(k)=k2;break;};
             };
           };
         };
      };
    };
  
//  // maintenant on met à jour le tableau tesN_encontact
//  //     Tableau < Tableau < LaLIST < LaLIST<ElContact>::iterator > > >  tesN_encontact;
//  // on sauvegarde l'ancien
//  Tableau < Tableau < LaLIST < LaLIST<ElContact>::iterator > > >  tesN_encontact_old(tesN_encontact);
//  // et on fait la passation
//  for (int i=1;i<=nb_mail_Esclave;i++)
//   {Tableau <int>& nouveau_Noe_i = nouveau_Noe(i);
//    int nbn = tesN_encontact(i).Taille();
//    for (int j=1;j<=nbn;j++)
//     { tesN_encontact(i)(nouveau_Noe_i(j)) = tesN_encontact_old(i)(j);
//     };
//   };
  
  // on continue avec le tableau: liste pour chaque noeud, des éléments qui contient ce noeud
  // indice(i)(j) : = la liste des éléments qui contiennent le noeud j, pour le maillage i
  Tableau < const Tableau <List_io < Element* > > *>  indice_old(indice);
  int nb_mail = indice_old.Taille();
  for (int i=1;i<=nb_mail;i++)
   {if (indice_old(i) != NULL)
     { int nbn = indice_old(i)->Taille();
//       const Tableau <List_io < Element* > > & indice_i = indice(i);
//       for (int j=1;j<=nbn;j++)
//indice
     
     }
   
   }
cout << "\n LesContacts::Prise_en_compte_nouvelle_numerotation_noeud() pas terminé !!"
     << " il faut changer lesMaillages pour récupérer directement la nouvelle numérotation !!";
Sortie(1);

 };
*/


// récupération via les éléments de contact des forces maxis
// et affichage éventuel
// un : le maxi en effort normal, deux: le maxi en effort tangentiel
DeuxDoubles LesContacts::Forces_contact_maxi(bool affiche) const
 {DeuxDoubles retour;
 int niveau_commentaire_lescontacts = Permet_affichage();

  LaLIST <ElContact>::const_iterator iNmax,iTmax,il,ilfin = listContact.end();
  for (il = iNmax = iTmax = listContact.begin();il != ilfin; il++)
    if ((*il).Actif())
     { const ElContact& icont = (*il); // pour simplifier
       double fNmax =  icont.F_N_MAX();
       double fTmax =  icont.F_T_MAX();
       if (Dabs(fNmax) > Dabs(retour.un) )
         {retour.un = fNmax;iNmax = il;
         };
       if (Dabs(fTmax) > Dabs(retour.deux) )
         {retour.deux = fTmax;iTmax = il;
         };
     };
  if ((affiche && (ParaGlob::NiveauImpression() > 2))
      || (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
     )
      cout << "\n contact: reaction ==> F_N max " << retour.un << " F_T max " << retour.deux;
  if (niveau_commentaire_lescontacts > 6)
   {cout << "\n F_N max: "; (*iNmax).Affiche(0);
    cout << "\n F_T max: "; (*iTmax).Affiche(0);
    cout << "\n";
   }
  else if (niveau_commentaire_lescontacts > 3)
   {cout << "\n F_N max: "; (*iNmax).Affiche(1);
    cout << "\n F_T max: "; (*iTmax).Affiche(1);
    cout << "\n";
   };
  return retour;
 };

// récupération via les éléments de contact des gaps maxis
// un : le maxi en gap normal, deux: le maxi en gap tangentiel
DeuxDoubles LesContacts::Gap_contact_maxi(bool affiche) const
 {DeuxDoubles retour;
  LaLIST <ElContact>::const_iterator iNmax,iTmax,il,ilfin = listContact.end();
  for (il = iNmax = iTmax = listContact.begin();il != ilfin; il++)
    if ((*il).Actif())
     { const ElContact& icont = (*il); // pour simplifier
       double fNmax =  icont.Gaptdt();
       double fTmax =  icont.Dep_T_tdt();
       if (Dabs(fNmax) > Dabs(retour.un) )
         {retour.un = fNmax;iNmax = il;
         };
       if (Dabs(fTmax) > Dabs(retour.deux) )
         {retour.deux = fTmax;iTmax = il;
         };
     };
  int niveau_commentaire_lescontacts = Permet_affichage();
  if ((affiche && (ParaGlob::NiveauImpression() > 2))
      || (niveau_commentaire_lescontacts > 3) // spécifiquement pour le contact
     )
      cout << ", maxi gap_N : " << retour.un << " gap_T : " << retour.deux;
  if (niveau_commentaire_lescontacts > 6)
   {cout << "\n maxi gap_N : "; (*iNmax).Affiche(0);
    cout << "\n maxi gap_T : "; (*iTmax).Affiche(0);
   }
  else if (niveau_commentaire_lescontacts > 3)
   {cout << "\n maxi gap_N : "; (*iNmax).Affiche(1);
    cout << "\n maxi gap_T : "; (*iTmax).Affiche(1);
   };
  return retour;
 };


// création et ajout des éléments de frontière correspondant aux angles morts
// en 2D : noeud frontière + éléments interne
// en 3D : ligne frontière + éléments interne
void LesContacts::ElementAngleMort(LesMaillages& lesMail)
 {
 // la liste des éléments qui contiennent des frontières, est reconstitué au démarrage avec Init_contact(..
//>>>>> list  <Element *> liste_elemens_front;
 // la liste pour chaque noeud, des éléments qui contient ce noeud : construite avec Init_contact
 // indice(i)(j) : = la liste des éléments qui contiennent le noeud j, pour le maillage i
//>>>>> Tableau < const Tableau <List_io < Element* > > *>  indice;
  // la liste des éléments frontières succeptibles d'entrer en contact
  // ces Front (qui contiennent que des pointeurs sauf une boite d'encombrement)
  // sont différents de ceux des maillages, et sont donc stocké en interne
//>>>>>   Tableau < Tableau < LaLIST_io <Front> > >  t_listFront;
       // t_listFront(i)(j)(k) : maillage maître (i)
       //  zone de contact (j)
       // (K) = kième frontière (dans l'ordre de la liste)
       // ** pour le tableaux t_listFront, le numéros dit de maillage, n'est pas le numéro
       // ** intrinsèque de maillage (telle que ceux associés aux noeuds et éléments)
       // ** mais uniquement un numéro locale d'ordre
       // ** mais on a: les éléments de frontière de t_listFront(i) font partie du maillage
       // i + (nb_mail_Esclave-nbmailautocontact)
   int niveau_commentaire_lescontacts = Permet_affichage();
   if (niveau_commentaire_lescontacts > 4)
      cout << "\n ==> LesContacts::ElementAngleMort:   ";

   // --- à la fin du traitement on a besoin de mettre à jour les éléments mitoyens des Front
   // --- on sauvegarde des infos
   Tableau < Tableau < list <Front*> > >  t_listFront_initial; // les pointeurs de front initiaux sans les angles morts
   
   // t_liFront_noeud(i)(j)(k) : la liste des frontières initiales qui contiennent le noeud k de la zone j du maillage i
   Tableau < Tableau < Tableau < list <Front*> > > > t_liFront_noeud;
   t_liFront_noeud.Change_taille(lesMail.NbMaillage());
   //**** à faire la même chose pour les elements segment .....
   
   int tail1 = t_listFront.Taille(); // num ordre dans les maillages
   t_listFront_initial.Change_taille(tail1);
   for (int i =1;i<= tail1;i++)
    {int i_mail = i + (nb_mail_Esclave-nbmailautocontact); // le num de maillage
     int nb_noe_total = lesMail.Nombre_noeud(i_mail); // le nombre total de noeud du maillage
    
     int tail2=t_listFront(i).Taille(); // nombre de zones
     t_listFront_initial(i).Change_taille(tail2);
     t_liFront_noeud(i).Change_taille(tail2);
     
     for (int j=1;j<= tail2;j++) // on balaie les zones
      {list <Front*> & t_listFront_initial_ij = t_listFront_initial(i)(j); // pour simplifier
       LaLIST_io <Front> & t_listFront_ij = t_listFront(i)(j); // pour simplifier
       // on dimensionne au nombre maxi de noeud pour chaque zone ...
       // ça peut faire des gros tableaux mais il faut bien que l'on sache à quelle zone on s'intéresse ...
       // donc pour l'instant c'est l'idée que je retiens
       t_liFront_noeud(i)(j).Change_taille(nb_noe_total);
       Tableau <list <Front*> >& t_liFront_noeud_ij = t_liFront_noeud(i)(j);
       LaLIST_io <Front>::iterator il,ilfin=t_listFront_ij.end();
       for (il = t_listFront_ij.begin();il != ilfin; il++)
         {t_listFront_initial_ij.push_back(&(*il));
          // on va remplir t_liFront_noeud_ij
          ElFrontiere* elfro = (*il).Eleme(); // pour simplifier
          const Tableau <Noeud *>& tabN = elfro->TabNoeud_const();
          int nbNF = tabN.Taille();
          for (int l=1;l<=nbNF;l++)
            { Noeud * noe = tabN(l);
              t_liFront_noeud_ij(noe->Num_noeud()).push_back(&(*il));
            };
         };
      };
    };
       
   // --- constitution des front d'angle mort
   // l'idée est de rechercher les éléments qui sont en relation directe avec la frontière
   // via une ligne ou un point, mais qui n'ont été pris en compte du fait qu'ils n'étaient pas
   // reliés à une frontière de base
   // on commence par les lignes ce qui conduit éventuellement à augmenter t_listFront
   // ensuite on regarde les noeuds. Ainsi, si un élément nouveau est introduit via les lignes
   // les noeuds de la ligne + l'élément ne vont pas s'ajouter
       
   
      
   // 1) === cas des lignes frontières + éléments internes
   //        ce cas ne concerne que les espaces de travail 3D non axisymétrique
   if ((ParaGlob::Dimension() == 3) && !(ParaGlob::AxiSymetrie()))
     { // on crée les frontières lignes au cas où
       lesMail.CreeListFrontiere_ligne_3D();
       // on récupère toutes les frontières lignes
       // ramène le tableau de pointeurs de frontières ligne 3D créées par CreeListFrontiere_ligne_3D
       Tableau <LaLIST <Front>*>&  lifrLigne = lesMail.ListFront_ligne_3D();
       if (nom_ref_zone_contact.size() == 0)
        { // cas d'un contact non restreint
          // cela correspond finalement à une seule zone de contact (cf. Init_contact(..))
          //on boucle sur les maillages maitres de t_listFront
          for (int im=1;im<=nbmailMaitre;im++)
            { // ici on ne boucle pas sur les zones restreintes car il n'y en n'a pas
              LaLIST_io <Front> & la_list_des_front = t_listFront(im)(1);
              int nb_front_init = la_list_des_front.size(); // la taille initiale
              LaLIST <Front>& lifrLigne_mail = *lifrLigne(im); // pour simplifier

              // avant de balayer les lignes, on fait une liste des éléments qui contiennent des frontières déjà référencées
              list <const Element* > li_Elem_avec_front;
              LaLIST_io <Front>::iterator il,ilfin = la_list_des_front.end();
              for (il = la_list_des_front.begin(); il != ilfin; il++)
                li_Elem_avec_front.push_back((*il).PtEI());
              // on supprime les doublons et on ordonne, c'est pour l'opti des recherches ensuites
              li_Elem_avec_front.sort();  // ordonne
              li_Elem_avec_front.unique(); // supprime les doublons
              
              // maintenant on regarde s'il faut ajouter des éléments d'angle mort
              // on va boucler sur les frontières lignes 3D
              LaLIST <Front>::iterator jl,jlfin=lifrLigne_mail.end();
              for (jl = lifrLigne_mail.begin(); jl != jlfin; jl++)
               { Element * el = (*jl).PtEI();// récup de l'élément
                 // on regarde si cet élément ne fait pas partie de la liste d'élément
                 // qui contient déjà une frontière
                 if (find(li_Elem_avec_front.begin(),li_Elem_avec_front.end(),el) == li_Elem_avec_front.end())
                   // on n'a pas trouvé d'élément, on ajoute l'élément front
                   // on doit indiquer qu'il s'agit d'un élément d'angle mort
                   // on se sert d'un élément intermédiaire
                   {Front inter((*jl));
                    inter.Change_angle_mort(1);
                    la_list_des_front.push_back(inter);
                   };
               };
              int nb_front_fin = la_list_des_front.size(); // la taille finale
              if (niveau_commentaire_lescontacts >2 )
                  cout << "\n mail. maitre "<<im<<" : "<<(nb_front_fin-nb_front_init)
                       << " frontieres segment pour angle mort pour contact ";

            }; // fin de la boucle sur les maillages maitres
        }
       else
        { // cas d'une zone restreinte de contact
          // on va boucler sur les zones définies pour le contact
          //on boucle sur les maillages maitres de t_listFront
          for (int im=1;im<=nbmailMaitre;im++)
            { LaLIST <Front>& lifrLigne_mail = *lifrLigne(im); // pour simplifier
              // ici on boucle sur les zones restreintes
              int nb_zone_et1 = 1+t_listFront(im).Taille();
              for (int i_zone=1;i_zone < nb_zone_et1;i_zone++)
               {// la liste des front de la zone
                LaLIST_io <Front> & la_list_des_front = t_listFront(im)(i_zone);
                int nb_front_init = la_list_des_front.size(); // la taille initiale
                // avant de balayer les lignes, on fait une liste des éléments relatifs à la zone
                // qui contiennent des frontières déjà référencées
                list <const Element* > li_Elem_avec_front;
                LaLIST_io <Front>::iterator il,ilfin = la_list_des_front.end();
                for (il = la_list_des_front.begin(); il != ilfin; il++)
                  li_Elem_avec_front.push_back((*il).PtEI());
                // on supprime les doublons et on ordonne, c'est pour l'opti des recherches ensuites
                li_Elem_avec_front.sort();  // ordonne
                li_Elem_avec_front.unique(); // supprime les doublons
               
                // maintenant on regarde s'il faut ajouter des éléments d'angle mort
                // on va boucler sur les frontières lignes 3D
                LaLIST <Front>::iterator jl,jlfin=lifrLigne_mail.end();
                for (jl = lifrLigne_mail.begin(); jl != jlfin; jl++)
                 { Element * el = (*jl).PtEI();// récup de l'élément
                   // on regarde si cet élément ne fait pas partie de la liste d'élément
                   // qui contient déjà une frontière
                   if (find(li_Elem_avec_front.begin(),li_Elem_avec_front.end(),el) == li_Elem_avec_front.end())
                    // on n'a pas trouvé d'élément, on ajoute l'élément front
                    // on doit indiquer qu'il s'agit d'un élément d'angle mort
                    // on se sert d'un élément intermédiaire
                    {Front inter((*jl));
                     inter.Change_angle_mort(1);
                     la_list_des_front.push_back(inter);
                    };
                 };
                int nb_front_fin = la_list_des_front.size(); // la taille finale
                if (niveau_commentaire_lescontacts >2 )
                     cout << "\n mail. maitre "<<im << " : zone de contact: " << i_zone
                          <<" : " <<(nb_front_fin-nb_front_init)
                          << " frontieres segment pour angle mort pour contact ";
                 
               };// fin de la boucle sur les zones
            }; // fin de la boucle sur les maillages maitres de t_listFront
        };  // fin du test avec ou sans zone de contact
     };

   // 2) === maintenant on s'intéresse aux cas des noeuds frontières + éléments internes
   Tableau <LaLIST <Front>*>& listFrontiere = lesMail.ListFrontiere();
   int ntmail = listFrontiere.Taille(); // nb maxi de maillages
   // 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 (cf. Init_contact(..))
      
      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
      //on boucle sur les maillages maitres de t_listFront
      for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++,ilistfront++)
       {  // ici on ne boucle pas sur les zones restreintes car il n'y en n'a pas
          LaLIST_io <Front> & la_list_des_front = t_listFront(ilistfront)(1);
          int nb_front_init = la_list_des_front.size(); // la taille initiale
          // pour continuer il faut: 1) qu'il y a des front, 2) que ces fronts appartiennent au maillage
          if (nb_front_init > 0)
           if ((*la_list_des_front.begin()).NumMail() == jf )
            {
             // on va créer une liste de numéro des noeuds de la zone de frontière concernée
             // et en même temps
             // avant de balayer les noeuds, on fait une liste des éléments relatifs à la zone
             // qui contiennent des frontières déjà référencées
             list <int> num_noe_front;
             list <const Element* > li_Elem_avec_front;
             LaLIST_io <Front>::iterator il,ilfin = la_list_des_front.end();
             for (il = la_list_des_front.begin(); il != ilfin; il++)
              { const Tableau <Noeud *>& tnoe = (*il).Eleme()->TabNoeud_const();
                int nb_noe_et1 = tnoe.Taille();
                for (int m =1;m<nb_noe_et1;m++)
                  num_noe_front.push_back(tnoe(m)->Num_noeud());
                li_Elem_avec_front.push_back((*il).PtEI());
              };
             // on ordonne et on supprime les doublons
             num_noe_front.sort(); // ordonne
             num_noe_front.unique(); // suppression des doublons
             li_Elem_avec_front.sort();  // ordonne
             li_Elem_avec_front.unique(); // supprime les doublons
             
             // on définit une liste temporaire des nouvelles front d'angle mort créé
             // c'est utilisé pour définir les mitoyens des éléments d'angle morts
             // qui sont apparus avec les angles morts (== les mitoyens angle mort des éléments angle morts !!)
             list <Front *> front_angle_mort;

             // maintenant on parcours les noeuds contenu dans num_noe_front
             // et on regarde s'il faut ajouter des éléments point d'angle mort
             list <int>::iterator ih,ih_fin=num_noe_front.end();
             for (ih = num_noe_front.begin();ih != ih_fin;ih++)
               {int i_noe = (*ih); // le num du noeud maître que l'on va tester
                Tableau <Noeud *> ttn(1);
                ttn(1)= &(lesMail.Noeud_LesMaille(jf,i_noe)); // récup du pointeur de noeud
                   
                // récup de la liste pour le noeud i_noe, des éléments qui contient ce noeud : construite avec Init_contact
                const List_io < Element* >& liel = (*indice(jf))(i_noe);
                // on boucle sur chaque élément qui contient le noeud
                List_io < Element* >::const_iterator il,ilfin=liel.end();
                for (il = liel.begin();il != ilfin;il++)
                  {const Element* el=(*il); // pour simplifier
                   // on regarde si cet élément ne fait pas partie de la liste d'élément
                   // qui contient déjà une frontière
                   bool trouver = false;
                   list <const Element* >::const_iterator ikl,iklfin=li_Elem_avec_front.end();
                   for (ikl = li_Elem_avec_front.begin();ikl != iklfin; ikl++)
                     {if (((*ikl)->Num_elt_const() == el->Num_elt_const()) && ((*ikl)->Num_maillage() == el->Num_maillage()))
                       {trouver= true; break;}
                     };
                   if (!trouver)
                    {// on n'a pas trouvé d'élément,
                     // 1. on récup le num local EF du noeud
                     int nb_noeu_el_et_1 = 1+el->Nombre_noeud(); // le nombre de noeud de l'élément
                     int num_noe_local = 0;
                     for (int k =1;k<nb_noeu_el_et_1;k++)
                       if (el->Num_noeud(k) == ttn(1)->Num_noeud())
                         {num_noe_local=k; break;};
                     // 2. on récupère la frontière noeud correspondante en forçant une création éventuelle
                     // on passe par l'intermédiaire de lesMail pour pouvoir modifier l'élément
                     // car c'est l'élément qui stocke et gère la frontière
                     Element& elem_non_const = lesMail.Element_LesMaille(el->Num_maillage(), el->Num_elt_const());
                     // 3. on crée l'élément de frontière ad hoc
                     ElFrontiere* const elfpoint = elem_non_const.Frontiere_points(num_noe_local,true);
                     // ramene le numero de la frontière passée en argument si elle existe actuellement au niveau de l'élément
                     // sinon ramène 0
                     // ramene également type_front: qui indique le type de frontière: POINT_G, LIGNE ou SURFACE
                     // c'est une méthode très longue, a utiliser avec précaution
                     Enum_type_geom type_front;
                     int num_front = el->Num_frontiere(*elfpoint,type_front);
                     // 4. on crée l'élément front ad hoc et on l'ajoute à la liste
                     const DdlElement & ddlElem = el->TableauDdl(); // récup des ddl
                     int angle_mort = 1;
                     la_list_des_front.push_front(Front(*elfpoint,&elem_non_const,num_front,angle_mort));
                     LaLIST_io <Front>::iterator iik = la_list_des_front.begin(); // récup de l'iterator
                     // on met à jour les frontières mitoyennes
                     int num_noeud = ttn(1)->Num_noeud(); // le num global du noeud
                     // récup de la liste des frontières initiales contenant le noeud
                     list <Front*> & t_liFront_noeud_ijk = t_liFront_noeud(ilistfront)(1)(num_noeud);
                     list <Front*>::iterator km,kmfin=t_liFront_noeud_ijk.end();
                     for (km=t_liFront_noeud_ijk.begin();km != kmfin;km++)
                       {(*km)->AjoutMitoyen(&(*iik));// ajout frontière pour la frontière initiale
                        (*iik).AjoutMitoyen(*km); // ajout frontière pour la nouvelle frontière d'angle mort
                        };
                     // on sauvegarde le nouvelle front dans une liste spécifique
                     front_angle_mort.push_front(&(*iik));

                     if (niveau_commentaire_lescontacts >4 )
                      { cout << "\n ajout front point: noeud "<<el->Num_noeud(num_noe_local)
                             << " mail: " << jf //<< " zone "
                             << " element: "<<el->Num_elt_const() ;
                      };
                    };
                  };
              };
             int nb_front_fin = la_list_des_front.size(); // la taille finale
             if (niveau_commentaire_lescontacts >2 )
                  cout << "\n ajout angle mort pour contact: mail. maitre "<< jf <<" : "<<(nb_front_fin-nb_front_init)
                       << " frontieres point  ";
                       
             #ifdef MISE_AU_POINT
             // petite vérif en passant
             if ((nb_front_fin-nb_front_init) != front_angle_mort.size())
              {cout << "\n *** erreur dans la definition des elements point d'angle mort "
                    << " on a deux listes qui les representent mais qui n'ont pas la meme taille "
                    << (nb_front_fin-nb_front_init) << " et " << front_angle_mort.size()
                    << "\n LesContacts::ElementAngleMort(..";
               Sortie(1);
              };
             #endif

             // on utilise front_angle_mort pour définir les mitoyens angle mort des éléments angle morts
             list <Front *>::iterator ag,agfin=front_angle_mort.end();
             for (ag=front_angle_mort.begin();ag != agfin; ag++)
              {list <Front *>::iterator bg;
               bg = ag; bg++;
               // on utilise deux boucles imbriquées
               for ( ; bg!= agfin ; bg++)
                 {const Tableau <Noeud *>& tan = (*ag)->Eleme()->TabNoeud_const();
                  const Tableau <Noeud *>& tbn = (*bg)->Eleme()->TabNoeud_const();
                  // normalement c'est des FrontPoinF, donc il n'y a qu'un seul noeud frontière
                  if (tan(1)->Num_noeud() == tbn(1)->Num_noeud())
                   // les deux éléments FrontPoinF partage le même noeud,
                   // on met à jour les mitoyens
                   { (*ag)->AjoutMitoyen((*bg));
                     (*bg)->AjoutMitoyen((*ag));
                   };
                 };
              };
             
             }; // fin du test if (nb_front_init > 0) et if ((*la_list_des_front.begin()).NumMail() == jf )

        }; // fin de la boucle sur les maillages maitres de t_listFront
    }
   else
    { // cas d'une zone restreinte de contact
      // on va boucler sur les zones définies pour le contact
      
      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
      //on boucle sur les maillages maitres de t_listFront
      for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++,ilistfront++)
       {  // ici on boucle sur les zones restreintes
          int nb_zone_et1 = 1+t_listFront(ilistfront).Taille();
          for (int i_zone=1;i_zone < nb_zone_et1;i_zone++)
           {// la liste des front de la zone
            LaLIST_io <Front> & la_list_des_front = t_listFront(ilistfront)(i_zone);
            int nb_front_init = la_list_des_front.size(); // la taille initiale
            // pour continuer il faut: 1) qu'il y a des front, 2) que ces fronts appartiennent au maillage
            if (nb_front_init > 0)
             if ((*la_list_des_front.begin()).NumMail() == jf )
              {
               // on va créer une liste de numéro des noeuds de la zone de frontière concernée
               // et en même temps
               // avant de balayer les noeuds, on fait une liste des éléments relatifs à la zone
               // qui contiennent des frontières déjà référencées
               list <int> num_noe_front;
               list <const Element* > li_Elem_avec_front;
               LaLIST_io <Front>::iterator il,ilfin = la_list_des_front.end();
               for (il = la_list_des_front.begin(); il != ilfin; il++)
                { const Tableau <Noeud *>& tnoe = (*il).Eleme()->TabNoeud_const();
                  int nb_noe_et1 = tnoe.Taille();
                  for (int m =1;m<nb_noe_et1;m++)
                    num_noe_front.push_back(tnoe(m)->Num_noeud());
                  li_Elem_avec_front.push_back((*il).PtEI());
                };
               // on ordonne et on supprime les doublons
               num_noe_front.sort(); // ordonne
               num_noe_front.unique(); // suppression des doublons
               li_Elem_avec_front.sort();  // ordonne
               li_Elem_avec_front.unique(); // supprime les doublons
               
               // on définit une liste temporaire des nouvelles front d'angle mort créé
               // c'est utilisé pour définir les mitoyens des éléments d'angle morts
               // qui sont apparus avec les angles morts (== les mitoyens angle mort des éléments angle morts !!)
               list <Front *> front_angle_mort;

               // maintenant on parcours les noeuds contenu dans num_noe_front
               // et on regarde s'il faut ajouter des éléments point d'angle mort
               list <int>::iterator ih,ih_fin=num_noe_front.end();
               for (ih = num_noe_front.begin();ih != ih_fin;ih++)
                 {int i_noe = (*ih); // le num du noeud maître que l'on va tester
                  Tableau <Noeud *> ttn(1);
                  ttn(1)= &(lesMail.Noeud_LesMaille(jf,i_noe)); // récup du pointeur de noeud
                     
                  // récup de la liste pour le noeud i_noe, des éléments qui contient ce noeud : construite avec Init_contact
                  const List_io < Element* >& liel = (*indice(jf))(i_noe);
                  // on boucle sur chaque élément qui contient le noeud
                  List_io < Element* >::const_iterator il,ilfin=liel.end();
                  for (il = liel.begin();il != ilfin;il++)
                    {const Element* el=(*il); // pour simplifier
                     // on regarde si cet élément ne fait pas partie de la liste d'élément
                     // qui contient déjà une frontière
                     bool trouver = false;
                     list <const Element* >::const_iterator ikl,iklfin=li_Elem_avec_front.end();
                     for (ikl = li_Elem_avec_front.begin();ikl != iklfin; ikl++)
                       {if (((*ikl)->Num_elt_const() == el->Num_elt_const()) && ((*ikl)->Num_maillage() == el->Num_maillage()))
                         {trouver= true; break;}
                       };
                     if (!trouver)
                      {// on n'a pas trouvé d'élément,
                       // 1. on récup le num local EF du noeud
                       int nb_noeu_el_et_1 = 1+el->Nombre_noeud(); // le nombre de noeud de l'élément
                       int num_noe_local = 0;
                       for (int k =1;k<nb_noeu_el_et_1;k++)
                         if (el->Num_noeud(k) == ttn(1)->Num_noeud())
                           {num_noe_local=k; break;};
                       // 2. on récupère la frontière noeud correspondante en forçant une création éventuelle
                       // on passe par l'intermédiaire de lesMail pour pouvoir modifier l'élément
                       // car c'est l'élément qui stocke et gère la frontière
                       Element& elem_non_const = lesMail.Element_LesMaille(el->Num_maillage(), el->Num_elt_const());
                       // 3. on crée l'élément de frontière ad hoc
                       ElFrontiere* const elfpoint = elem_non_const.Frontiere_points(num_noe_local,true);
                       // ramene le numero de la frontière passée en argument si elle existe actuellement au niveau de l'élément
                       // sinon ramène 0
                       // ramene également type_front: qui indique le type de frontière: POINT_G, LIGNE ou SURFACE
                       // c'est une méthode très longue, a utiliser avec précaution
                       Enum_type_geom type_front;
                       int num_front = el->Num_frontiere(*elfpoint,type_front);
                       // 4. on crée l'élément front ad hoc et on l'ajoute à la liste
                       const DdlElement & ddlElem = el->TableauDdl(); // récup des ddl
                       int angle_mort = 1;
                       la_list_des_front.push_front(Front(*elfpoint,&elem_non_const,num_front,angle_mort));
                       LaLIST_io <Front>::iterator iik = la_list_des_front.begin(); // récup de l'iterator
                       // on met à jour les frontières mitoyennes
   //                    // t_liFront_noeud(i)(j)(k) : la liste des frontières initiales qui contiennent le noeud k de la zone j du maillage i
   //                    Tableau < Tableau < Tableau < list <Front*> > > > t_liFront_noeud;
                       int num_noeud = ttn(1)->Num_noeud(); // le num global du noeud
                       // récup de la liste des frontières initiales contenant le noeud
                       list <Front*> & t_liFront_noeud_ijk = t_liFront_noeud(ilistfront)(i_zone)(num_noeud);
                       list <Front*>::iterator km,kmfin=t_liFront_noeud_ijk.end();
                       for (km=t_liFront_noeud_ijk.begin();km != kmfin;km++)
                         {(*km)->AjoutMitoyen(&(*iik));// ajout frontière pour la frontière initiale
                          (*iik).AjoutMitoyen(*km); // ajout frontière pour la nouvelle frontière d'angle mort
                         };
                       // on sauvegarde le nouvelle front dans une liste spécifique
                       front_angle_mort.push_front(&(*iik));

                       if (niveau_commentaire_lescontacts >4 )
                        { cout << "\n ajout front point: noeud "<<el->Num_noeud(num_noe_local)
                               << " mail: " << jf << " zone "<< i_zone
                               << " element: "<<el->Num_elt_const() ;
                        };
                      };
                    };
                 };
               int nb_front_fin = la_list_des_front.size(); // la taille finale
               if (niveau_commentaire_lescontacts >2 )
                     cout << "\n ajout angle mort pour contact: mail. maitre "<<jf << " : zone de contact: " << i_zone
                          <<" : " <<(nb_front_fin-nb_front_init)
                          << " frontieres point ";
                           
               #ifdef MISE_AU_POINT
               // petite vérif en passant
               if ((nb_front_fin-nb_front_init) != front_angle_mort.size())
                {cout << "\n *** erreur dans la definition des elements point d'angle mort "
                      << " on a deux listes qui les representent mais qui n'ont pas la meme taille "
                      << (nb_front_fin-nb_front_init) << " et " << front_angle_mort.size()
                      << "\n LesContacts::ElementAngleMort(..";
                 Sortie(1);
                };
               #endif

               // on utilise front_angle_mort pour définir les mitoyens angle mort des éléments angle morts
               list <Front *>::iterator ag,agfin=front_angle_mort.end();
               for (ag=front_angle_mort.begin();ag != agfin; ag++)
                 {list <Front *>::iterator bg;
                  bg = ag; bg++;
                  // on utilise deux boucles imbriquées
                  for ( ; bg!= agfin ; bg++)
                    {const Tableau <Noeud *>& tan = (*ag)->Eleme()->TabNoeud_const();
                     const Tableau <Noeud *>& tbn = (*bg)->Eleme()->TabNoeud_const();
                     // normalement c'est des FrontPoinF, donc il n'y a qu'un seul noeud frontière
                     if (tan(1)->Num_noeud() == tbn(1)->Num_noeud())
                      // les deux éléments FrontPoinF partage le même noeud,
                      // on met à jour les mitoyens
                      { (*ag)->AjoutMitoyen((*bg));
                        (*bg)->AjoutMitoyen((*ag));
                      };
                    };
                 };
              if (niveau_commentaire_lescontacts >7 )
               { cout << "\n liste finale des elements angle mort "
                      << " mail: " << jf << " zone "<< i_zone;
                 for (ag=front_angle_mort.begin();ag != agfin; ag++)
                   (*ag)->Affiche();
               };

              }; // fin du test if (nb_front_init > 0) et if ((*la_list_des_front.begin()).NumMail() == jf )

           };// fin de la boucle sur les zones
        }; // fin de la boucle sur les maillages maitres de t_listFront
    };  // fin du test avec ou sans zone de contact


 };





