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

/************************************************************************
 *     DATE:        23/01/97                                            *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  Creation et gestion des  contacts.                         * 
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef LESCONTACTS_H
#define LESCONTACTS_H

#include "Front.h"
#include <list>
#include "List_io.h"
#include "ElContact.h"
#include "Condilineaire.h"
#include "Nb_assemb.h"
#include "LesMaillages.h"
#include "LesReferences.h"
#include "Basiques.h"
#include "TypeQuelconque.h"
#include "Temps_CPU_HZpp.h"
#include "Enum_TypeQuelconque.h"
#include "TypeQuelconqueParticulier.h"

#include <stdlib.h>
#ifdef UTILISATION_MPI
  #include <boost/serialization/split_member.hpp>
  #include <boost/serialization/string.hpp>
  #include "mpi.h"
  #include <boost/mpi/environment.hpp>
  #include <boost/mpi/communicator.hpp>
  #include <boost/serialization/string.hpp>
  #include <boost/mpi.hpp>
  namespace mpi = boost::mpi;
#endif


/// @addtogroup Groupe_sur_les_contacts
///  @{
///


class LesContacts
{
  public :
  // CONSTRUCTEURS :
  // constructeur par defaut
  LesContacts ();
  // constructeur de copie
  LesContacts (const LesContacts& a);
  // DESTRUCTEUR :
  ~LesContacts ();
  
  // METHODES PUBLIQUES :
  
  // ramène le nombre de maillages esclaves en auto contact, donc qui joue le rôle esclave et maître, ou maillages mixte: dépend de la manière dont les zones de contact ont été
  // est définit en lecture des données
  int NbmailAutoContact() const {return nbmailautocontact;};
    
  // ramène la liste des éléments de contact
  LaLIST <ElContact>& LesElementsDeContact() {return listContact;}; 
      
// 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 Init_contact(LesMaillages& lesMail
                   ,const LesReferences& lesRef
                   ,LesFonctions_nD* lesFonctionsnD);

  // mise à jour du tableau "indice": là on utilise les numéros de noeuds qui peuvent changer
  // via une renumérotation. Le tableau indice, est un tableau utilisé pour les recherches
  // mais le numéro de noeud n'est pas utilisé pour les stockages divers (on utilise un pointeur de noeud)
  // du coup le tableau indice peut évoluer ex: après un remaillage avec chg de num de noeud
  // il doit donc être remis à jour avant l'étude de nouveau contact
  // la 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
  void Mise_a_jour_indice(const  Tableau < const Tableau <List_io < Element* > > *> ind)
     { indice = ind;};
 
  // indique si l'initialisation a déjà été effectuée ou pas, car celle-ci ne doit-être faite
  // qu'une fois
  bool Init_contact_pas_effectue() const { return (tesctotal.Taille() == 0);};
 
  // verification qu'il n'y a pas de contact avant le premier increment de charge
  void Verification();

  // definition des elements de contact eventuels
  //  - imposition des conditions de non penetration
  // dep_max : déplacement maxi des noeuds du maillage
  //           , sert pour def des boites d'encombrement maxi des frontières
  // ramène true s'il y a effectivement création d'élément de contact
  bool DefElemCont(double dep_max);
  
  // 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
  //           , sert pour def des boites d'encombrement maxi des frontières
  bool Nouveau(double dep_max);
		
		// suppression définitive, si le contact à disparu, des éléments inactifs
		// ramène false si aucun élément n'est finalement supprimé
		bool SuppressionDefinitiveElemInactif();
		
		// relachement des noeuds collés
		// ramène true s'il y a des noeuds qui ont été relachés
		bool RelachementNoeudcolle();
      
  // definition de conditions lineaires de contact
  // marquage des ddl correspondant aux directions bloquees s'il s'agit d'un contact de type 1
  // casAssemb : donne le cas d'assemblage en cours
  // Dans le cas d'un   calcul  parallèle, il y a transfert des conditions au  cpu 0
  // seules les cpu i calculent les conditions linéaires
  // NB: on ne met pas la liste en const car on  a besoin de pouvoir modifier les infos à l'intérieur
  // des CL pour les utiliser, mais l'idée est la  liste elle, reste  constante
  list <Condilineaire>&  ConditionLin(const Nb_assemb& casAssemb);
 
  // création d'une liste 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,
  // Dans le cas d'un   calcul  parallèle, il y a transfert des conditions au  cpu 0
  // seules les cpu i calculent les conditions linéaires
  // NB: on ne met pas la liste en const car on  a besoin de pouvoir modifier les infos à l'intérieur
  // des CL pour les utiliser, mais l'idée est la  liste elle, reste  constante
  list <Condilineaire>&   ConnectionCLL();
 
  // effacement du marquage de ddl bloque du au conditions lineaire de contact
  void EffMarque();
 
  // 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 Maitres_avec_deplacement_imposer() const;
  
		// 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)
  // en retour, ramène un booleen qui :
  //  = true : si la largeur de bande en noeud est supérieure à 1 (cas d'un contact avec une surface déformable)
  //  = false : si non, ce qui signifie dans ce cas qu'il n'y a pas d'augmentation de la largeur
  //            en noeud (cas d'un contact avec une surface rigide)
  //  dans  le cas d'un calcul // seule  le cpu  0 effectue   la résolution,  par contre tous les cpu i   contribuent
  //  ils vont donc transmettre  les  informations  au cpu   0
  bool Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb,int& cumule);
      
		// actualisation du contact, on examine que les elements de contact, dont on
		// actualise la projection du noeud esclave en fonction de la position de l'element
		// maitre frontiere (mais la position finale du noeud n'est pas forcément changée, cela dépend du
		// modèle de contact (cinématique, pénalisation etc.)
  // ramène true si quelque chose à changé, false sinon
  // choix == 1 : les éléments actifs sont maintenu en contact même si l'intersection est hors frontière
  //              si l'intersection n'est pas calculable, l'élément de contact est laissè inchangé
  // choix == 0 : les éléments actifs sont inactivés si l'intersection est hors frontière ou
  //              si l'intersection n'est pas calculable
  // NB: pour les deux choix, s'il y a doublon d'élément de contact, due à un changement de frontière
  //     en cours d'actualisation, on inactive le(s) doublon(s)
  //  dans  le cas d'un calcul // chaque proc i effectue son actualisation, s'il y a changement de surface avec sortie
  //  de la surface gérée par le proc i, cela sera vérifié au niveau de l'élément de contact
  // Le proc 0 se contente de récupérer et globaliser les retours des proc  i
  bool Actualisation(int choix);
 
  // 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 Liste_noeuds_position_changer(list <Noeud * >& li_noe);
 

  // calcul des reactions de contact et stockage des valeurs
  // solution : le vecteur residu
  // test d'un decollement eventuelle, pour un noeud en contact
  // ramene true s'il y a decollement, sinon false
  // casAssemb : donne le cas d'assemblage en cours
  void CalculReaction(Vecteur& residu,bool& decol,const Nb_assemb& casAssemb
                      ,bool affiche);
 
  // récupération via les éléments de contact des forces maxis
  // un : le maxi en effort normal, deux: le maxi en effort tangentiel
  DeuxDoubles Forces_contact_maxi(bool affiche) ;
 
  // récupération via les éléments de contact des gaps maxi en négatif, donc les mini
  // un : le maxi en gap normal, deux: le maxi en gap tangentiel
  DeuxDoubles Gap_contact_maxi(bool affiche) ;

  // 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, des forces de réaction et de la pénétration
		// donc nécessite que le contact ait déjà été étudié et que les efforts de contact ait été calculé
		double Pas_de_temps_ideal();
 
  // calcul d'une estimation du pas de temps critique du aux éléments de contact


		// affichage des reactions de contact sur la sortie
  void Affiche(ostream& sort) const ;
  
  // affichage à l'écran des informations liées au contact
  void Affiche() const ;      
  
  // affichage et definition interactive des commandes
  void Info_commande_LesContacts(UtilLecture & entreePrinc);
 
  // lecture éventuelle des zones où le contact doit être recherché, à l'exclusion de tout
  // autre zone, ainsi que la définition de l'auto-contact éventuel
  // ainsi que des contacts solide-deformables éventuel
  // cas d'un  calcul parallèle, tous  les proc utilisent la méthode, seule le proc  0 affiche
  void Lecture_zone_contact(UtilLecture & entreePrinc,const LesReferences& lesRef);

  // récupération des ddl ou des grandeurs actives de tdt vers t 
  void TdtversT();
  // actualisation des ddl et des grandeurs actives de t vers tdt      
  void TversTdt();
  
  // ramène le nombre de contacts actifs actuel
  int Nb_actifs() const {return nb_contact_actif;};

  //------- temps cpu -----
  // retourne temps cumulé pour imposer les CL imposées
  const Temps_CPU_HZpp& Temps_cpu_Contact() const {return tempsContact;};

#ifdef UTILISATION_MPI
  // cas d'un calcul parallèle: // passage des infos entre process
  const Temps_CPU_HZpp&  Temps_transfert_court() const {return temps_transfert_court;} ;
  const Temps_CPU_HZpp&  Temps_transfert_long() const {return temps_transfert_long;} ;
  const Temps_CPU_HZpp&  Temps_attente() const {return temps_attente;} ;
  // mise à jour list contact pour proc 0: il s'agit des infos minimales
  void Mise_a_jour_liste_contacts_actif_interProc();
  // on définit une méthode qui permet de retrouver un élément à partir d'infos minimales
  ElContact*  RecupElContactActif( int num_mailEsclave, int num_noeudEsclave, int numUnique)
    {LaLIST <ElContact>::iterator ili,ilifin = listContact.end();
     for (ili = listContact.begin();ili != ilifin;ili++)
       if (    ((*ili).Esclave()->Num_Mail() == num_mailEsclave)
           &&  ((*ili).Esclave()->Num_noeud() == num_noeudEsclave)
           &&  ((*ili).Elfront()->NumUnique() == numUnique)
          )
         return (&(*ili));
     return NULL;
    } ;
#endif

	 //----- lecture écriture de restart -----
     // cas donne le niveau de sauvegarde
	 void Ecri_base_info_LesContacts(ostream& sort);
	  // on utilise deux pointeurs de fonctions qui permettent de récupérer le pointeur de noeud esclave
	  // idem au niveau de l'élément 
	 template <class T> 
	 void Lec_base_info_LesContacts(istream& ent
						,T& instance  // l'instance qui permet d'appeler les pointeurs de fonctions
						,Noeud& (T::*RecupNoeud)(int i, int j) const
						,Element& (T::*RecupElement_LesMaille) (int i, int j) const);
      
#ifdef UTILISATION_MPI
  // retour de la taille globale des sorties retardées
  // concernant les sorties sur .BI
  MPI_Offset Taille_buffer_sortie_BI();
  // récupération de l'offset global sur .BI pour la classe
  // et mise à jour des offsets de classes dérivées si besoin
  void Mise_a_jour_Offset_BI_ecriture(MPI_Offset offset,const int cas);
  // idem en lecture, mais là il s'agit uniquement de la mise à jour
  // de l'offset seul puis c'est la classe qui s'en débrouille
  void Mise_a_jour_Offset_BI_lecture(MPI_Offset offset,const int cas);

  // lecture MPI des infos bufferisées
  void Lecture_base_info_MPI_IO(MPI_File * ent_MPI,const int cas);
  // écriture MPI des infos bufferisées
  void Ecriture_base_info_MPI_IO(MPI_File * sort_MPI, const int cas);
#endif

  // méthode générale: récupération des grandeurs particulière (hors ddl )
  // correspondant à liTQ
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  // ===> n'est pas utilisée dans le cas du contact, c'est la méthode spécifique
  // Mise_a_jour_Pour_Grandeur_particuliere qui la remplace (qui n'est pas en const car elle
  // modifie les conteneurs des noeuds et éventuellement éléments)
  void Grandeur_particuliere
       (bool absolue,List_io<TypeQuelconque>& ,Loi_comp_abstraite::SaveResul * ,list<int>& decal) const
         {};
 
  // 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
  //--> important : les conteneurs sont supposés initialisés avec l'appel
  void Mise_a_jour_Pour_Grandeur_particuliere(
                                List_io < TypeQuelconque >& li_restreinte_TQ
                                );

  // 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> ListeGrandeurs_particulieres(bool absolue) const;
 
  // concernant les grandeurs gérées par le contact:
  // ramène une liste d'iterator correspondant aux List_io<TypeQuelconque> passé en paramètre
  // idem pour une List_io < Ddl _enum_etendu >
  void List_reduite_aux_contact(const List_io<TypeQuelconque>& liTQ
                                ,List_io < TypeQuelconque >& li_restreinte_TQ
                               );
 
  // 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
// ok, mais à revoir sans doute cf. pense bete 14 oct
  void Init_Grandeur_particuliere (bool absolue,List_io<TypeQuelconque>& li1);
  
     
  //retourne le niveau d'affichage
  // li si non nulle permet d'indiquer spécifiquement quelle grandeur on veut
  // sortir
  int Permet_affichage(list <TypeQuelconque> * li = NULL ) const
     { int niveau_commentaire_lescontacts = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_LesContact();
       return( (fct_niveau_commentaire == NULL) ?
                 (niveau_commentaire_lescontacts == 0) ? ParaGlob::NiveauImpression() : niveau_commentaire_lescontacts
                : Valeur_fct_nD_LesContacts(fct_niveau_commentaire, li
                              ,LesContacts::tqi_fct_nD_niveau_commentaire
                              ,LesContacts::tqi_const_fct_nD_niveau_commentaire
                              ,LesContacts::t_num_ordre_fct_nD_niveau_commentaire)
             );
     };

  // initialisation de la liste de grandeurs qui sont effectivement gérées par le contact
// ok, mais à revoir sans doute cf. pense bete 14 oct 
//  List_io<TypeQuelconque> Init_list_grandeur_contact_a_sortir(const Tableau <List_io < TypeQuelconque > >& li1);
 
  class ReactCont
    { // surcharge de l'operator de lecture
      friend istream & operator >> (istream &, ReactCont &);
      // surcharge de l'operator d'ecriture
      friend ostream & operator << (ostream &, const ReactCont &);

      public :
       Noeud* noe; // noeud esclave
       Coordonnee force ; // force de reaction au noeud esclave
       Tableau <Noeud *> tabNoeud; // les noeuds de la frontiere maitre
       Tableau <Coordonnee> tabForce; // les reac   ""   ""
       // constructeur par defaut
       ReactCont() ;
       // constructeur en fonction des datas du noeud esclave seul
       ReactCont(Noeud* no,const Coordonnee& forc) ;
       // constructeur en fonction des datas de tous les noeuds
       ReactCont(Noeud* no,const Coordonnee& forc,Tableau <Noeud *> tN,const Tableau <Coordonnee>& tFor);
       // constructeur de copie
       ReactCont(const ReactCont& a);
       // affectation
       ReactCont& operator = (const ReactCont& a);
       // test
       bool operator == (const ReactCont& a); 
       bool operator != (const ReactCont& a);
    };
   //----------------------------------------------------------------------------------------------------    
  private :  
    // VARIABLES PROTEGEES de la classe LesContacts:
    LesFonctions_nD* sauve_lesFonctionsnD ; // sauvegarde à l'initialisation (méthode Init_contact)
    ElContact::Fct_nD_contact fct_nD_contact; // fonctions nD de pilotage: peuvent ne pas exister
    // -- partie affichage éventuellement piloté
    Fonction_nD * fct_niveau_commentaire; // fct nD dans le cas d'une valeur pilotée
    static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_niveau_commentaire;
    static Tableau < TypeQuelconque *  > tqi_fct_nD_niveau_commentaire;
    static Tableau <int>  t_num_ordre_fct_nD_niveau_commentaire;
    list <TypeQuelconque>  li_pour_noeuds_element; // pour une sortie spécifique noeud et ou élément fini contenant la frontière
    Grandeur_scalaire_entier* gr_pour_noeud; // contient le numéro de noeud esclave éventuel
    Grandeur_scalaire_entier* gr_pour_elem; // contient le numéro éventuel de l'élément fini contenant la frontière
    // -- fin partie affichage éventuellement piloté


    LaLIST <ElContact> listContact; // la liste des elements en contact
    LaLIST <LaLIST <ElContact>::iterator> listContact_nouveau_tatdt; // la liste des nouveaux contacts qui sont apparus sur l'incrément
    LaLIST <ElContact> listContact_efface_tatdt; // la liste des contacts effacés sur l'incrément
	   int nb_contact_actif;  // nombre de contact actif courant
//    list <TroisEntiers> numtesN; // .un : maillage, .deux: num zone de contact, .trois: num propre du noeud
//                // la liste des numéros dans tesN des noeuds en contact
    Tableau <ReactCont> tabReacCont; // les reactions 
    list <Condilineaire> listCoLin; // tableau des conditions lineaires
 
    static MotCle motCle; // liste des mots clés
    // 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;
 
//--------- les tableaux de gestions pour la recherche de contact ----------------
    list <Quatre_string_un_entier> nom_ref_zone_contact; // liste des noms de références des zones de contact éventuelle
    // cette liste peut être vide, dans ce cas cela signifie que toutes les frontières des pièces sont
    // suceptible de rentrer en contact. Dans le cas où la liste n'est pas vide, seules les grandeurs
    // référencées sont succeptibles de rentrer en contact
    // nom1 -> nom_mail_ref_zone_contact pour les noeuds
    // nom2 -> le nom de la référence de noeuds
    // nom3 -> nom_mail_ref_zone_contact pour les frontières
    // nom4 -> le nom de la référence de frontière
    // n -> l'entier = 0 : pas d'utilisation
    //          = 1 : indique qu'il faut considérer un contact collant (glue)
    //          = 2 : idem mais avec en plus suppression du gap initial
    Tableau <int> lissage_de_la_normale; // même dimension que nom_ref_zone_contact
       // lissage_de_la_normale(i) : indique si oui ou non, la normale sur la zone i doit être lissée
 
 
    // 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)
  #ifdef UTILISATION_MPI
    // cas d'un calcul parallèle: // passage des infos entre process
    Tableau <Front *> pointe_t_listFront; // pointe_t_listFront(i_num) permet de repérer un élément unique
             // dans  t_listFront
             // à l'inverse, chaque Front stocke son numéro i_num
             // pointe_t_listFront  est défini dans LesContacts::Init_contact
    Vecteur v_interProc_contact_actif; // conteneur de travail utilisé pour le passage d'infos
             // entre proc , par la méthode Mise_a_jour_liste_contacts_actif_interProc()
    // pour les i/o
    MPI_Offset nb_buffer; // ici = 3  buffers, tous les proc ont le même nombre de buffer
      // par contre il y a seulement un non nul pour les proc i et 2 non nuls pour le proc 0
    //a) en lecture
    // tous les proc lisent le fichier de manière collective, par contre
    // - chaque proc i (!= 0), récupère dans le buffer que les éléments de contact
    //    qui intègre un élément fini qu'il gère
    // - le proc 0 récupère l'entête et la fin uniquement (pas les éléments de contact)
    // - un seul buffer est utilisé pour lire tous les éléments
    //b) en écriture
    // - le premier et le dernier buffer sont pour le proc 0
    // celui du milieu est pour chacun des proc i
    Tableau <std::string > buffer_ioBI_MPI; // les buffers pour la sortie retardée
      // uniquement les buffers propres : ici taille 3 pour tous les proc
    std::vector<MPI_Offset>  tailles_buffer_ioBI_MPI; // tailles des buffers
      // size [nbTotalProc] pour tous les proc, commun à tous les proc en écriture
    // offsets ,
    // offset_LesContacts[0] est l'offset de début, utile pour proc 0
    //  valable en lecture et écriture
    // puis en écriture:
    // [k] : début des éléments de contact pour le proc k (!= 0)
    // [nbTotalProc] : c-a-d nb proc i + 1, début du temps cpu pour proc 0
    // [nbTotalProc+1] : position de la fin
    std::vector<MPI_Offset> offset_LesContacts;
    MPI_Offset taille_offset; // = nbTotalProc+2 ici
  #endif

    // les noeuds esclaves potentiels
    Tableau < Tableau < Tableau < Noeud*> > >  tesctotal;
         // tesctotal(i)(j)(k) : maillage esclave (i), zone de contact (j)
         // noeud esclave (k) : k= le numéro d'ordre dans tesctotal(i)(j),
         //                     ==>> ce n'est pas le numéro du noeud dans le maillage !


    // indicateur de  noeuds collants
    Tableau < Tableau < Tableau < int> > > tesN_collant;
         // tesN_collant(i)(j)(k): maillage esclave (i), zone de contact (j)
         // noeud esclave (k):k= le numéro d'ordre dans tesctotal(i)(j),
         //                     ==>> ce n'est pas le numéro du noeud dans le maillage !
         //  indique pour si le noeud esclave  doit être
         //  considéré en contact collant (=1) ou pas (=0)
 
    // tesN_encontact: globalise tous les contacts sur un noeud (indépendamment des zones de contact)
    // tesN_encontact(i)(num_noe) : nombre de contact avec le noeud
// ancien stockage:    Tableau < Tableau < LaLIST < LaLIST<ElContact>::iterator > > >  tesN_encontact;
// ancien stockage         // tesN_encontact(i)(num_noe): maillage (i), noeud -> num_noe:
         // indique pour le noeud esclave s'il est en contact ou non via la taille de la liste associée
       // utilisation: pour chaque Noeud* = tesctotal(i)(k) -> la liste des éléments en contact
       // contenant le noeud k

// on remplace par une map: l'avantage c'est que l'on utilise plus les numéros de noeuds pour
// retrouver la liste, mais on utilise à la place la valeur pointeur de noeud esclave qui
// doit être  unique, du coup c'est indépendant de la numérotation des noeuds -> permet de la renumérotation
// sans changer la map
 
    Tableau < std::map<Noeud*,LaLIST < LaLIST<ElContact>::iterator > > > tesN_encontact;
    // tesN_encontact(numMail_esclave)[*pt_noeud] -> la liste des iterators d'élément de contact
    // avec le noeud

//--------- fin tableaux de gestions pour la recherche de contact ----------------

    int nb_mail_Esclave; // indique le nombre de maillages esclaves
	   int nbmailautocontact; // indique le nombre de maillages esclaves en auto contact, donc qui joue le rôle esclave et maître, ou maillages mixte: dépend de la manière dont les zones de contact ont été définit
    int nbmailMaitre; // indique le nombre de maillages maitres
                      // = nombre total de maillage - (nb_mail_Esclave-nbmailautocontact)
	     // si l'on considère l'ensemble des maillages du calcul on a successivement: 
	     // les nb_mail_Esclave-nbmailautocontact premier maillages: purement esclave
	     // puis les nbmailautocontact qui sont en auto contact: ils jouent le rôle d'esclaves et maîtres en même temps
	     // puis nbmailMaitre-nbmailautocontact : purement maître

    list < Deux_String > cont_solide_defor; // liste des noms de maillages définissants les contacts
               // solide-déformable: (*ie).nom1 -> le maillage solide , (*ie).nom2 -> le maillage deformable
 
    // ---- pour le post traitement ---
    List_io<TypeQuelconque> liQ_en_sortie; // liste de grandeurs quelconque qu'il faut sortir
 
    // -------- une variable de travail pour la méthode LesContacts::ConnectionCLL()---
    list <Condilineaire>   t_connectionCLL;
 
    //------- temps cpu -----
    // retourne temps cumulé pour imposer les CL imposées
    Temps_CPU_HZpp tempsContact;
  #ifdef UTILISATION_MPI
    // cas d'un calcul parallèle: // passage des infos entre process
    Temps_CPU_HZpp  temps_transfert_court ;
    Temps_CPU_HZpp  temps_transfert_long ;
    Temps_CPU_HZpp  temps_attente ;
    Vecteur          inter_transfer; //  un conteneur de transfert  pour ConditionLin
    Vecteur          inter_transfer2; //  un conteneur de transfert  pour ConnectionCLL
    // on sauvegarde un  pointeur sur les maillages
    LesMaillages* lesMaille;
  #endif

    // METHODES PROTEGEES :
    // mise à jour des boites d'encombrement pour les éléments qui contiennent une frontière
    void Mise_a_jour_boite_encombrement_element_contenant_front();
 
    // suppression du gap de contact pour les noeuds "collant avec suppression de gap"
    void Suppression_gap_pour_noeud_collant();
 
    // 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 Recup_ref( ElContact& al) ;
 
    // récupère le nombre de contact actif et met à jour ce nombre
    int Calcul_Nb_contact_actif();
    
    // création du conteneur Fct_nD_contact
    void Creation_Fct_nD_contact();
    
    // 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 ElementAngleMort(LesMaillages& lesMail);
    
    // test si un nouvel élément de contact possible appartient en fait déjà à la liste des contacts enregistrés
    // NB: pas rusé mais il faudrait pour optimiser, ordonner la liste des éléments de contact en
    // introduisant une nouvelle relation d'ordre et un nouvel operateur d'égalité ...
//il faut regarder s'il est actif aussi ???
//mais en création on pourrait regarder les intactifs, et au lieu de créer un nouveau, passer l'inactif en actif
//du coup, il faudrait peut-être ramener l'élément trouvé pour changer son activité ??
//donc ici il y a quelque chose à faire
    ElContact*  Element_contact_deja_present( const ElContact& al)
     {LaLIST <ElContact>::iterator ili,ilifin = listContact.end();
      for (ili = listContact.begin();ili != ilifin;ili++)
        if ((*ili).MemeOrigine(al))
          return (&(*ili));
      return NULL;
     } ;
    // idem mais avec un iterator
    // permet de comparer un iterator de la liste avec les éléments de la liste
    ElContact*  Element_contact_deja_present( LaLIST <ElContact>::iterator& il)
    {LaLIST <ElContact>::iterator ili,ilifin = listContact.end();
     for (ili = listContact.begin();ili != ilifin;ili++)
       if (((*ili).MemeOrigine(*il)) && (il != ili))
         return (&(*ili));
     return NULL;
    } ;
    
    // recherche dans les Front enregistrés de la zone , c-a-d dans t_listFront(i)(zone)
    //  un Front de même origine , c-a-d sans les mitoyens
    // si aucun résultat retourne NULL
    // sinon ramène l'élément de t_listFront de même origine
    Front* Front_de_meme_origine(Front* fro, int zone) const;

    // init éventuel du pilotage par fct nD du niveau de commentaire
    void Init_fct_niveau_commentaire();
    // définition des conteneurs  des TypeQuelconque pour fct nD de LesContacts
    void Definition_conteneurs_fctnD_TypeQuelconque
         (Fonction_nD * pt_fonct,Tableau < TypeQuelconque *  >& tqi,Tableau < const TypeQuelconque *  >& tqii
          ,Tableau <int>&  t_num_ordre );

    // calcul d'une fonction nD relative à aux données de LesContacts
    double Valeur_fct_nD_LesContacts(Fonction_nD * fct_nD,list <TypeQuelconque> * li
                                 ,Tableau < TypeQuelconque *  >& tqi
                                 ,Tableau < const TypeQuelconque *  >& tqii
                                 ,Tableau <int>&  t_num_ordre) const;

 };
  /// @}  // end of group


  // pour faire de l'inline: nécessaire avec les templates
  // on n'inclut que les méthodes templates
  #include "LesContacts_2.cc"  
  #define  LesContacts_2_deja_inclus 
 
#endif