
// 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:  Element de contact.                                        *
 *           - l'élément utilise une frontiere Front qui contient ses   *
 *           donnees geometriques : l'élément de contact crée une copie *
 *           d'un élément de frontière qui existe par ailleurs, en fait *
 *           l'originale existe dans LesContacts.                       *
 *           L'aspect spécifique est:                                   *
 *           . le Front de l'élément de contact est une copie           *
 *           . le tableau de ses mitoyens pointe sur les originaux      *
 *             du coup on peut supprimer et créer de nouvelles copies   *
 *             de Front sans invalider le tableau de pointeur de Front  *
 *             qui définit les mitoyens !   (un peu tordu )             *
 *           - il gère les aspects spécifiques du contact: efforts,     *
 *           résidu, raideur etc.                                       *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef ELCONTACT_H
#define ELCONTACT_H

#include "Front.h"
#include "Noeud.h"
#include "Condilineaire.h"
#include "LesFonctions_nD.h"


/** @defgroup Groupe_sur_les_contacts
*
*     BUT:   groupe relatif aux contacts
*
*
* \author    Gérard Rio
* \version   1.0
* \date       23/01/97
* \brief       groupe relatif aux contacts
*
*/

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

class ElContact
{
 public :
  // une classe structure de transfert pour simplifier le passage de paramètres
  class Fct_nD_contact
  { public:
     Fct_nD_contact();
     Fct_nD_contact(const Fct_nD_contact& a);
     ~Fct_nD_contact();
     Fct_nD_contact& operator= (const Fct_nD_contact& a);
     
  
     // utilisation de fct nD
     Fonction_nD * fct_nD_penalisationPenetration; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_penetration_contact_maxi; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_penetration_borne_regularisation; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_force_contact_noeud_maxi; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_penalisationTangentielle;
     Fonction_nD * fct_nD_tangentielle_contact_maxi; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_tangentielle_borne_regularisation; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_nD_force_tangentielle_noeud_maxi; // fct nD dans le cas d'une valeur pilotée
     Fonction_nD * fct_niveau_commentaire; // fct nD dans le cas d'une valeur pilotée
     
     // initialisation des conteneurs statique des fonction nD
     void Init_conteneur_statique();
     
     // stockage transitoire pour les quelconques vraiment quelconque
     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_penalisationPenetration;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_penalisationPenetration;
     static Tableau <int>  t_num_ordre_fct_nD_penalisationPenetration;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_penetration_contact_maxi;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_penetration_contact_maxi;
     static Tableau <int>  t_num_ordre_fct_nD_penetration_contact_maxi;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_penetration_borne_regularisation;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_penetration_borne_regularisation;
     static Tableau <int>  t_num_ordre_fct_nD_penetration_borne_regularisation;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_force_contact_noeud_maxi;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_force_contact_noeud_maxi;
     static Tableau <int>  t_num_ordre_fct_nD_force_contact_noeud_maxi;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_penalisationTangentielle;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_penalisationTangentielle;
     static Tableau <int>  t_num_ordre_fct_nD_penalisationTangentielle;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_tangentielle_contact_maxi;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_tangentielle_contact_maxi;
     static Tableau <int>  t_num_ordre_fct_nD_tangentielle_contact_maxi;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_tangentielle_borne_regularisation;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_tangentielle_borne_regularisation;
     static Tableau <int>  t_num_ordre_fct_nD_tangentielle_borne_regularisation;

     static Tableau <const TypeQuelconque *  > tqi_const_fct_nD_force_tangentielle_noeud_maxi;
     static Tableau < TypeQuelconque *  > tqi_fct_nD_force_tangentielle_noeud_maxi;
     static Tableau <int>  t_num_ordre_fct_nD_force_tangentielle_noeud_maxi;
     
     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;
     protected :
      // définition des conteneurs de transfert  des TypeQuelconque
      // pour une fonction nD particulière
      void Definition_conteneurs_static_TypeQuelconque
             (Fonction_nD * pt_fonct,Tableau < TypeQuelconque *  >& tqi
              ,Tableau < const TypeQuelconque *  >& tqii,Tableau <int>&  t_num_ordre );


  };

  // CONSTRUCTEURS :
  // par defaut
  ElContact();
  
  // la version avec fonction de pilotage nD
  ElContact(Fct_nD_contact & fct_contact);
  
  // fonction d'un pointeur d'element frontiere et d'un pointeur de noeud
  // du fait éventuel qu'il peut-être collant ou pas
  ElContact ( const Front * elfront, const Noeud * noeud, Fct_nD_contact & fct_contact_
              ,const Front * elfront_initial, int collant = 0);
  // de copie
  ElContact ( const ElContact & a);
  // DESTRUCTEUR :
  ~ElContact ();
  
  // METHODES PUBLIQUES :
  
  // affectation de toute les donnees
  ElContact& operator = ( const ElContact& a);
  
  // test d'egalite sur les éléments originaux :
  // l'élément de frontière front, le noeud esclave, même zone de contact
  inline bool MemeOrigine( const ElContact& a) const
   { if ( (this->elfront->MemeOrigine(*a.Elfront()))
          && (this->noeud->Num_noeud() == a.Const_Esclave()->Num_noeud())
          && (this->noeud->Num_Mail() == a.Const_Esclave()->Num_Mail())
          && (num_zone_contact == a.Const_Num_zone_contact())
        )
        return true;
      else
        return false;
    };

  // init  d'une fonction nD pour le pilotage du type de contact 4
  static void Init_fct_pilotage_contact4(Fonction_nD * fct_pilo_contact4)
     {fct_pilotage_contact4 = fct_pilo_contact4;};
     
  //retourne le niveau d'affichage
  int Permet_affichage() const
     { return( (fct_nD_contact.fct_niveau_commentaire == NULL) ?
                 (niveau_commentaire == 0) ? ParaGlob::NiveauImpression() : niveau_commentaire
                : Valeur_fct_nD(fct_nD_contact.fct_niveau_commentaire
                              ,ElContact::Fct_nD_contact::tqi_fct_nD_niveau_commentaire
                              ,ElContact::Fct_nD_contact::tqi_const_fct_nD_niveau_commentaire
                              ,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_niveau_commentaire
                              )
             );
     };

  // méthode statique de modification éventuelle du type de contact utilisé localement
  // par exemple pour le type 4 en fonction des itérations
  static int Recup_et_mise_a_jour_type_contact() ;

  // affichage à l'écran des informations liées au contact
  // cas = 0 : affichage en fonction du niveau de commentaire voulu
  // cas = 1 : affichage minimal nécessaire pour repérer l'élément
  // cas = 2 : affichage en fonction du niveau de commentaire pour les éléments de contact
  void Affiche(int cas=0) const ;
    
// calcul d'un contact eventuel entre le noeud esclave et la frontiere
// ramene true s'il y a contact
// si init = false, on recherche le contact a partir du precedent point sauvegarde
// sinon on commence a l'aide d'element de reference,
// et on calcule et sauvegarde les coordonnées
// initiale locales theta^i du point de contact

// si le contact existe  et si l'algo le demande (cf. ParaAlgoControle) :
// le noeud pourrait-être ramené sur la surface mais:
// on ne fait pas de projection, sinon on ne peut pas tester plusieurs contacts pour
// choisir le meilleur, puisque les choses changent entre avant et après le test de contact
// donc ici la position du noeud esclave n'est pas modifiée
  bool Contact( bool init = true);
  // juste après l'utilisation de la méthode Contact(), ramène le point en contact
  const Coordonnee& Point_intersection() const { return Mtdt; };
 
  // un stockage utilisé par les méthodes appelantes
  int& Num_zone_contact() {return num_zone_contact;};
  int Const_Num_zone_contact() const {return num_zone_contact;};

  // calcul de la trajectoire a prendre en compte pour le contact
  // ---- a) cas ou à t il n'y avait pas de contact, ou que l'on n'a pas fait de projection sur la surface (cas du contact cinématique)
  // 4 cas : 1) le noeud bouge, dans ce cas la trajectoire est determinee
  //   par la variation de la position du noeud
  //  2) le noeud est immobile, mais la frontiere bouge, la trajectoire est determine
  // par une parallele a la variation moyenne de la frontiere (variation de G)
  //  4) est une variante du 2), cas où l'on a une rotation autour de G, dans ce cas on prend comme trajectoire
  //     le maxi des déplacements de noeud
  //  3) rien ne bouge, on utilise la normale au point de reference de l'element de frontiere
  // pour calculer la trajectoire .
  // dans le cas 3 la variable test = 0 , sinon elle vaut 1 pour le cas 1 et 2 pour le cas 2 , 4 pour le cas 4
  // ---- b) cas ou à t on était déjà en contact avec projection sur la surface 
  //  la trajectoire est alors systématiquement la direction de la dernière normale, 
  // retour : test=5
  Coordonnee  Trajectoire(int & test);
  
  // calcul de l'Intersection de la trajectoire du noeud definit par le vecteur V
  // avec l'element frontiere
  // ramene les coordonnees du noeud projete
  // dans le cas où il n'y a pas d'intersection, on ramène un point de dimension nulle
  Coordonnee Intersection( const Coordonnee& V,bool init);
  
  // construction de la condition lineaire de contact
  // nb_assemb : indique le numéro d'assemblage correspondant    
  Condilineaire ConditionLi(int nb_assemb);
  
  // ramene le tableau de tous les noeuds, le premier est celui esclave
  Tableau <Noeud*>& TabNoeud() {return tabNoeud;};
  const Tableau <Noeud*>& Const_TabNoeud() const {return tabNoeud;};
	 // ramene le tableau pour assemblage: dépend du Cas_solide()
	 // est cohérent avec TableauDdlCont
  Tableau <Noeud*>& TabNoeud_pour_assemblage() {return tabNoeud_pour_assemblage;};

	 // retourne les tableaux de ddl associés aux noeuds, gere par l'element
	 // qui sont actifs au moment de la demande
 	// Tableau de DdlElement pour l'assemblage uniquement
  const DdlElement & TableauDdlCont() const {return *ddlElement_assemblage;};
  // ramene le noeud esclave
  inline Noeud* Esclave() { return noeud;};
  inline const Noeud* Const_Esclave() const { return noeud;};
  // ramene la force de contact pour consultation
  const Coordonnee& Force_contact() const {return force_contact;};
  // ramène les maxis concernant le noeud esclave
  double F_N_MAX() const {return F_N_max;};
  double F_T_MAX() const {return F_T_max;};
  // ramène la pénalisation actuelle éventuelle
  const double& Penalisation() const {return penalisation;};
  const double& Penalisation_tangentielle() const {return penalisation_tangentielle;};
 
  // ramène le déplacement tangentiel actuel
  const Coordonnee& Dep_tangentiel() const {return dep_tangentiel;};
  // ramène la normale actuelle
  const Coordonnee& Normale_actuelle() const {return N;};

  // idem pour les réactions sur les noeuds de la facette
  const Tableau <Coordonnee>& TabForce_cont() const {return tabForce_cont;};
 
  // actualisation de  la projection du noeud esclave en fonction de la position de l'element
  // maitre frontiere. Lorsque le noeud change d'element fontiere, on change l'element
  // frontiere de l'element de contact en consequence
  // dans le cas ou on ne trouve pas d'intersection, cas d'un noeud qui sort d'une zone de
  // contact, on retourne 0, sinon retourne 1 si on n'a pas changé de frontière
  // retourne 2 si on a changé de frontière
  // en fonction de la méthode de contact, le noeud est ramené éventuellement sur la frontière
  int Actualisation();
  
  // ramene un pointeur sur l'element frontiere 
  inline Front * Elfront()  const { return elfront;};
  // ramene un pointeur sur l'element frontiere initiale
  inline Front * Elfront_initiale()  const { return front_initiale;};

	 // permet de changer le deplacement maxi de tous les noeuds, qui sert
	 // pour éviter de considérer des contact trop éloignés
	 static void Change_dep_max(const double & deplac_max) 
	   {dep_max = deplac_max * ParaGlob::param->ParaAlgoControleActifs().FacPourRayonAccostage();};
  
  // test et met à jour le compteur de décollage du noeud
  // si le noeud decolle ou non en fonction de la force de reaction
  // ramene 1:  s'il decolle
  //        0: s'il ne décolle pas
  bool Decol();
  // change force: permet de changer la valeur de la force
  // utile quand la force est calculée en dehors de l'élément de contact
  void Change_force(const Coordonnee& force);
  
  // idem pour les forces réparties sur la facette
  void Change_TabForce_cont(const Tableau <Coordonnee>& tab)  {tabForce_cont=tab;};
 
	 // gestion de l'activité
	 int Actif() const {return actif;}; // ramène l'activité du contact
	 void Met_Inactif() { actif = 0;nb_decol_tdt=0;
                       #ifdef MISE_AU_POINT
                       if (Permet_affichage() > 2)
                         {cout << "\n       -- ElContact::Met_Inactif() -> inactivation du contact: ";this->Affiche(1);};
                       #endif
                     }; // met en inactif
	 void Met_actif() { actif++;nb_decol_tdt=0;
                     #ifdef MISE_AU_POINT
                     if (Permet_affichage() > 2)
                       {cout << "\n       -- ElContact::Met_actif()  -> activation du contact: ";this->Affiche(1);};
                     #endif
                   }; // met en actif une fois de plus
 
  // ramène le nombre actuel de décolement
  int Nb_decol() const {return nb_decol_tdt;};
  // ramène le nombre de pénétration actuel
  int Nb_pene() const {return nb_pene_tdt;};

	 // --- calcul des puissances virtuelles développées par les efforts de contact ----------
  //     et eventuellement calcul de la raideur associé 
	 // -> explicite à tdt 
	 virtual Vecteur* SM_charge_contact();
	 // -> implicite, 
	 virtual Element::ResRaid SM_K_charge_contact();
  // récup uniquement des conteneurs raideurs et résidu (pas forcément remplis, mais de la bonne taille)
  Element::ResRaid  Conteneur_ResRaid();
  // récup uniquement du conteneur résidu (pas forcément rempli, mais de la bonne taille)
  Vecteur* Conteneur_Residu();
  
	 // récupération des énergies intégrées sur l'éléments, résultants d'un précédent calcul
  // explicite, ou implicite: 
  // 1- il s'agit ici de l'énergie développée par le frottement glissant ou pas
	 const EnergieMeca& EnergieFrottement() const {return energie_frottement;};
	 // 2- énergie de pénalisation (élastique a priori)
	 const double& EnergiePenalisation() const {return energie_penalisation;};
	
	 // cas d'une méthode avec pénalisation: calcul éventuel d'un pas de temps idéal,
	 // permettant de limiter la pénétration 
  // 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 Pas_de_temps_ideal()const;
	
	 // ramène l'info sur le fait que le contact est avec un solide ou pas
	 // retour = 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 bloqué (solide)
	 int Cas_solide() const {return cas_solide;};

  // permet de modifier le contact entre collant ou non suivant "change"
  void Change_contact_collant(bool change)
    {cas_collant = change;};
  // récup de l'information concernant le contact collant ou pas
  bool Collant() const {return cas_collant;};
  
  //  gestion du lissage du lissage de la normale
  void Change_lissage_normale(int lissage)
    {normale_lisser = lissage;};
  // récup de l'information
  // indique si la normale doit-être lissée sur l'élément frontière, ou non
  int Lissage_normale() const {return normale_lisser;};
 
  // récup des gaps calculés
  const double &  Gaptdt() const {return gap_tdt;};
  const double &  Dep_T_tdt() const {return dep_T_tdt;} 
 
  // mise à jour du niveau de commentaire
  static void Mise_a_jour_niveau_commentaire()
    {niveau_commentaire = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();};

	 // 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();
	 
    //----- lecture écriture de restart -----
  void Lec_base_info_ElContact(istream& ent);
	 void Ecri_base_info_ElContact(ostream& sort);

#ifdef UTILISATION_MPI // spécifique au calcul parallèle
// ----- pour l'instant ne sert pas !!! on commente ------
//  // stockage dans un unique vecteur, des infos à  partir de l'indice rang inclus
//  // correspond à une sérialisation des  infos
//  // ramène le positionnement dans  v pour un prochain enreg, sauf si > à la taille de v
//  // dans ce cas ramène 0
//  // niveau: == 1 -> niveau minimum de sauvegarde, concerne uniquement la structure de l'élément
//  int Pack_vecteur(int niveau, Vecteur&  v,int rang) const;
//  // taille du conteneur actuel de la condition  linéaire
//  // dépend du niveau de sauvegarde
//  int Taille_Pack(int niveau) const;
//  // modification des infos à  partir de l'indice rang inclus en fonction du vecteur passé en paramètre
//  // correspond à une désérialisation
//  // ramène le positionnement dans  v pour un prochain enreg, sauf si > à la taille de v
//  // dans ce cas ramène 0
//  // on passe  un  pointeur  de fonctions qui ramène un noeud en fonction d'un numéro de maillage et d'un
//  // numéro de noeud, ceci pour éviter de  passer toute l'instance de la classe Les_maillages
//  // niveau: == 1 -> niveau minimum de sauvegarde, concerne uniquement la structure de l'élément
//
//  template <class T> int UnPack_vecteur(T& instance,int niveau,const Vecteur&  v,int rang,
//                      Noeud & (T::*Ptfonc) (int num_mail,int  num_noeud) const );
#endif

protected :  
    // VARIABLES PROTEGEES :
	 int actif; // un indicateur, disant si le contact est actif ou pas
					// conteneur plutôt utilisé par les classes appelantes 
	 // =1 -> premier contact, > 1 contact qui suit un contact
  
  // ... elfront, noeud, tabNoeud : peuvent changer d'affectation sur le pas
  //     pour pouvoir revenir au temps t, on définit les valeurs à t
  Front*  elfront, * elfront_t; // un element frontiere , qui est créé par l'élément de contact
   // et qui correspond à une copie d'un élément frontière qui existe par ailleurs
   // en fait, qui existe dans LesContacts
  Noeud * noeud, * noeud_t; // un pointeur de noeud
  // pour éviter de le construire à chaque demande on définit un tableau de tous les noeuds
  Tableau <Noeud*> tabNoeud, tabNoeud_t; // tableau de tous les noeud, le premier est noeud
  
  
  int num_zone_contact; // un stockage uniquement utilisé par les méthodes appelantes
  // le tableau des positions successives du noeud esclave, ceci pour effectuer une moyenne glissante
  Tableau <Coordonnee> tab_posi_esclave;
  // le nombre courant de positions de noeuds esclaves actuellement stockées
  int nb_posi_esclave_stocker_t,nb_posi_esclave_stocker_tdt;
  // indice dans tab_posi_esclave, du prochain stockage
  int indice_stockage_glissant_t,indice_stockage_glissant_tdt;
	  
  Coordonnee Mtdt,Mt; // sauvegarde du point d'intercection s'il est recevable
  Coordonnee M_noeud_tdt_avant_projection; // dans le cas d'une projection du noeud sur la surface maître
              // sauvegarde des coordonnées du noeuds esclave: utilisation avec le type de contact 4
  // les fonctions d'interpolation au premier point en contact: sert pour le contact collant
  Vecteur phi_theta_0 ; // phi(theta^i) phi des coordonnées en theta du premier point en contact
  Front* front_initiale; // la frontière initiale correspondante
  
  EnergieMeca energie_frottement; // énergie développée par le frottement glissant ou pas
  double energie_penalisation; // énergie due à la pénalisation (élastique a priori)
	 // cas_solide permet de simplifier le contact dans le cas ou le maître ou l'esclave est solide
	 // sert  pour diminuer la taille de la raideur uniquement
	 int cas_solide; // =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
  bool cas_collant; // prise en compte éventuelle d'un contact collant, si false : contact normal
      // = true : contact collant
  int normale_lisser; // indique si la normale doit-être lissée sur l'élément, ou non
      
  int nb_change_frontiere; // totalise sur un incrément le nb de fois de changement de front
  // sert à éviter les flip flop en implicite
  
	 Vecteur * residu; // residu local 
	 Mat_pleine * raideur; // raideur locale 
	 DdlElement * ddlElement_assemblage; // le ddlElement qui correspond 
  Tableau <Noeud*> tabNoeud_pour_assemblage; // tableau des noeuds qui servent pour l'assemblage
	 Coordonnee force_contact,force_contact_t; // force de contact sur le noeud principal
  double F_N_max,F_T_max,F_N_max_t,F_T_max_t; // les maxis constatés
  Tableau <Coordonnee> tabForce_cont,tabForce_cont_t; // le tableau des forces sur les noeuds de la facette
  Coordonnee N; // la dernière normale calculée
  Coordonnee dep_tangentiel; // le dernier déplacement tangentiel calculé
 
	 int nb_decol_t,nb_decol_tdt; // nombre de fois où le noeud décolle de manière consécutive
	 double gap_t,gap_tdt; // les pénétrations d'un pas à l'autre
  double dep_T_t, dep_T_tdt; // les valeurs absolue des déplacements tangentiels d'un pas à l'autre
	 double nb_pene_t,nb_pene_tdt; // le nombre de penetration positives
 
  // cas TypeCalculPenalisationPenetration() = 4 ou -4
  // -> cas d'un facteur multiplicatif évolutif, on fait une moyenne glissante de 2
  // on mémorise donc les facteurs multiplicatifs successifs
  double mult_pene_t,mult_pene_tdt;
  // cas TypeCalculPenalisationTangentielle() = 4 ou -4
  // -> cas d'un facteur multiplicatif évolutif, on fait une moyenne glissante de 2
  // on mémorise donc les facteurs multiplicatifs successifs
  double mult_tang_t,mult_tang_tdt;
 
  double penalisation,penalisation_tangentielle; // on sauvegarde la pénalisation
    // l'intérêt est de pouvoir la visualiser
  double penalisation_t,penalisation_tangentielle_t; // les grandeurs à t
  
  // utilisation de fct nD
  Fct_nD_contact fct_nD_contact;
 
  // pour le contact 4, pour le calcul de la pénalisation avec une moyenne glissante
  Tableau <double > val_penal; // tableau de stockage intermédiaire
  int pt_dans_val_penal;       // indice du prochain elem du tableau a remplir

	 // stocke le dernier type de trajectoire du noeud par rapport à la facette
	 // c-a-d la valeur de la variable test dans la fonction Trajectoire(int & test)
	 int type_trajectoire_t,type_trajectoire_tdt;
 
  // concernant les enum de ddl associées aux éléments de contact, on définit un tableau global
  // qui est utilisé par tous les éléments
  static list <DdlElement> list_Ddl_global; // liste de tous les DdlElements des éléments de contact
  static list <Vecteur> list_SM; // list de seconds membres locals: sert pour tous les éléments de contact
  static list <Mat_pleine> list_raideur; // list de raideurs locales:     "     "        "         "
	 // stockage du maximum de distance tolérée entre noeud à tdt et le projeté, sert pour éliminer les contacts aberrants
	 static double dep_max;
  static int niveau_commentaire;

  // stockage d'une fonction nD pour le pilotage du type de contact 4
  static Fonction_nD * fct_pilotage_contact4;
    
  // METHODES PROTEGEES :
  // calcul la normal en fonction de differente conditions
  Coordonnee Calcul_Normale (int dim, Plan & pl, Droite & dr,int indic);
  void Libere();
  // construction du tableau de tous les noeuds, le premier est celui esclave
  // et mise à jour de ddlElement et de list_Ddl_global éventuellement
  // et mise à jour des grandeurs liées à elfront: concerne le dimensionnement
  // si on change d'elfront -> peut changer le nombre de noeud maître d'où
  // il faut redimensionner: tabForce_cont,tabForce_cont_t;
  void Construction_TabNoeud();
  
  // récupération d'informations des classes internes pour le calcul du résidu
  // N: le vecteur normal
  // M_impact: le point d'impact sur la surface (ou ligne)
  // phii : les fonctions d'interpolation au point d'impact
	 // si avec_var est vrai: il y a retour du tableau de variation de la normale
	 Tableau <Coordonnee >* RecupInfo(Coordonnee& N,Coordonnee& M_impact,Vecteur& phii,bool avec_var );

	 // mise à jour de cas_solide et donc de ddlElement en fonction de l'activité des ddl
	 // mise à jour du tableau de noeud pour l'assemblage tabNoeud_pour_assemblage
	 void Mise_a_jour_ddlelement_cas_solide_assemblage();
  // récup  d'une place pour le résidu local et mise à jour de list_SM éventuellement
  void RecupPlaceResidu(int nbddl);
  // récup  d'une place pour la raideur locale et mise à jour de list_raideur éventuellement
  void RecupPlaceRaideur(int nbddl);
  // calcul du facteur de pénalisation en pénétration, en fonction de la géométrie
  // du module de compressibilité et des différents possibles
  // éventuellement, calcul de la dérivée: d_beta_gapdu, du facteur par rapport au gap
  // la sensibilité dépend du type de calcul du facteur de pénalisation
  double CalFactPenal(const double& gap,double & d_beta_gap,int contact_type);
  // calcul du facteur de pénalisation tangentielle, en fonction de la géométrie
  // du module de compressibilité et des différents cas possibles
  // éventuellement, calcul de la dérivée: d_beta_gapdu, du facteur par rapport au gap
  // la sensibilité dépend du type de calcul du facteur de pénalisation
  double CalFactPenalTangentiel(const double& gap,double & d_beta_gap);
	 // limitation éventuelle au niveau de la pénétration maxi
	 //void Limitation_penetration_maxi(
  // calcul éventuel de la moyenne glissante des positions successive du noeud esclave
  void ChangeEnMoyGlissante(Coordonnee& Noe_atdt);
 
  // calcul de la moyenne glissante de la pénalisation
  void Moyenne_glissante_penalisation(double& penalisation, double& essai_penalisation);
  
  // calcul d'une fonction nD relative à des données de contact
  double Valeur_fct_nD(Fonction_nD * fct_nD,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 "ElContact_3.cc"
#define  ElContact_deja_inclus

#endif  
