diff --git a/contact/Cercle.cc b/contact/Cercle.cc
new file mode 100644
index 0000000..90e3943
--- /dev/null
+++ b/contact/Cercle.cc
@@ -0,0 +1,416 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+#include "Cercle.h"
+#include "MathUtil.h"
+#include "ParaGlob.h"
+
+ // CONSTRUCTEURS :
+// par defaut
+Cercle::Cercle () :
+ centre(),rayon(0.),N(NULL)
+ { if (ParaGlob::Dimension()== 1)
+ { cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
+ cout << "\nCercle::Cercle ()" << endl;
+ Sortie(1);
+ };
+ };
+// avec les datas
+Cercle::Cercle ( const Coordonnee& B, const double& r , const Coordonnee* No):
+ centre(B),rayon(r),N(NULL)
+ { if (ParaGlob::Dimension()== 1)
+ { cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
+ cout << "\nCercle::Cercle ()" << endl;
+ Sortie(1);
+ };
+ if (rayon < 0.)
+ { cout << "\n erreur dans la construction d'un Cercle, le rayon " << rayon
+ << " est negatif !! ";
+ Sortie(1);
+ };
+ if (ParaGlob::Dimension() == 3)
+ if (No != NULL)
+ { N = new Coordonnee(*No);
+ double norme = N->Norme();
+ if (norme < ConstMath::petit)
+ { cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
+ << " a une norme (=" << norme <<") trop petite !! " ;
+ Sortie(1);
+ };
+ (*N) /= norme; // on normalise le vecteur
+ };
+ // sinon la normale n'existe pas, il faudra la définir
+ };
+// avec la dimension
+Cercle::Cercle (int dim):
+ centre(dim),rayon(0.),N(NULL)
+ { if (ParaGlob::Dimension()== 1)
+ { cout << "\nErreur : la dimension est 1 et on veut utiliser un cercle ??? ";
+ cout << "\nCercle::Cercle ()" << endl;
+ Sortie(1);
+ };
+ };
+ // de copie
+Cercle::Cercle ( const Cercle& a):
+ centre(a.centre),rayon(a.rayon),N(NULL)
+ { if (ParaGlob::Dimension() == 3)
+ if (a.N != NULL) // a priori il est normé
+ { N = new Coordonnee(*(a.N));};
+ // sinon la normale n'existe pas, il faudra la définir
+ };
+
+ // DESTRUCTEUR :
+Cercle::~Cercle ()
+ { if (N != NULL)
+ {delete N;N=NULL;};
+ };
+
+// surcharge des operator
+Cercle& Cercle::operator = ( const Cercle & cer)
+ { centre = cer.centre; rayon = cer.rayon;
+ if (ParaGlob::Dimension() == 3)
+ if (cer.N != NULL) // a priori la normale est normée
+ { N = new Coordonnee(*(cer.N));};
+ // sinon la normale n'existe pas, il faudra la définir
+ return *this;
+ };
+
+// METHODES PUBLIQUES :
+
+// change le centre du Cercle
+void Cercle::Change_centre( const Coordonnee& B)
+ {
+ #ifdef MISE_AU_POINT
+ if (B.Dimension() != centre.Dimension())
+ { cout << "\nErreur : les dimensions du centre et du vecteur ne sont pas identique !";
+ cout <<"\ndim B = " <Norme();
+ if (norme < ConstMath::petit)
+ { cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
+ << " a une norme (=" << norme <<") trop petite !! " ;
+ cout << "\nCercle::Change_Normale( const Coordonnee& No)" << endl;
+ Sortie(1);
+ };
+ (*N) /= norme; // on normalise le vecteur
+ };
+ };
+
+
+
+// change toutes les donnees
+void Cercle::change_donnees( const Coordonnee& B, const double& r,const Coordonnee* No)
+ {
+ #ifdef MISE_AU_POINT
+ if (B.Dimension() != centre.Dimension())
+ { cout << "\nErreur : les dimensions du centre et du vecteur ne sont pas identique !";
+ cout <<"\ndim B = " <Dimension() != 3)
+ { cout << "\nErreur : la dimension de la normale devrait etre 3 alors qu'elle est : "
+ <Dimension() <<" ";
+ cout << "\nCercle::change_donnees()" << endl;
+ Sortie(1);
+ };
+ #endif
+ if (N == NULL)
+ { N = new Coordonnee (*No);}
+ else
+ { *N = *No;};
+ double norme = N->Norme();
+ if (norme < ConstMath::petit)
+ { cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
+ << " a une norme (=" << norme <<") trop petite !! " ;
+ cout << "\nCercle::change_donnees(.." << endl;
+ Sortie(1);
+ };
+ (*N) /= norme; // on normalise le vecteur
+ };
+
+ };
+
+// calcul les deux intercections M1 et M2 d'une droite avec le Cercle,
+// ramene 0 s'il n'y a pas d'intersection, ramene -1 si l'intersection
+// ne peut pas etre calculee
+// et 1 s'il y a deux points d'intercection
+int Cercle::Intersection( const Droite & dr,Coordonnee& M1, Coordonnee& M2)
+{switch (ParaGlob::Dimension())
+ {case 2:
+ {// C le centre du cercle, H la projection de C sur la droite
+ // M1 et M2 les deux intersections potentielles
+ const Coordonnee& A = dr.PointDroite(); // pour simplifier
+ const Coordonnee& U = dr.VecDroite();
+ Coordonnee CA = A - centre;
+ double ah = - CA * U;
+ Coordonnee CH = CA + ah * U;
+ double ch_2 = CH * CH;
+ if (sqrt(ch_2) > rayon)
+ return 0; // cas pas d'intersection
+ // sinon
+ double hm = sqrt(rayon*rayon - ch_2);
+ M1 = centre + CH + hm * U;
+ M2 = centre + CH - hm * U;
+ return 1;
+ break;
+ }
+ case 3:
+ {
+ #ifdef MISE_AU_POINT
+ if (N==NULL)
+ { cout << "\nErreur : la normale au cercle n'est pas defini, "
+ << " on ne peut pas calculer la distance au cercle ";
+ cout << "\nCercle::Distance_au_Cercle()" << endl;
+ Sortie(1);
+ };
+ #endif
+ // on calcul le projeté sur le plan d'un point de la droite
+ const Coordonnee& A = dr.PointDroite(); // pour simplifier
+ const Coordonnee& U = dr.VecDroite();
+ Coordonnee CA = A-centre;
+ double ha = CA*(*N); // distance du point au plan du cercle
+ if (ha > ConstMath::pasmalpetit)
+ return 0; // cas pas d'intersection
+ // sinon le point appartient au plan: même procédure qu'en 2D
+ // C le centre du cercle, H la projection de C sur la droite
+ // M1 et M2 les deux intersections potentielles
+ double ah = - CA * U;
+ Coordonnee CH = CA + ah * U;
+ double ch_2 = CH * CH;
+ if (sqrt(ch_2) > rayon)
+ return 0; // cas pas d'intersection
+ // sinon
+ double hm = sqrt(rayon*rayon - ch_2);
+ M1 = centre + CH + hm * U;
+ M2 = centre + CH - hm * U;
+ return 1;
+ break;
+ }
+ case 1:
+ { cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
+ cout << "\nCercle::Intersection(.." << endl;
+ Sortie(1);
+ };
+ };
+ // normalement on n'arrive jamais ici
+ return -1;
+};
+
+// calcul la distance d'un point au Cercle
+double Cercle::Distance_au_Cercle(const Coordonnee& M) const
+ { switch (ParaGlob::Dimension())
+ {case 2:
+ return Dabs((centre - M).Norme()-rayon);break;
+ case 3:
+ {
+ #ifdef MISE_AU_POINT
+ if (N==NULL)
+ { cout << "\nErreur : la normale au cercle n'est pas defini, "
+ << " on ne peut pas calculer la distance au cercle ";
+ cout << "\nCercle::Distance_au_Cercle()" << endl;
+ Sortie(1);
+ };
+ #endif
+ // on calcul le projeté sur le plan
+ Coordonnee CM = M-centre;
+ double cm = (CM*(*N));
+ Coordonnee CH = CM - cm * (*N);
+ // calcul du point intersection CH avec le cercle -> E
+ double ch = CH.Norme();
+ if (ch < ConstMath::trespetit)
+ { // cela veut dire que le point M est sur l'axe du cercle
+ return (sqrt(cm*cm + rayon*rayon));
+ }
+ else
+ { Coordonnee CE = CH * (rayon/ch);
+ return (CM-CE).Norme();
+ };
+ break;
+ }
+ case 1:
+ { cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
+ cout << "\nCercle::Distance_au_Cercle()" << endl;
+ Sortie(1);
+ };
+ };
+ // normalement on n'arrive jamais ici
+ return ConstMath::tresgrand;
+ };
+
+// calcul du projeté d'un point sur le plan
+Coordonnee Cercle::Projete(const Coordonnee& M) const
+ { switch (ParaGlob::Dimension())
+ {case 2: // le projeté est directement M
+ return M;break;
+ case 3:
+ {
+ #ifdef MISE_AU_POINT
+ if (N==NULL)
+ { cout << "\nErreur : la normale au cercle n'est pas defini, "
+ << " on ne peut pas calculer la distance au cercle ";
+ cout << "\nCercle::Projete(.." << endl;
+ Sortie(1);
+ };
+ #endif
+ // on calcul le projeté sur le plan
+ return (M - ((M-centre)* (*N))* (*N));
+ break;
+ }
+ case 1:
+ { cout << "\nErreur : la dimension est 1 et on utilise un cercle ??? ";
+ cout << "\nCercle::Projete(.." << endl;
+ Sortie(1);
+ };
+ };
+ // normalement on n'arrive jamais ici
+ Coordonnee toto; // on fait en deux fois pour la version linux
+ return (toto);
+ };
+
+// fonction valable uniquement en 2D, sinon erreur
+// ramène true si le point est à l'intérieur du cercle, false sinon
+bool Cercle::Dedans(const Coordonnee& M)const
+{ if (ParaGlob::Dimension() == 2)
+ { return ((M-centre).Norme() < rayon);}
+ else
+ { cout << "\n erreur, la fonction Cercle::Dedans(... n'est utilisable "
+ << " qu'en dimension 2D, alors que l'on est en " << ParaGlob::Dimension() << " ";
+ Sortie(1);
+ return false; // pour éviter un warning
+ };
+ };
+
+// surcharge de l'operateur de lecture
+istream & operator >> (istream & entree, Cercle & cer)
+ { // vérification du type
+ string nom;
+ entree >> nom;
+ #ifdef MISE_AU_POINT
+ if (nom != "_cercle_")
+ { cout << "\nErreur, en lecture d'une instance cercle "
+ << " on attendait _cercle_ et on a lue: " << nom ;
+ cout << "istream & operator >> (istream & entree, Cercle & cer)\n";
+ Sortie(1);
+ };
+ #endif
+ // puis lecture des différents éléments
+ entree >> nom >> cer.centre >> nom >> cer.rayon;
+ bool existe_N;
+ entree >> existe_N;
+ if (existe_N)
+ { if (cer.N == NULL)
+ cer.N = new Coordonnee(ParaGlob::Dimension());
+ entree >> (*(cer.N));
+ double norme = cer.N->Norme();
+ if (norme < ConstMath::petit)
+ { cout << "\n erreur dans la construction d'un Cercle, le vecteur normal "
+ << " a une norme (=" << norme <<") trop petite !! " ;
+ cout << "\nCercle::change_donnees(.." << endl;
+ Sortie(1);
+ };
+ (*cer.N) /= norme; // on normalise le vecteur
+ }
+ else
+ { if (cer.N != NULL)
+ delete cer.N;
+ };
+ return entree;
+ };
+
+// surcharge de l'operateur d'ecriture
+ostream & operator << ( ostream & sort,const Cercle & cer)
+ { // tout d'abord un indicateur donnant le type
+ sort << " _cercle_ " ;
+ // puis les différents éléments
+ sort << "\n C= " << cer.centre << " r= " << cer.rayon << " ";
+ if (cer.N == NULL)
+ { sort << 0 ;}
+ else
+ { sort << 1 << (*(cer.N)) << " " ;}
+ return sort;
+ };
diff --git a/contact/Cercle.h b/contact/Cercle.h
new file mode 100644
index 0000000..62a4be9
--- /dev/null
+++ b/contact/Cercle.h
@@ -0,0 +1,137 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 19/01/2007 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: Def géométrie d'un cercle: un centre , un rayon *
+ * et une normale au plan du cercle dans le cas 3D *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * VERIFICATION: *
+ * *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * ! ! ! ! *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' *
+ * MODIFICATIONS: *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * $ *
+ ************************************************************************/
+#ifndef CERCLEE_H
+#define CERCLEE_H
+
+#include "Droite.h"
+#include "Coordonnee.h"
+
+/// @addtogroup Groupe_sur_les_contacts
+/// @{
+///
+
+
+class Cercle
+{ // surcharge de l'operator de lecture
+ friend istream & operator >> (istream &, Cercle &);
+ // surcharge de l'operator d'ecriture
+ friend ostream & operator << (ostream &, const Cercle &);
+
+ public :
+ // CONSTRUCTEURS :
+ // par defaut
+ Cercle ();
+ // avec les datas
+ Cercle ( const Coordonnee& B, const double& r, const Coordonnee* N);
+ // avec la dimension
+ Cercle (int dim);
+ // de copie
+ Cercle ( const Cercle& a);
+ // DESTRUCTEUR :
+ ~Cercle ();
+ // surcharge des operator
+ Cercle& operator = ( const Cercle & P);
+
+ // METHODES PUBLIQUES :
+ // retourne le centre du Cercle
+ inline const Coordonnee& CentreCercle() const { return centre;};
+ // retourne le rayon du Cercle
+ inline double RayonCercle() const { return rayon;};
+ // retourne la normale au cercle en 3D sinon NULL
+ inline const Coordonnee* NormaleCercle() const { return N;};
+
+ // change le centre du Cercle
+ void Change_centre( const Coordonnee& B);
+ // change le rayon du Cercle
+ void Change_rayon( const double & r);
+ // change la normale au Cercle en 3D, sinon c'est inutile, warning
+ void Change_Normale( const Coordonnee& N);
+ // change toutes les donnees
+ // N n'est utilisé qu'en 3D, en 2D on met NULL
+ void change_donnees( const Coordonnee& B, const double& r,const Coordonnee* N);
+
+ // calcul les deux intercections M1 et M2 d'une droite avec le Cercle,
+ // ramene 0 s'il n'y a pas d'intersection, ramene -1 si l'intercection
+ // ne peut pas etre calculee
+ // et 1 s'il y a deux points d'intercection
+ int Intersection( const Droite & D,Coordonnee& M1, Coordonnee& M2);
+
+ // calcul la distance d'un point au Cercle
+ double Distance_au_Cercle(const Coordonnee& M) const;
+
+ // calcul du projeté d'un point sur le plan
+ Coordonnee Projete(const Coordonnee& M) const;
+
+ // indique si oui ou non le projeté du point est dans le cercle
+ bool ProjeteDedans(const Coordonnee& M) const
+ { return ((Projete(M)-centre).Carre() < rayon*rayon);};
+
+ // fonction valable uniquement en 2D, sinon erreur
+ // ramène true si le point est à l'intérieur du cercle, false sinon
+ bool Dedans(const Coordonnee& M)const ;
+
+
+
+ protected :
+ // VARIABLES PROTEGEES :
+ Coordonnee centre; // centre du Cercle
+ double rayon; // rayon du Cercle
+ Coordonnee* N; // normal au cercle : utilisé qu'en 3D
+ // la grandeur stockée est normée
+ // METHODES PROTEGEES :
+
+ };
+ /// @} // end of group
+
+#endif
diff --git a/contact/Cylindre.cc b/contact/Cylindre.cc
new file mode 100644
index 0000000..ab95d6e
--- /dev/null
+++ b/contact/Cylindre.cc
@@ -0,0 +1,189 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+#include "Cylindre.h"
+#include "MathUtil.h"
+#include "ParaGlob.h"
+
+ // CONSTRUCTEURS :
+// par defaut
+Cylindre::Cylindre () :
+ cercle(3)
+ { if (ParaGlob::Dimension() != 3)
+ { cout << "\nErreur : la dimension est differente de 3 et on veut utiliser un Cylindre ??? ";
+ cout << "\nCylindre::Cylindre ()" << endl;
+ Sortie(1);
+ };
+ };
+// avec les datas
+Cylindre::Cylindre ( const Cercle& cer):
+ cercle(cer)
+ { if (ParaGlob::Dimension() != 3)
+ { cout << "\nErreur : la dimension est differente de 3 et on veut utiliser un Cylindre ??? ";
+ cout << "\nCylindre::Cylindre (.." << endl;
+ Sortie(1);
+ };
+ };
+
+// avec la dimension
+Cylindre::Cylindre (int dim):
+ cercle(dim)
+ { if (ParaGlob::Dimension() != 3)
+ { cout << "\nErreur : la dimension est differente de 3 et on veut utiliser un Cylindre ??? ";
+ cout << "\nCylindre::Cylindre ()" << endl;
+ Sortie(1);
+ };
+ if (dim != 3)
+ { cout << "\nErreur : la dimension demandee est differente de 3 et on veut utiliser un Cylindre ??? ";
+ cout << "\nCylindre::Cylindre ()" << endl;
+ Sortie(1);
+ };
+ };
+
+// de copie
+Cylindre::Cylindre ( const Cylindre& a):
+ cercle(a.cercle)
+ { };
+
+ // DESTRUCTEUR :
+Cylindre::~Cylindre ()
+ { };
+
+// surcharge des operator
+Cylindre& Cylindre::operator = ( const Cylindre & cer)
+ { cercle = cer.cercle;
+ return *this;
+ };
+
+// METHODES PUBLIQUES :
+
+// change le cercle du Cylindre
+void Cylindre::Change_cercle( const Cercle& cer)
+ {
+ #ifdef MISE_AU_POINT
+ if (cer.CentreCercle().Dimension() != cercle.CentreCercle().Dimension())
+ { cout << "\nErreur : les dimensions du cercle demande n'est pas identique a celle existante !";
+ cout <<"\ndim nouveau = " <> (istream & entree, Cylindre & cer)
+ { // vérification du type
+ string nom;
+ entree >> nom;
+ #ifdef MISE_AU_POINT
+ if (nom != "_Cylindre_")
+ { cout << "\nErreur, en lecture d'une instance Cylindre "
+ << " on attendait _Cylindre_ et on a lue: " << nom ;
+ cout << "istream & operator >> (istream & entree, Cylindre & cer)\n";
+ Sortie(1);
+ };
+ #endif
+ // puis lecture des différents éléments
+ entree >> nom >> cer.cercle ;
+ return entree;
+ };
+
+// surcharge de l'operateur d'ecriture
+ostream & operator << ( ostream & sort,const Cylindre & cer)
+ { // tout d'abord un indicateur donnant le type
+ sort << " _Cylindre_ " ;
+ // puis les différents éléments
+ sort << "\n Cercle= " << cer.cercle << " ";
+ return sort;
+ };
diff --git a/contact/Cylindre.h b/contact/Cylindre.h
new file mode 100644
index 0000000..39092ea
--- /dev/null
+++ b/contact/Cylindre.h
@@ -0,0 +1,121 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 19/01/2007 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: Def géométrie d'un cylindre: un cercle 3D, donc avec une *
+ * normale. Le cylindre n'est pas limité en hauteur. *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * VERIFICATION: *
+ * *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * ! ! ! ! *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' *
+ * MODIFICATIONS: *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * $ *
+ ************************************************************************/
+#ifndef CYLINDREE_H
+#define CYLINDREE_H
+
+#include "Droite.h"
+#include "Coordonnee.h"
+#include "Cercle.h"
+
+/// @addtogroup Groupe_sur_les_contacts
+/// @{
+///
+
+
+class Cylindre
+{ // surcharge de l'operator de lecture
+ friend istream & operator >> (istream &, Cylindre &);
+ // surcharge de l'operator d'ecriture
+ friend ostream & operator << (ostream &, const Cylindre &);
+
+ public :
+ // CONSTRUCTEURS :
+ // par defaut
+ Cylindre ();
+ // avec les datas
+ Cylindre ( const Cercle& B);
+ // avec la dimension
+ Cylindre (int dim);
+ // de copie
+ Cylindre ( const Cylindre& a);
+ // DESTRUCTEUR :
+ ~Cylindre ();
+ // surcharge des operator
+ Cylindre& operator = ( const Cylindre & P);
+
+ // METHODES PUBLIQUES :
+ // retourne le cercle d'embase du Cylindre
+ inline const Cercle& CercleCylindre() const { return cercle;};
+
+ // change le centre du Cylindre
+ void Change_cercle( const Cercle& B);
+ // change toutes les donnees
+ void change_donnees( const Cercle& cer);
+
+ // calcul les deux intercections M1 et M2 d'une droite avec le Cylindre,
+ // ramene 0 s'il n'y a pas d'intersection, ramene -1 si l'intercection
+ // ne peut pas etre calculee
+ // et 1 s'il y a deux points d'intercection
+ int Intersection( const Droite & D,Coordonnee& M1, Coordonnee& M2);
+
+ // calcul la distance d'un point au Cylindre
+ double Distance_au_Cylindre(const Coordonnee& M) const;
+
+ // ramène true si le point est à l'intérieur du cylindre, false sinon
+ bool Dedans(const Coordonnee& M)const ;
+
+ // projection d'un point M sur la parois du cylindre
+ // dans le cas où M appartient à l'axe du cylindre, la projection n'est pas
+ // possible, dans ce cas projection_ok = false en retour, sinon true
+ Coordonnee Projete(const Coordonnee& M,bool& projection_ok) const;
+
+ protected :
+ // VARIABLES PROTEGEES :
+ Cercle cercle; // cercle du Cylindre
+ // METHODES PROTEGEES :
+
+ };
+ /// @} // end of group
+
+#endif
diff --git a/contact/Droite.cc b/contact/Droite.cc
new file mode 100644
index 0000000..5ad2293
--- /dev/null
+++ b/contact/Droite.cc
@@ -0,0 +1,345 @@
+//#include "Debug.h"
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+
+#include "Droite.h"
+#include "ConstMath.h"
+#include "MathUtil.h"
+#include "Util.h"
+
+//----------------------------------------------------------------
+// def des donnees commune a toutes les droites
+//----------------------------------------------------------------
+int Droite::alea = 0;
+
+ // CONSTRUCTEURS :
+// par defaut
+// par defaut définit une droit // à x et passant par 0, et de dimension celle de l'espace de travail
+Droite::Droite () :
+ A(ParaGlob::Dimension()), U(ParaGlob::Dimension())
+ { // on met une valeur 1 par défaut sur U
+ U(1)=1.;
+ };
+// avec les datas
+Droite::Droite ( const Coordonnee& B, const Coordonnee& vec) :
+ A(B), U(vec)
+ {
+ #ifdef MISE_AU_POINT
+ if (B.Dimension() != vec.Dimension())
+ { cout << "\nErreur : les dimensions du point et du vecteur ne sont pas identique !";
+ cout <<"\ndim point = " <A = P.A; this->U = P.U;
+ return *this;
+ };
+
+ // METHODES PUBLIQUES :
+
+ // change le point de ref de la droite
+void Droite::Change_ptref( const Coordonnee& B)
+ {
+ #ifdef MISE_AU_POINT
+ if (B.Dimension() != U.Dimension())
+ { cout << "\nErreur : les dimensions du point et du vecteur ne sont pas identique !";
+ cout <<"\ndim point = " <= ConstMath::petit) //pasmalpetit)
+ // trop de distance entre les deux droites -> pas d'Intersection
+ return 0;
+ }
+ }
+ break;
+ case 2:
+ { // on regarde si les droites ne sont pas //
+ if ( Dabs(1.-Dabs(U*V)) < ConstMath::petit) //pasmalpetit)
+ // soit les droites sont distinctes soit elles sont confondues
+ // mais dans tous les cas, on ne peut pas calculer un seul point d'intersection
+ return 0;
+ }
+ break;
+ case 1:
+ { // en 1D on considère que l'on ne peut pas calculer un seul point d'intersection
+ return 0;
+ }
+ break;
+ default:
+ cout << "\n erreur, on ne devrait pas passer par ici !!! "
+ << "\n *** Droite::Intersection( const Droite & D,Coordonnee& M) " << endl;
+ Sortie(1);
+ };
+ // cas ou l'Intersection existe
+ // détail du calcul du point M = intersection
+ // on a: vec(AB) = vec(AM) + vec(MB) = alpha U + beta V
+ // d'où : (1): AB*U = alpha - beta U*V et (2): AB*V = alpha U*V - beta
+ // on fait (1) * (-U*V) + (2) -> - (AB*U) (U*V) + (AB*V) = beta ((U*V)^2 -1)
+ // et BM = beta V
+
+
+ double uv = U * V;
+ double beta = -((AB * U) * uv - (AB * V)) / (uv * uv -1.);
+ M = B + beta * V;
+////--- debug
+//cout << "\n debug Droite::Intersection( ";
+//A.Affiche(cout, 10); M.Affiche(cout, 10); cout << "\n" << endl;
+//cout << "\n uv= " << uv << ", V: " << V(1) << " " << V(2) << " V= " << sqrt(V(1)*V(1)+V(2)*V(2))
+// << " B: " << B(1) << " " << B(2) << ", AB: " << AB(1) << " " << AB(2) << ", beta= " << beta;
+//double diff = (B-M)*(A-M); cout << " (B-M)*(A-M) "<< diff;
+//
+//cout << "\n A: " << A(1) << " " << A(2) << ", U: " << U(1) << " " << U(2)
+// << ", M: " << M(1) << " " << M(2) << endl;
+////--- fin debug
+
+ return 1;
+ };
+
+// calcul si un point donné appartient ou non à la droite (à la précision donnée)
+bool Droite::Appartient_a_la_droite(const Coordonnee& B)
+ { // le point B appartient à la droite lorsque AB est // à U donc que le produit
+ // vectoriel de ces deux vecteurs est nul en 3D, en 2D c'est le déterminant et en 1D c'est toujours ok
+ Coordonnee AB = B-A;
+ switch (AB.Dimension())
+ { case 1 : // la collinéarité est obligatoire ici
+ return true; break;
+ case 2 : // examen du déterminant
+// if (Abs(Util::Determinant(U,AB)) <= ConstMath::pasmalpetit) return true; else return false;
+ if (Abs(Util::Determinant(U,AB)) <= ConstMath::petit) return true; else return false;
+ break;
+ case 3 :
+// if((Util::ProdVec_coor(U,AB)).Norme() <= ConstMath::pasmalpetit) return true; else return false;
+ if((Util::ProdVec_coor(U,AB)).Norme() <= ConstMath::petit) return true; else return false;
+ break;
+ default :
+ cout << "\nErreur : la dimension de AB est nulle !, suite des calculs impossible\n";
+ cout << "Droite::Appartient_a_la_droite... \n";
+ Sortie(1);
+ };
+ // ne doit jamais passer ici mais pour taire le compilo ....
+ Sortie(1);
+ return false;
+ };
+
+// ramene une normale, en 2D il y a une seule solution, en 3D a chaque appel on ramene
+// une nouvelle normale calculée aleatoirement
+Coordonnee Droite::UneNormale()
+ { // on considere la dimension
+ switch (A.Dimension())
+ { case 2:
+ // cas ou l'on est en dimension 2
+ { Coordonnee ve(2);
+ ve(1) = -U(2);
+ ve(2) = U(1);
+ return ve;
+ }
+ break;
+ case 3: // cas où l'on est en dimension 3
+ { Coordonnee ve(3);
+ Coordonnee v1(3),v2(3);
+ // on cherche un vecteur du plan normal a la droite : v1
+ v2(1) = 1.;
+ v1 = Util::ProdVec_coor(U,v2);
+ double r = v1.Norme();
+ if (r <= ConstMath::petit)
+ // cas U // v2
+ { v2(2) = 1.; v2(1) = 0;
+ v1 = Util::ProdVec_coor(U,v2);
+ };
+ // maintenant le second
+ v2 = Util::ProdVec_coor(U,v1);
+ // on genere un angle aleatoirement -> un cos
+ double cos = ((double)rand())/RAND_MAX;
+ // et le vecteur correspondant
+ ve = cos * v1 + (1.-cos) * v2;
+ // update le nombre aleatoire
+ alea++; srand((unsigned) alea);
+ return ve;
+ }
+ break;
+ }
+ };
+
+// calcul la distance d'un point à la droite
+double Droite::Distance_a_la_droite(const Coordonnee& M) const
+ { int dima = ParaGlob::Dimension();
+ Coordonnee AM(M-A);
+ Coordonnee HM(AM-(AM * U)*U);
+ return HM.Norme();
+ };
+
+// fonction valable uniquement en 2D !!!, sinon erreur
+// ramène true si les deux points sont du même coté de la droite, false sinon
+bool Droite::DuMemeCote(const Coordonnee& M1, const Coordonnee& M2) const
+ { if (ParaGlob::Dimension() == 2)
+ {
+ // erreur 12 avril 2011: correction, il faut utiliser le déterminant et non le produit vectoriel
+ // return ((Util::ProdVec_coor(U,(M1-A)) * Util::ProdVec_coor(U,(M2-A))) >= 0.);
+ return ((Util::Determinant(U,(M1-A)) * Util::Determinant(U,(M2-A))) >= 0.);
+ }
+ else
+ { cout << "\n erreur, la fonction Droite::DuMemeCote(.., n'est pas utilisable pour une dimension "
+ << " differente de 2D ";
+ Sortie(1);
+ return false; // pour éviter un warning
+ }
+ };
+
+// surcharge de l'operateur de lecture
+istream & operator >> (istream & entree, Droite & dr)
+ { // vérification du type
+ string nom;
+ entree >> nom;
+ #ifdef MISE_AU_POINT
+ if (nom != "_droite_")
+ { cout << "\nErreur, en lecture d'une instance Droite "
+ << " on attendait _droite_ et on a lue: " << nom ;
+ cout << "istream & operator >> (istream & entree, Droite & dr)\n";
+ Sortie(1);
+ };
+ #endif
+ // puis lecture des différents éléments
+ entree >> nom >> dr.A >> nom >> dr.U;
+ return entree;
+ };
+
+// surcharge de l'operateur d'ecriture
+ostream & operator << ( ostream & sort,const Droite & dr)
+ { // tout d'abord un indicateur donnant le type
+ sort << " _droite_ " ;
+ // puis les différents éléments
+ sort << "\n A= " << dr.A << " U= " << dr.U << " ";
+ return sort;
+ };
+
diff --git a/contact/Droite.h b/contact/Droite.h
new file mode 100644
index 0000000..884b0a9
--- /dev/null
+++ b/contact/Droite.h
@@ -0,0 +1,135 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 23/01/97 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: Def de la geometrie d'une droite: un point et un vecteur *
+ * directeur. *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * VERIFICATION: *
+ * *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * ! ! ! ! *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' *
+ * MODIFICATIONS: *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * $ *
+ ************************************************************************/
+#ifndef DROITE_H
+#define DROITE_H
+
+#include "Coordonnee.h"
+
+/// @addtogroup Groupe_sur_les_contacts
+/// @{
+///
+
+
+class Droite
+{ // surcharge de l'operator de lecture
+ friend istream & operator >> (istream &, Droite &);
+ // surcharge de l'operator d'ecriture
+ friend ostream & operator << (ostream &, const Droite &);
+
+ public :
+ // CONSTRUCTEURS :
+ // par defaut définit une droit // à x et passant par 0, et de dimension celle de l'espace de travail
+ Droite ();
+ // avec les datas
+ // vec est quelconque, non norme
+ Droite ( const Coordonnee& B, const Coordonnee& vec);
+ // avec la dimension: la droite générée par défaut est une droite qui passe par 0 et est // à l'axe des x
+ Droite (int dim);
+ // de copie
+ Droite ( const Droite& a);
+ // DESTRUCTEUR :
+ ~Droite ();
+ // surcharge des operator
+ Droite& operator = ( const Droite & P);
+
+ // METHODES PUBLIQUES :
+ // retour le point de ref la droite
+ inline const Coordonnee& PointDroite() const { return A;};
+ // retourne le vecteur directeur de la droite (de norme = 1 )
+ inline const Coordonnee& VecDroite() const { return U;};
+
+ // change la dimension de la droite
+ void Change_dim(int dima) {A.Change_dim(dima);U.Change_dim(dima);};
+ // change le point de ref de la droite
+ void Change_ptref( const Coordonnee& B);
+ // change le vecteur de la droite
+ void Change_vect( const Coordonnee& vec);
+ // change toutes les donnees
+ void change_donnees( const Coordonnee& B, const Coordonnee& vec);
+
+ // calcul l'intercection M de la droite avec une autre droite, ramene 0 s'il n'y
+ // a pas d'Intersection, ramene -1 si l'Intersection ne peut pas etre calculee
+ // et 1 s'il y a un point d'Intersection
+ int Intersection( const Droite & D,Coordonnee& M);
+
+ // calcul si un point donné appartient ou non à la droite (à la précision donnée)
+ bool Appartient_a_la_droite(const Coordonnee& B);
+
+ // ramene une normale, en 2D il y a une solution, en 3D a chaque appel on ramene
+ // une nouvelle normale calculée aleatoirement
+ Coordonnee UneNormale();
+
+ // calcul la distance d'un point à la droite
+ double Distance_a_la_droite(const Coordonnee& M) const;
+
+ // calcul du projeté d'un point sur la doite
+ Coordonnee Projete(const Coordonnee& M) const
+ {return (A+((M-A)*U) * U);};
+
+ // fonction valable uniquement en 2D !!!, sinon erreur
+ // ramène true si les deux points sont du même coté de la droite, false sinon
+ bool DuMemeCote(const Coordonnee& M1, const Coordonnee& M2) const;
+
+
+ protected :
+ // VARIABLES PROTEGEES :
+ Coordonnee A; // un point de la droite
+ Coordonnee U; // vecteur directeur de la droite
+ static int alea; // une variables aleatoire qui sert pour la sortie d'une normale
+ // aleatoire en 3D
+ // METHODES PROTEGEES :
+ };
+ /// @} // end of group
+
+#endif
diff --git a/contact/ElContact.cc b/contact/ElContact.cc
new file mode 100644
index 0000000..18084d7
--- /dev/null
+++ b/contact/ElContact.cc
@@ -0,0 +1,1759 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+
+#include "ElContact.h"
+#include "Droite.h"
+#include "ConstMath.h"
+#include "MathUtil.h"
+#include "ElemMeca.h"
+#include "Util.h"
+#include
+#include "TypeConsTens.h"
+#include "Enum_TypeQuelconque.h"
+#include "TypeQuelconqueParticulier.h"
+
+ using namespace std;
+
+//---------- variables statiques --------------
+list ElContact::list_Ddl_global; // liste de tous les DdlElements des éléments de contact
+list ElContact::list_SM; // list de second membre local: sert pour tous les éléments de contact
+list ElContact::list_raideur; // list des raideurs locales: " " " "
+// stockage du maximum de distance tolérée entre noeud à tdt et le projeté, sert pour éliminer les contacts aberrants
+double ElContact::dep_max=1.e15; // au début un nombre très grand par défaut
+int ElContact::niveau_commentaire=0; // init par défaut -> est mis à jour par les_contacts
+Fonction_nD * ElContact::fct_pilotage_contact4=NULL ; // pour le pilotage du type de contact 4
+
+//----------- fin variables statiques ----------
+
+///------- particularité class Fct_nD_contact ------------------
+ElContact::Fct_nD_contact::Fct_nD_contact():
+ fct_nD_penalisationPenetration(NULL)
+ ,fct_nD_penetration_contact_maxi(NULL)
+ ,fct_nD_penetration_borne_regularisation(NULL)
+ ,fct_nD_force_contact_noeud_maxi(NULL)
+ ,fct_nD_penalisationTangentielle(NULL)
+ ,fct_nD_tangentielle_contact_maxi(NULL)
+ ,fct_nD_tangentielle_borne_regularisation(NULL)
+ ,fct_nD_force_tangentielle_noeud_maxi(NULL)
+ {};
+
+ElContact::Fct_nD_contact::Fct_nD_contact(const Fct_nD_contact& a) :
+ fct_nD_penalisationPenetration(a.fct_nD_penalisationPenetration)
+ ,fct_nD_penetration_contact_maxi(a.fct_nD_penetration_contact_maxi)
+ ,fct_nD_penetration_borne_regularisation(a.fct_nD_penetration_borne_regularisation)
+ ,fct_nD_force_contact_noeud_maxi(a.fct_nD_force_contact_noeud_maxi)
+ ,fct_nD_penalisationTangentielle(a.fct_nD_penalisationTangentielle)
+ ,fct_nD_tangentielle_contact_maxi(a.fct_nD_tangentielle_contact_maxi)
+ ,fct_nD_tangentielle_borne_regularisation(a.fct_nD_tangentielle_borne_regularisation)
+ ,fct_nD_force_tangentielle_noeud_maxi(a.fct_nD_force_tangentielle_noeud_maxi)
+ {};
+
+ElContact::Fct_nD_contact::~Fct_nD_contact()
+ {};
+
+ElContact::Fct_nD_contact& ElContact::Fct_nD_contact::operator= (const ElContact::Fct_nD_contact& a)
+ {fct_nD_penalisationPenetration = a.fct_nD_penalisationPenetration;
+ fct_nD_penetration_contact_maxi = a.fct_nD_penetration_contact_maxi;
+ fct_nD_penetration_borne_regularisation = a.fct_nD_penetration_borne_regularisation;
+ fct_nD_force_contact_noeud_maxi = a.fct_nD_force_contact_noeud_maxi;
+ fct_nD_penalisationTangentielle = a.fct_nD_penalisationTangentielle;
+ fct_nD_tangentielle_contact_maxi = a.fct_nD_tangentielle_contact_maxi;
+ fct_nD_tangentielle_borne_regularisation = a.fct_nD_tangentielle_borne_regularisation;
+ fct_nD_force_tangentielle_noeud_maxi = a.fct_nD_force_tangentielle_noeud_maxi;
+ return *this;
+
+ };
+///------- fin particularité class Fct_nD_contact ------------------
+
+
+ // CONSTRUCTEURS :
+// par defaut
+ElContact::ElContact () :
+ tabNoeud(),Mtdt(ParaGlob::Dimension()),Mt(0) // Mt de dim 0, au début pour dire qu'il n'est pas activé
+ ,M_noeud_tdt_avant_projection(ParaGlob::Dimension())
+ ,phi_theta_0()
+ ,force_contact(),force_contact_t(),tabForce_cont(),tabForce_cont_t()
+ ,F_N_max(0.),F_T_max(0.),F_N_max_t(0.),F_T_max_t(0.)
+ ,ddlElement_assemblage(NULL),raideur(NULL),residu(NULL)
+ ,energie_penalisation(0.),energie_frottement(),elfront(NULL),noeud(NULL)
+ ,num_zone_contact(0)
+ ,nb_decol_t(0),nb_decol_tdt(0),gap_t(0.),gap_tdt(0.),nb_pene_t(0.),nb_pene_tdt(0.)
+ ,dep_T_t(0.),dep_T_tdt(0.)
+ ,mult_pene_t(1.),mult_pene_tdt(1.)
+ ,mult_tang_t(1.),mult_tang_tdt(1.)
+ ,actif(1),type_trajectoire_t(0),type_trajectoire_tdt(0)
+ ,cas_solide(0),cas_collant(0)
+ ,tabNoeud_pour_assemblage(),tab_posi_esclave()
+ ,nb_posi_esclave_stocker_t(0),nb_posi_esclave_stocker_tdt(0)
+ ,indice_stockage_glissant_t(1),indice_stockage_glissant_tdt(1)
+ ,penalisation(0.),penalisation_tangentielle(0.)
+ ,penalisation_t(0.),penalisation_tangentielle_t(0.)
+ // utilisation éventuelle de fonction nD
+ ,fct_nD_contact()
+
+ ,N(),dep_tangentiel()
+ // pour le contact 4, pour le calcul de la pénalisation avec une moyenne glissante
+ ,val_penal(10),pt_dans_val_penal(1)
+ {};
+ // fonction d'un pointeur d'element frontiere et d'un pointeur de noeud
+ // du fait éventuel qu'il peut-être collant ou pas
+ElContact::ElContact ( const Front * elf, const Noeud * noe, Fct_nD_contact & fct_contact_,int collant):
+ tabNoeud(),Mtdt(ParaGlob::Dimension()),Mt(0) // Mt de dim 0, au début pour dire qu'il n'est pas activé
+ ,M_noeud_tdt_avant_projection(ParaGlob::Dimension())
+ ,phi_theta_0()
+ ,force_contact(ParaGlob::Dimension()),tabForce_cont()
+ ,force_contact_t(ParaGlob::Dimension()),tabForce_cont_t()
+ ,F_N_max(0.),F_T_max(0.),F_N_max_t(0.),F_T_max_t(0.)
+ ,ddlElement_assemblage(NULL),raideur(NULL),residu(NULL)
+ ,energie_penalisation(0.),energie_frottement(),elfront(NULL),noeud(NULL)
+ ,num_zone_contact(0)
+ ,nb_decol_t(0),nb_decol_tdt(0),gap_t(0.),gap_tdt(0.),nb_pene_t(0.),nb_pene_tdt(0.)
+ ,dep_T_t(0.),dep_T_tdt(0.)
+ ,mult_pene_t(1.),mult_pene_tdt(1.),mult_tang_t(1.),mult_tang_tdt(1.)
+ ,actif(1),type_trajectoire_t(0),type_trajectoire_tdt(0)
+ ,cas_solide(0),cas_collant(collant)
+ ,tabNoeud_pour_assemblage(),tab_posi_esclave()
+ ,nb_posi_esclave_stocker_t(0),nb_posi_esclave_stocker_tdt(0)
+ ,indice_stockage_glissant_t(1),indice_stockage_glissant_tdt(1)
+ ,penalisation(0.),penalisation_tangentielle(0.)
+ ,penalisation_t(0.),penalisation_tangentielle_t(0.)
+ // utilisation éventuelle de fonction nD
+ ,fct_nD_contact(fct_contact_)
+
+ ,N(),dep_tangentiel()
+ // pour le contact 4, pour le calcul de la pénalisation avec une moyenne glissante
+ ,val_penal(10),pt_dans_val_penal(1)
+ { noeud = ( Noeud *) noe; // le noeud esclave
+ elfront = new Front(*elf);
+ // on cree un nouvelle element generique frontiere identique
+ // pour stocker les info specifique aux intersections et tangence
+ // par contre les info generique (noeuds etc) sont identiques
+ Construction_TabNoeud(); // on construit le tableau de noeud global
+ tabForce_cont.Change_taille(tabNoeud.Taille()-1);
+ tabForce_cont_t.Change_taille(tabNoeud.Taille()-1);
+
+ };
+// de copie
+ElContact::ElContact ( const ElContact & a):
+ tabNoeud(),Mtdt(a.Mtdt),Mt(a.Mt),M_noeud_tdt_avant_projection(a.M_noeud_tdt_avant_projection)
+ ,phi_theta_0(a.phi_theta_0)
+ ,force_contact(a.force_contact),tabForce_cont(a.tabForce_cont)
+ ,force_contact_t(a.force_contact_t),tabForce_cont_t(a.tabForce_cont_t)
+ ,F_N_max(a.F_N_max),F_T_max(a.F_T_max)
+ ,F_N_max_t(a.F_N_max_t),F_T_max_t(a.F_T_max_t)
+ ,ddlElement_assemblage(a.ddlElement_assemblage)
+ ,raideur(a.raideur),residu(a.residu)
+ ,energie_penalisation(a.energie_penalisation)
+ ,energie_frottement(a.energie_frottement),elfront(NULL),noeud(NULL)
+ ,num_zone_contact(a.num_zone_contact)
+ ,nb_decol_t(a.nb_decol_t),nb_decol_tdt(a.nb_decol_tdt)
+ ,gap_t(a.gap_t),gap_tdt(a.gap_tdt),nb_pene_t(a.nb_pene_t),nb_pene_tdt(a.nb_pene_tdt)
+ ,dep_T_t(a.dep_T_t),dep_T_tdt(a.dep_T_tdt)
+ ,mult_pene_t(a.mult_pene_t),mult_pene_tdt(a.mult_pene_tdt)
+ ,mult_tang_t(a.mult_tang_t),mult_tang_tdt(a.mult_tang_tdt)
+ ,actif(a.actif),type_trajectoire_t(a.type_trajectoire_t)
+ ,type_trajectoire_tdt(a.type_trajectoire_tdt)
+ ,cas_solide(a.cas_solide),cas_collant(a.cas_collant)
+ ,tabNoeud_pour_assemblage(a.tabNoeud_pour_assemblage),tab_posi_esclave(a.tab_posi_esclave)
+ ,nb_posi_esclave_stocker_t(a.nb_posi_esclave_stocker_t),nb_posi_esclave_stocker_tdt(a.nb_posi_esclave_stocker_tdt)
+ ,indice_stockage_glissant_t(a.indice_stockage_glissant_t),indice_stockage_glissant_tdt(a.indice_stockage_glissant_t)
+ ,penalisation(a.penalisation),penalisation_tangentielle(a.penalisation_tangentielle)
+ ,penalisation_t(a.penalisation_t),penalisation_tangentielle_t(a.penalisation_tangentielle_t)
+ // utilisation éventuelle de fonction nD
+ ,fct_nD_contact(a.fct_nD_contact)
+
+ ,N(a.N),dep_tangentiel(a.dep_tangentiel)
+ // pour le contact 4, pour le calcul de la pénalisation avec une moyenne glissante
+ ,val_penal(a.val_penal),pt_dans_val_penal(a.pt_dans_val_penal)
+ { noeud = a.noeud;
+ elfront = new Front(*(a.Elfront()));
+ // on cree un nouvelle element generique frontiere identique
+ // pour stocker les info specifique aux intersections et tangence
+ // par contre les info generique (noeuds etc) sont identiques
+ Construction_TabNoeud(); // on construit le tableau de noeud global
+ };
+ // DESTRUCTEUR :
+ElContact::~ElContact ()
+ { Libere();
+ };
+
+ // METHODES PUBLIQUES :
+
+// affichage à l'écran des informations liées au contact
+void ElContact::Affiche() const
+ { cout << "\n element de contact ";
+ if (!actif) cout << " Inactif ! ";
+ cout << " constitue du noeud " << noeud->Num_noeud() << " du maillage "
+ << noeud->Num_Mail() << ", et de l'element de frontiere suivant: ";
+ elfront->Affiche();
+ cout << "\n F_contact_noeud: "<< force_contact;
+ cout << "\n F_contact_facette: "<< tabForce_cont;
+ cout << "\n norme_F_N: " << F_N_max
+ << ", norme_F_T: " << F_T_max;
+ cout << "\n normale: "<< N
+ << " dep_tangentiel: " << dep_tangentiel;
+ cout << "\n num_zone_contact " << num_zone_contact
+ << ", Mtdt: "<< Mtdt
+ << ", M_noeud_tdt_avant_projection " << M_noeud_tdt_avant_projection
+ << ", energie_frottement= "<< energie_frottement
+ << ", energie_penalisation= "<< energie_penalisation
+ << ", cas_solide= " << cas_solide
+ << ", cas_collant= " << cas_collant
+ << ", nb_decol_tdt= " << nb_decol_tdt
+ << ", gap_tdt= " << gap_tdt
+ << ", dep_T_tdt= " << dep_T_tdt
+ << ", nb_pene_tdt= " << nb_pene_tdt
+ << ", mult_pene_tdt= " << mult_pene_tdt
+ << ", mult_tang_tdt= " << mult_tang_tdt
+ << ", penalisation= " << penalisation
+ << ", penalisation_tangentielle= " << penalisation_tangentielle
+ << ", type_trajectoire_tdt= " << type_trajectoire_tdt ;
+ if (niveau_commentaire > 2)
+ {cout << "\n fct_nD_penalisationPenetration: ";
+ if (fct_nD_contact.fct_nD_penalisationPenetration != NULL )
+ {cout << fct_nD_contact.fct_nD_penalisationPenetration->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_penetration_contact_maxi: ";
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL )
+ {cout << fct_nD_contact.fct_nD_penetration_contact_maxi->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_penetration_borne_regularisation: ";
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL )
+ {cout << fct_nD_contact.fct_nD_penetration_borne_regularisation->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_force_contact_noeud_maxi: ";
+ if (fct_nD_contact.fct_nD_force_contact_noeud_maxi != NULL )
+ {cout << fct_nD_contact.fct_nD_force_contact_noeud_maxi->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_penalisationTangentielle: ";
+ if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL )
+ {cout << fct_nD_contact.fct_nD_penalisationTangentielle->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_tangentielle_contact_maxi: ";
+ if (fct_nD_contact.fct_nD_tangentielle_contact_maxi != NULL )
+ {cout << fct_nD_contact.fct_nD_tangentielle_contact_maxi->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_tangentielle_borne_regularisation: ";
+ if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL )
+ {cout << fct_nD_contact.fct_nD_tangentielle_borne_regularisation->NomFonction();}
+ else { cout << " NULL "; };
+ cout << "\n fct_nD_force_tangentielle_noeud_maxi: ";
+ if (fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi != NULL )
+ {cout << fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi->NomFonction();}
+ else { cout << " NULL "; };
+ };
+
+ };
+
+// 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 dans les faits:
+// 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 ElContact::Contact( bool init)
+ { int test = false; // pas de contact par défaut
+ // on dimensionne éventuellement le tableau des positions successives
+ if (tab_posi_esclave.Taille() != ParaGlob::param->ParaAlgoControleActifs().Nb_moy_glissant())
+ tab_posi_esclave.Change_taille
+ (ParaGlob::param->ParaAlgoControleActifs().Nb_moy_glissant(),Coordonnee(ParaGlob::Dimension()));
+
+/* // on exclue les cas non traité actuellement
+// if ((ParaGlob::Dimension() == 3) && (elfront->Eleme()->ElementGeometrique().Dimension()==1))
+// {// le cas du contact avec des lignes en 3D n'est pas encore implanté, sauf si le ddl 3 est bloqué pour tous les noeuds
+// int tail = tabNoeud.Taille();
+// bool ok_apriori = true;
+// for (int i=1;i<=tail;i++)
+// if (!(tabNoeud(i)->Ddl_fixe(X3)))
+// {ok_apriori=false;break;};
+//
+// if ((ParaGlob::NiveauImpression() >= 6) && (!ok_apriori))
+// { cout << "\n *** warning : le contact avec des lignes n'est pas encore implante en 3D ";
+// return test;
+// };
+// };
+
+// // le cas de la trajectoire pose des pb donc on va tout d'abor regarder si le noeud est interne à l'élément
+// // si oui, on le déclare actif et dans ce cas la trajectoire sera la normale
+// {// récup de l'élément qui contient la frontière
+// Element& elem = *(elfront->PtEI());
+// if (actif ==0) // si actif est différent de 0, alors cela signifie qu'il y a déjà contact, on ne va pas plus loin
+// if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+// {actif=1;
+//////debug
+//if (noeud->Num_noeud() == 84)
+// {cout << "\n debug ElContact::Contact( bool init) temps " << ParaGlob::Variables_de_temps().TempsCourant();
+// noeud->Coord2().Affiche();
+//// cout << " actif = " << actif;
+//// elem.RecupBoite_encombre_element().Premier().Affiche();
+//// elem.RecupBoite_encombre_element().Second().Affiche();
+// };
+
+//fin debug
+//
+//
+// }; // cela va modifier la manière de calculer la trajectoire
+// }; */
+
+ // on exclue un cas particulier qui ne peut pas être pris en compte a priori
+ // c'est le cas 1D du contact de la frontière 1D d'un segment avec un point
+ // le déplacement est forcément colinéaire avec la frontière
+ // donc les vrais frontières pertinentes
+ // sont les points d'extrémité mais pas le segment, mais c'est cependant la ligne que
+ // l'on utilisera pour avoir la notion de in et out donc
+ if ((ParaGlob::Dimension() == 1) // on est dans un espace 1D
+ && (elfront->Eleme()->ElementGeometrique().Dimension()==1) // la frontière est une ligne ou un point
+ && (elfront->Eleme_const()->TabNoeud_const().Taille() > 1 ) // + d'un seul noeud: c'est une ligne
+ )
+ {// le cas du contact avec des lignes en 1D n'est pas recevable a priori, ou plutôt il y a toujours intersection
+ return false;
+ };
+
+ // calcul de la trajectoire a utiliser
+ Coordonnee V = Trajectoire(test);
+
+// -- le fait que l'on n'est pas en contact a priori est neutralisé, car on peut s'en accomoder (on essaie)
+// s'il n'y a rien qui bouge: cas du tout début, ce sera la normale au point de référence qui sera la trajectoire
+// dans le cas ou rien ne bouge -> pas de contact a priori a l'initialisation
+ // les solides doivent etre hors contacts, et ensuite le contact est a chaque fois regarde
+// if (!test) return false;
+
+ // cas ou quelque chose a bouge
+
+// -- fin de la neutralisation
+
+
+ // calcul de l'intersection de la trajectoire avec la frontiere
+ int dim = noeud->Dimension();
+ Coordonnee M1(dim);
+ if (init)
+ {M1 = Intersection(V,true);
+ }
+ else
+ {M1 = Intersection(V,false);};
+ // dans le cas ou M1 a une dimension nulle, signifie qu'il n'y a pas d'intersection,
+ // on peut alors dire qu'il ne peut pas y avoir contact donc retour
+ if (M1.Dimension() == 0)
+ return false;
+ // pour la suite on suppose que l'on a trouvé une intersection
+ // maintenant on regarde si l'intersection est acceptable
+ // -- tout d'abord on arrete si l'intersection est vraiment trop loin du noeud
+ // donc 1) on teste le point projeter / à l'encombrement de l'élément frontière
+ // si le contact est collant, le point est concervé même en dehors de la boite
+ // c'est par exemple le cas point-facette, où le point est en dehors de la zone d'épaisseur
+ if (!cas_collant)
+ if (!(elfront->In_boite_emcombrement_front(M1)))
+ return false;
+ // 2) on regarde si la distance entre le point projeté et le noeud à tdt n'est pas
+ // anormalement grande: le test est également vrai pour le cas collant, pour
+ // éviter des contacts anormaux
+ double d_MM1 = (M1-noeud->Coord2()).Norme();
+
+// if (d_MM1 > MaX(dep_max,ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete()))
+//---- modif du 8 janvier: je ne comprend pas pourquoi j'ai pris en compte dep_max ici ??? donc je change
+// avec dep_max grand, cela supprime le paramétre de contrôle donc ... on ne contrôle plus rien ??
+ if (d_MM1 > ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete())
+ return false;
+ // sinon c'est que le pt M1 est encore acceptable, on poursuit les tests
+// cout << "\n debug ElContact::Contact distance = " << d_MM1 << endl;
+
+ // - cote surface
+ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ // ici on recherche avec une précision donnée
+ double extra_in_surface = ParaGlob::param->ParaAlgoControleActifs().PointInternePrecThetaiInterne();
+ // dans le cas d'un contact avec pénalisation de type 7,
+ // on considère le contact également pour un gap positif
+ int type_penal = ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ if ((contactType == 2)|| (contactType == 41) || (contactType == 42))
+ if ( abs(type_penal) == 7)
+ {// recup des dernières différentes informations calculées au niveau de la cinématique de contact
+ Coordonnee M_impact,N; // le point d'impact, la normale
+ Vecteur phii;
+ RecupInfo(N,M_impact,phii,false);
+
+ // calcul de la pénétration normale: deltaX=de la surface au point pénétré
+ Coordonnee deltaX = noeud->Coord2() - M_impact;
+ // le N sort de la surface maître, donc rentre dans la surface esclave
+ double gap= N * deltaX; // gap est négatif quand il y a pénétration
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ // on calcul un facteur en fonction de la distance: = 0.25*exp(-gap/(0.25*borne))
+ if (gap > borne_regularisation)
+ // on considère qu'il n'y a pas contact dans ce cas
+ {return false;}
+ else if (elfro.InSurf(extra_in_surface))
+ // on regarde si le point projeté est dans la surface de la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ };
+ // sinon on continue sur le cas normale
+ };
+
+ // on traite le cas particulier du contact collant
+ if (cas_collant)
+ { if (elfro.InSurf(extra_in_surface))
+ // on ne s'occupe pas du coté de la projection pour le cas collant
+ // on déclare le noeud pas en contact si la distance entre le noeud et la frontière est
+ // trop grande
+ { double dmax = ParaGlob::param->ParaAlgoControleActifs().DistanceMaxiAuPtProjete();
+ double r=0;
+ // on utilise BonCote_tdt uniquement pour calculer r
+ elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (Dabs(r) > dmax)
+ // pas de contact
+ { return false;}
+ else
+ {Mtdt = M1; // sauvegarde
+ return true;
+ };
+ };
+ };
+
+ // cas non collant: on regarde si le point projeté est dans la surface de la frontière
+ double dismini = ParaGlob::param->ParaAlgoControleActifs().Precision_pt_sur_front();
+ if (elfro.InSurf(extra_in_surface))
+ { // on commence par traiter les cas classiques, en particulier on verra après le cas en 3D avec un point et une ligne
+ if ( !((ParaGlob::Dimension() == 3) && (elfront->Eleme()->ElementGeometrique().Dimension()==1)))
+ // ok surface, -> cote droite ?
+ {if (test == 1) // cas du noeud qui bouge
+ { double r=0;
+ // le point a t est-il du bon cote (= hors matière) de la surface a t
+ if (elfront->BonCote_t(noeud->Coord1(),r))
+ // oui, deux cas selon que le point initial est dans l'element final ou pas
+ { if (elfront->BonCote_tdt(noeud->Coord1(),r))
+ // oui point initiale hors matière -> il faut maintenant regarder le point final
+ { bool bon_cote = elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (bon_cote && (r > dismini))
+ // oui -> signifie que le noeud est sortie de l'element-> pas de contact
+ { return false;}
+ else // sinon on a le point initial hors matière finale et le point final dans la matière finale
+ { // donc contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ };
+ }
+ else // non le point initial est dans la matiere final
+ { Coordonnee B = (noeud->Coord2() + noeud->Coord1()) / 2.; // point milieu entre t et tdt
+ double rl = (M1 - B).Norme();
+ if (rl <= V.Norme()/2.)
+ // le point est acceptable, on change les coordonnees a tdt du noeud
+ { // contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else
+// return false; // il n'y a pas contact
+// *** non la suite ne marche pas , je le laisse pour mémoire
+// si on essaie
+ { // c'est un cas qui peut arriver en particulier dans le cas de la pénalisation
+ // on regarde si la position finale est dans l'élément fini associé à la frontière
+ Element & elem = *(elfront->PtEI()); // l'element qui contiend la frontiere
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+ // on teste alors plus précisemment, si la position finale est dans l'élément
+ // il y a contact
+ { if (elem.Interne_tdt(noeud->Coord2()) > 0) // point interne ou sur la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // sinon il n'y a définitivement pas de contact
+ { return false;};
+ }
+ else // si on n'est pas dans la boite d'encombrement --> pas de contact
+ {return false;};
+ };
+
+ };
+ }
+ else // non point initial a t est du mauvais cote, donc dans la matière à t
+
+// *** non la suite ne marche pas , je le laisse pour mémoire
+// si on essaie
+ { // c'est un cas qui peut arriver en particulier dans le cas de la pénalisation
+ // on regarde si la position finale est dans l'élément fini associé à la frontière
+ Element & elem = *(elfront->PtEI()); // l'element qui contiend la frontiere
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+ // on teste alors plus précisemment, si la position finale est dans l'élément
+ // il y a contact
+ { if (elem.Interne_tdt(noeud->Coord2()) > 0) // point interne ou sur la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // sinon il n'y a définitivement pas de contact
+ {return false;};
+ }
+ else // si on n'est pas dans la boite d'encombrement --> pas de contact
+ {return false;};
+ };
+
+ // en fait si on arrive ici, et qu'il y a vraiment contact, cela signifie qu'il y a une erreur
+ // car le point à t ne devrait pas être dans la matière à t, car cela veut dire qu'il y avait déjà
+ // contact à t, ce contact n'a pas été détecté !!
+
+/// {return false;};
+ }// -- fin du test == 1
+ else if (test == 0) // cas rien ne bouge ni noeud ni frontière
+ { double r=0;
+ // le point final = initial, est-il dans la matiere finale
+ if (!elfront->BonCote_tdt(noeud->Coord2(),r))
+ // oui -> contact
+ { // contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // non -> pas de contact,
+ return false;
+ }
+ else
+ // cas du noeud fixe, et de la frontiere qui bouge
+ { double r=0;
+ // le point a t est-il du bon cote de la surface a t
+ if (elfront->BonCote_t(noeud->Coord1(),r))
+ // le point final = initial, est-il dans la matiere finale
+ { bool bon_cote = elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (!bon_cote || (r <= dismini))
+ // oui -> contact
+ { // contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // non -> pas de contact,
+ return false;
+ }
+ else // non
+ return false; // on etait a l'arriere d'une facette
+ }
+ }
+ else if ( (ParaGlob::Dimension() == 3) && (ParaGlob::AxiSymetrie()) && (elfront->Eleme()->ElementGeometrique().Dimension()==1))
+ // cas en dimension 3, axisymétrique
+ // on examine le contact en fonction de la trajectoire
+ {if (test == 1) // cas du noeud qui bouge
+ { double r = 0.;
+ // le point a t est-il du bon cote (= hors matière) de la ligne a t
+ if (elfront->BonCote_t(noeud->Coord1(),r))
+ // oui, deux cas selon que le point initial est dans l'element final ou pas
+ { if (elfront->BonCote_tdt(noeud->Coord1(),r))
+ // oui point initiale hors matière -> il faut maintenant regarder le point final
+ { bool bon_cote = elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (bon_cote && (r > dismini))
+ // oui -> signifie que le noeud est sortie de l'element-> pas de contact
+ { return false;}
+ else // sinon on a le point initial hors matière finale et le point final dans la matière finale
+ { // donc contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ };
+ }
+ else // non le point initial est dans la matiere final
+ { // on regarde si le point final est aussi dans la matière
+ bool bon_cote = elfront->BonCote_tdt(noeud->Coord1(),r);
+ if (bon_cote && (r > dismini))
+ // oui -> signifie que le noeud est sortie de l'element-> pas de contact
+ { return false;}
+ else // sinon on a le point initial et le point final sont dans la matière finale
+ { // donc contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ };
+
+ // --- la suite je ne sais pas pourquoi il faut la garder ??
+
+
+
+
+
+ Coordonnee B = (noeud->Coord2() + noeud->Coord1()) / 2.; // point milieu entre t et tdt
+ double rl = (M1 - B).Norme();
+ if (rl <= V.Norme()/2.)
+ // le point est acceptable, on change les coordonnees a tdt du noeud
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else
+// return false; // il n'y a pas contact
+// *** non la suite ne marche pas , je le laisse pour mémoire
+// si on essaie
+ { // c'est un cas qui peut arriver en particulier dans le cas de la pénalisation
+
+
+
+ // on regarde si la position finale est dans l'élément fini associé à la frontière
+ Element & elem = *(elfront->PtEI()); // l'element qui contiend la frontiere
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+ // on teste alors plus précisemment, si la position finale est dans l'élément
+ // il y a contact
+ { if (elem.Interne_tdt(noeud->Coord2()) > 0) // point interne ou sur la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // sinon il n'y a définitivement pas de contact
+ { return false;};
+ }
+ else // si on n'est pas dans la boite d'encombrement --> pas de contact
+ {return false;};
+ };
+
+ };
+ }
+ else // non point initial a t est du mauvais cote, donc dans la matière à t
+
+// *** non la suite ne marche pas , je le laisse pour mémoire
+// si on essaie
+ { // c'est un cas qui peut arriver en particulier dans le cas de la pénalisation
+ // on regarde si la position finale est dans l'élément fini associé à la frontière
+ Element & elem = *(elfront->PtEI()); // l'element qui contiend la frontiere
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+ // on teste alors plus précisemment, si la position finale est dans l'élément
+ // il y a contact
+ { if (elem.Interne_tdt(noeud->Coord2()) > 0) // point interne ou sur la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // sinon il n'y a définitivement pas de contact
+ {return false;};
+ }
+ else // si on n'est pas dans la boite d'encombrement --> pas de contact
+ {return false;};
+ };
+
+ // en fait si on arrive ici, et qu'il y a vraiment contact, cela signifie qu'il y a une erreur
+ // car le point à t ne devrait pas être dans la matière à t, car cela veut dire qu'il y avait déjà
+ // contact à t, ce contact n'a pas été détecté !!
+
+/// {return false;};
+ }// -- fin du test == 1
+ else if (test == 0) // cas rien ne bouge ni noeud ni frontière
+ { // le point final = initial, est-il dans la matiere finale
+ double r=0.;
+ bool bon_cote = elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (!bon_cote || (r <= dismini))
+ // oui -> contact
+ { // contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // non -> pas de contact,
+ return false;
+ }
+ else
+ // cas du noeud fixe, et de la frontiere qui bouge
+ { // le point a t est-il du bon cote de la surface a t
+ double r=0.;
+ bool bon_cote = elfront->BonCote_t(noeud->Coord1(),r);
+ if (!bon_cote || (r <= dismini))
+ // le point final = initial, est-il dans la matiere finale
+ { bool bon_cote2 = elfront->BonCote_tdt(noeud->Coord2(),r);
+ if (!bon_cote2 || (r <= dismini))
+ // oui -> contact
+ { // contact sans original
+ Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // non -> pas de contact,
+ return false;
+ }
+ else // non
+ return false; // on etait a l'arriere d'une facette
+ }
+ }
+ //---------------------
+ else // cas en 3D avec un point et une ligne
+ { // on regarde si la position finale est dans l'élément fini associé à la frontière
+ Element & elem = *(elfront->PtEI()); // l'element qui contiend la frontiere
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ // ou de tous les éléments qui contiennent également les noeuds de la frontière
+ // car on peut passer à travers l'élément de la frontière et être dans un autre élément
+ // et c'est valide
+ if (elem.In_boite_emcombrement_elem(noeud->Coord2()))
+ // on teste alors plus précisemment, si la position finale est dans l'élément
+ // il y a contact
+ { if (elem.Interne_tdt(noeud->Coord2()) > 0) // point interne ou sur la frontière
+ { Mtdt = M1; // sauvegarde
+ return true;
+ }
+ else // sinon il n'y a définitivement pas de contact
+ {return false;};
+ }
+ else // si on n'est pas dans la boite d'encombrement --> pas de contact
+ {return false;};
+ };
+ }
+//=========
+ else // le point n'est pas sur la frontiere
+ {return false; };
+ };
+
+// 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 ElContact::Trajectoire(int & test)
+ { // ---> constitution de la droite de projection, et initialisation de V
+ Coordonnee V = noeud->Coord2() - noeud->Coord1(); // trajectoire du noeud de t a tdt
+ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ // ------- cas où le contact était déjà effectif à t et que l'on impose la projection sur la surface -------
+// if ((actif > 1) && (ParaGlob::param->ParaAlgoControleActifs().ContactType() == 1))
+ if ((actif > 1) // en fait c'est vrai quelque soit le type de contact
+ || cas_collant // dans le cas collant on projette systématiquement de manière normale
+ // sinon on peut avoir des différences importante entre l'intersection
+ // et le point collé qui ne sont pas bien prise en compte,
+ // même si le noeud est sur la facette
+ )
+ { // dans ce cas la trajectoire considérée est la normale, cela veut dire que
+ // systématiquement, ce que l'on fait
+ // c'est de calculer selon la normale, le point sur la surface
+ // recherche de la normale ,traitement suivant les different cas
+ // dimensionnement des variables de tangence (plan ou droite)
+ int dim = noeud->Dimension(); // dimension des points
+ if (elfro.TypeFrontiere() == "FrontPointF")
+ {// cas où la frontière est un point on utilise l'élément linéaire
+ // dont c'est la frontière, pour calculer la direction de la normale
+ // qui correspond à la tangent à l'élément
+ Element * elemf = elfront->PtEI(); // récup de l'élément fini
+ ElemGeomC0& elem_geom = elemf->ElementGeometrique(); // recup de l'élément géométrique correspondant
+ // on peut répondre directement s'il s'agit d'un élément de type segment
+ if (elem_geom.TypeGeometrie() == SEGMENT)
+ { // on doit avoir un élément de mécanique
+ ElemMeca & elMeca = (ElemMeca &) (*elemf);
+ // il n'y a qu'un seul noeud d'ou le pointeur du noeud frontière
+ Noeud * noe = elfro.TabNoeud()(1);
+ // récupération de la base locales au noeud noe, pour le temps: temps
+ const BaseB & baseB = elMeca.Gib_elemeca(TEMPS_tdt,noe);
+ // le premier vecteur est le vecteur tangent que l'on considère normal à la frontière
+ V = baseB(1).Coor();
+ // on renseigne le point frontière du vecteur tangent qui lui est attribué, ceci pour l'utilisation
+ // de la fonction: duboncote
+ }
+ else
+ { cout << "\n cas actuellement non implante: element point, frontiere d'une geometrie autre que segment"
+ << "\n ElContact::Trajectoire(int & test)";
+ Sortie(1);
+ }
+ }
+ else
+ { // dans le cas où il s'agit d'une frontière ligne ou surface
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ // constitution d'un plan tangent ou de la droite tangente au point de reference
+ elfro.TangentRef(dr,pl,indic);
+ V = Calcul_Normale(dim,pl,dr, indic);
+ }
+ test = type_trajectoire_tdt = 5; return V;
+ };
+
+ // ------- cas où soit le contact n'était pas effectif auparavant,
+ // soit il n'y a pas de projection sur la facette -------
+ // on cherche dans quel cas de contact on se trouve
+ // 3 cas : le noeud bouge ou seul la frontiere bouge ou tout est immobile
+ double L = V.Norme(); // la distance de t a tdt
+ if (L <= ConstMath::trespetit)
+ // cas ou le vecteur est nul c-est a dire, cas ou le noeud n'a pas bouge, on regarde si
+ // l'element maitre a bougé
+ { const Tableau & tabnoeud = elfro.TabNoeud();
+ int tail = tabnoeud.Taille();
+ Coordonnee V11(V); // variation totale
+ // en fait on peut regarder le mvt du centre de gravité qui à NBE près est
+ // le V11 qui suit
+ for (int it=1;it<= tail;it++)
+ V11 += tabnoeud(it)->Coord2() - tabnoeud(it)->Coord1();
+ double L11 = V11.Norme();
+ if (L11 <= ConstMath::trespetit)
+ { // le centre de gravité ne bouge pas, donc soit la frontière est immobile,
+ // soit il y a rotation autour de G,
+ // dans ce cas on essaie le maxi du déplacement de chaque noeud
+ Coordonnee V12(V);double L12=0.; V11=V; L11= V11.Norme();// init
+ for (int itt=2;itt<=tail;itt++)
+ { V12=tabnoeud(itt)->Coord2() - tabnoeud(itt)->Coord1(); L12=V12.Norme();
+ if (L12 > L11) {V11=V12;L11=L12; };
+ };
+ // on reteste la nouvelle longueur L11 finale
+ if (L11 > ConstMath::trespetit)
+ // cas où il y a rotation autour de G, et V11 est le maxi des déplacements
+ { test = type_trajectoire_tdt = 4; return V11;};
+ // sinon on sort des deux if (on sera à: // -<<>>-- ) et on en conclue que vraiment rien ne bouge !
+ }
+ else
+ // cas où le centre de gravité bouge et V11 est le déplacement de G
+ { test = type_trajectoire_tdt = 2; return V11;};
+
+ // -<<>>-- là vraiment il n'y a rien qui bouge sur la frontière
+ // --on prendra comme direction la normale a l'element
+ // recherche de la normale ,traitement suivant les different cas
+ { // dimensionnement des variables de tangence (plan ou droite)
+ int dim = noeud->Dimension(); // dimension des points
+ if (elfro.TypeFrontiere() == "FrontPointF")
+ {// cas où la frontière est un point on utilise l'élément linéaire dont c'est la frontière
+ // pour calculer la direction de la normale qui correspond à la tangent à l'élément
+ Element * elemf = elfront->PtEI(); // récup de l'élément fini
+ ElemGeomC0& elem_geom = elemf->ElementGeometrique(); // recup de l'élément géométrique correspondant
+ // on peut répondre directement s'il s'agit d'un élément de type segment
+ if (elem_geom.TypeGeometrie() == SEGMENT)
+ { // on doit avoir un élément de mécanique
+ ElemMeca & elMeca = (ElemMeca &) (*elemf);
+ // il n'y a qu'un seul noeud d'ou le pointeur du noeud frontière
+ Noeud * noe = elfro.TabNoeud()(1);
+ // récupération de la base locales au noeud noe, pour le temps: temps
+ const BaseB & baseB = elMeca.Gib_elemeca(TEMPS_tdt,noe);
+ // le premier vecteur est le vecteur tangent que l'on considère normal à la frontière
+ V = baseB(1).Coor();
+ // on renseigne le point frontière du vecteur tangent qui lui est attribué, ceci pour l'utilisation
+ // de la fonction: duboncote
+ }
+ else
+ { cout << "\n cas actuellement non implante: element point, frontiere d'une geometrie autre que segment"
+ << "\n ElContact::Trajectoire(int & test)";
+ Sortie(1);
+ }
+ }
+ else
+ { // dans le cas où il s'agit d'une frontière ligne ou surface
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ // constitution d'un plan tangent ou de la droite tangente au point de reference
+ elfro.TangentRef(dr,pl,indic);
+ V = Calcul_Normale(dim,pl,dr, indic);
+ };
+ test = type_trajectoire_tdt = 0; return V;
+ };
+ }
+ else
+ // lorsque l'on arrive ici, c'est donc que le noeud bouge, et c'est son déplacement
+ // qui est retenue comme trajectoire
+ {test = type_trajectoire_tdt = 1; return V ; };
+ };
+
+
+// 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 ElContact::Intersection( const Coordonnee& V,bool init)
+ { ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ // dimensionnement des variables de tangence (plan ou droite)
+ int dim = noeud->Dimension(); // dimension des points
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ if (init)
+ // constitution d'un plan tangent ou de la droite tangente au point de reference
+ elfro.TangentRef(dr,pl,indic);
+ else
+ // on reactualise le dernier plan tangent
+ elfro.DernierTangent(dr,pl,indic);
+////---- debug
+//if (noeud->Num_noeud() == 2)
+// {cout << "\n debug : ElContact::Intersection(.. ";
+// // on vérifie la perpendicularité
+// double perpen = dr.VecDroite() * V;
+// cout << "\n diff normale : "<< perpen ;
+// cout <Coord1();
+ if (((actif > 1)
+ && ( (contactType == 1) || (contactType == 3) )
+ )
+ // dans le cas du type 4 on fait toujours une projection normale
+ || ((actif > 0) && (contactType == 4))
+ )
+ pointDeBase = noeud->Coord2();
+////---- debug
+//if (noeud->Num_noeud() == 2)
+// {cout << "\n debug : ElContact::Intersection(.. ";
+// cout << "\n pointDeBase : "<< pointDeBase ;
+// };
+////---- fin debug
+ Droite droite(pointDeBase,V); // la droite
+ // dans le cas très particulier où l'élément de frontière maître est un point:
+ if (indic == 0)
+ { // il n'y a qu'un seul noeud d'ou le pointeur du noeud frontière
+ Noeud * noe = elfro.TabNoeud()(1);
+ Coordonnee point_frontiere=noe->Coord2();
+ // on regarde si le point frontière est sur la trajectoire
+ if (droite.Appartient_a_la_droite(point_frontiere))
+ { // le point frontière est sur la trajectoire, l'intersection est donc au noeud frontière
+ // les fonctions d'interpolations du premier point en contact
+ if (init)
+ {phi_theta_0 = elfro.Phi();};
+ return point_frontiere;
+ }
+ else
+ { // il n'y a pas d'intersection, on ramène un point de dimension nulle
+ Coordonnee retour(0);
+ return retour;
+ }
+ };
+
+////---- debug
+//if (noeud->Num_noeud() == 2)
+// {cout << "\n debug : ElContact::Intersection(.. ";
+// // on vérifie la perpendicularité
+// double perpen = dr.VecDroite() * droite.VecDroite();
+// cout << " diff normale2 : "<< perpen ;
+// cout <ParaAlgoControleActifs().Nb_boucle_newton_position_sur_frontiere();
+ // distance maxi entre le point d'inter du plan et le point correspondant de la surface
+ double dismini = ParaGlob::param->ParaAlgoControleActifs().Precision_pt_sur_front();
+ //---------------------------------------
+ // recherche du point d'intersection M
+ //---------------------------------------
+ do
+ {
+ // calcul de l'intersection
+ if (indic == 1)
+ // cas d'une droite
+ { int ret = dr.Intersection(droite,M);
+ if (( ret == 0) || ( ret == -1)) // pas d'intersection, on essaie deux autres points
+ { for (int i=1;i<= 2; i++)
+ { elfro.AutreTangent(dr,pl,indic); // on suppose indic du meme type
+ ret = dr.Intersection(droite,M);
+ if (ret) { intp = 1; break;};
+ };
+ // dernier essai, on perturbe 2 fois la trajectoire
+ for (int i=1;i<=2; i++)
+ { Coordonnee newtra = droite.VecDroite() + 0.1 * droite.UneNormale();
+ droite.Change_vect(newtra);
+ for (int i=1;i<= 2; i++)
+ { elfro.AutreTangent(dr,pl,indic); // on suppose indic du meme type
+ ret = dr.Intersection(droite,M);
+ if (ret) { intp = 1; break;};
+ };
+ if (intp) break;
+ };
+ }
+ else
+ intp = 1; // on a trouve un point
+ }
+ else
+ // cas d'un plan
+ { int ret = pl.Intersection(droite,M);
+ if (( ret == 0) || ( ret == -1)) // pas d'intersection, on essaie trois autres points
+ { for (int i=1;i<= 3; i++)
+ { elfro.AutreTangent(dr,pl,indic); // on suppose indic du meme type
+ ret = pl.Intersection(droite,M);
+ if (ret) { intp = 1; break;};
+ };
+ // dernier essai, on perturbe 2 fois la trajectoire
+ for (int i=1;i<=2; i++)
+ { Coordonnee newtra = droite.VecDroite() + 0.1 * droite.UneNormale();
+ droite.Change_vect(newtra);
+ for (int i=1;i<= 2; i++)
+ { elfro.AutreTangent(dr,pl,indic); // on suppose indic du meme type
+ ret = dr.Intersection(droite,M);
+ if (ret) { intp = 1; break;};
+ };
+ if (intp) break;
+ };
+ }
+ else
+ intp = 1; // on a trouve un point
+ };
+ if (intp)
+ // calcul du point M1 de la surface correspondant a M
+ { elfro.Tangent(M,M1,dr,pl,indic);
+ nm = (M1 - M).Norme();
+ }
+ else
+ { // on n'arrive pas à calculer un point d'intersection
+ if (niveau_commentaire >= 7)
+ {cout << "\n remarque , pas d'intersection "
+ << " entre la trajectoire du noeud esclave "
+ << noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
+ << " avec frontiere:"
+ << elfront->Num_frontiere()
+ << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
+ << elfront->PtEI()->Num_maillage() << " \n ";
+ };
+ if (niveau_commentaire >= 9)
+ { noeud->Affiche();
+ elfro.Affiche();
+ cout << "ElContact::Intersection(bool init, bool forcee)"<< endl;
+ };
+ // on considère qu'il n'y a pas d'intersection (donc on n'en tient pas compte) et retour
+ // évite au programme de planter globalement alors qu'il n'y a peut-être qu'un pb local
+ Coordonnee retour(0);
+ return retour;
+ };
+ // test d'arret si l'on est en dehors de la boite d'encombrement
+ // sauf dans le cas d'un contact collant car pour le collant: l'intersection est toujours valide
+ // ensuite il y aura éventuellement un choix entre différents éléments de contact
+// cout << "\n"; M1.Affiche();elfront->Encom_mini_FR().Affiche();elfront->Encom_maxi_FR().Affiche();cout << endl;
+ if (!cas_collant)
+ if (!(elfront->In_boite_emcombrement_front(M1)))
+ break;
+ compteur++;
+ }
+ while ((compteur <= max_compteur) && (nm >= dismini)) ;
+ // retour du point d'intersection
+////////debug
+// if (noeud->Num_noeud()==84)
+// {
+// cout << "\n debug ElContact::Intersection : noeud: " << noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
+// << " avec frontiere:" << elfront->Num_frontiere()
+// << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
+// << elfront->PtEI()->Num_maillage();
+// cout <<"\n Noe_atdt= " << noeud->Coord2() << "\n point projete= " << M1 << endl;
+// };
+////// fin debug
+ // les fonctions d'interpolations du premier point en contact
+ if (init)
+ {phi_theta_0 = elfro.Phi();};
+ // retour du point d'intersection
+ return M1;
+ };
+
+// construction de la condition lineaire de contact
+// nb_assemb : indique le numéro d'assemblage correspondant
+Condilineaire ElContact::ConditionLi(int nb_assemb)
+ { ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ // recup de la dimension
+ int dim = noeud->Dimension();
+ // --- def des tableaux pour la condition lineaire
+ Tableau & tabnoeudf = elfro.TabNoeud(); // le tableau de noeuds de l'élément frontière
+
+ // on cherche le nombre de ddl attaché à l'ensemble des noeuds concerné par le contact
+ int nbnc = tabnoeudf.Taille(); int tail=0; // init
+ // puis on boucle sur les noeuds en cumulant les ddl actif pour le cas d'assemblage donné
+ // on considère que le cas d'assemblage est celui de ddl de déplacement uniquement
+ if (cas_solide == 1)
+ // on ajoute les ddl du noeud projectile, qui est ici le seul libre, le reste est solide
+ {tail += noeud->NB_ddl_actif_casAssemb (nb_assemb);}
+ else // pour les autres cas on considère pour l'instant tous les ddl
+ {for (int ine=1;ine<=nbnc;ine++) tail += tabnoeudf(ine)->NB_ddl_actif_casAssemb (nb_assemb);
+ //on rajoute les ddl du noeud projectile
+ tail += noeud->NB_ddl_actif_casAssemb (nb_assemb);
+ };
+ Tableau pt(tail); //définition du tableau de pointeurs des ddls concernées par la condition de contact
+ Vecteur val(tail); // coefs de la condition lineaire
+ Tableau t_enu(tail); // le tableau des énumérés correspondant aux ddl de la CLL
+ int nb_noeud_CLL= 1; // init par défaut
+ if (cas_solide != 1) nb_noeud_CLL += nbnc;
+ Tableau t_noeudCLL(nb_noeud_CLL); // le tableau de noeuds de la CLL
+ // --- fin def des tableaux pour la condition lineaire
+
+ // recup du dernier plan tangent (ou droite)
+ // dimensionnement des variables de tangence
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ elfro.DernierTangent(dr,pl,indic);
+ // calcul de la normale en fonction de differente conditions
+ Coordonnee N( Calcul_Normale(dim,pl,dr,indic)) ;
+
+
+ // remplissage des tableaux
+ // on commence par le noeud esclave
+/// int numX = noeud->Existe(X1) -1;
+/// int pointeur = noeud->PosiAssemb(nb_assemb) + numX;// pointeur d'assemblage
+ int numX = noeud->Position_ddl(X1,nb_assemb)-1;
+ #ifdef MISE_AU_POINT
+ if ( numX == -2 )
+ { cout << "\nErreur : ddl X1 inexistant pour le cas de charge " << nb_assemb << '\n'
+ << "ElContact::ConditionLi(int nb_assemb) 1\n";
+ Sortie(1);
+ };
+ #endif
+
+ int pointeur = noeud->Pointeur_assemblage(X1,nb_assemb) - 1;// pointeur d'assemblage - 1
+ #ifdef MISE_AU_POINT
+ if ( pointeur == -2 )
+ { cout << "\nErreur : ddl X1 inexistant pour le cas de charge " << nb_assemb << '\n'
+ << "ElContact::ConditionLi(int nb_assemb) 2\n";
+ Sortie(1);
+ };
+ #endif
+ int itab ; // indice des tableaux
+ // le premier indice correspondra a la direction bloquee, il faut s'assurer qu'il ne
+ // soit pas nul et qu'il ne correspond pas a une direction deja bloquee par les conditions
+ // limites de depart
+ // on boucle sur la dim pour trouver le coef le plus grand correspondant a une direction
+ // non bloquee
+ int iti;double max = 0;int indi = 0;
+ int posi = Id_nom_ddl("X1") -1; // position du ddl X1
+ for (iti=1; iti<= dim; iti++)
+ { if (!noeud->Ddl_fixe(Enum_ddl(posi+iti))) // cas d'un ddl libre
+ if (Dabs(N(iti)) > max)
+ { max = Dabs(N(iti));
+ indi = iti;
+ };
+ };
+ if (indi ==0)
+ { // cas ou soit les trois ddl sont bloque, soit le vecteur normal = 0
+ cout << "\n erreur dans les conditions lineaire de contact, "
+ << " soit les trois ddl de deplacement du noeud esclave sont tous bloque, "
+ << " soit le vecteur normal a la surface maitre = 0 \n";
+ noeud->Affiche();
+ cout << "\n et la normal : " ; N.Affiche();
+ cout << "ElContact::ConditionLi()" << endl;
+// cout << "\n fixite= " << noeud->Ddl_noeud_t(Enum_ddl(posi+1)).Fixe()
+// << " " << noeud->Ddl_noeud_t(Enum_ddl(posi+1)).Fixe() << endl;
+ Sortie (1);
+ };
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ // dans le cas d'un contact de type 1
+ if ( (contactType == 1)|| (contactType == 3) )
+ {// on indique que la nouvelle direction "indi" est bloque, ceci permet
+ // pour une autre condition de contact, de ne pas reprendre cette direction
+ // --> ce marquage est effacer apres resolution, par la fonction efface blocage
+ noeud->Change_fixe(Enum_ddl(posi+indi),true);
+ };
+ t_noeudCLL(1) = noeud;
+
+ // constitution de la condition lineaire
+ int indi_t = indi; // récup de l'indice du ddl du noeud esclave bloqué (de 1 à dim)
+ // dans une variable intermédiaire, car elle sera modifié par la boucle suivante
+ // et on en a besoin dans la constitution de la condition linéaire-> condi_retour
+ for (itab=1;itab<= dim;itab++)
+ { val(itab) = N(indi_t); // val(1) correspond à N(indi), puis les autres suivent
+ pt(itab) = pointeur + indi_t; // ici il s'agit du pointeur d'assemblage du noeud bloqué
+ t_enu(itab) = Enum_ddl(posi+indi_t);
+ indi_t ++;
+ if (indi_t > dim) indi_t = 1;
+ };
+ if (cas_solide != 1) // le cas == 1 correspond au cas d'un contact avec un solide
+ // dans ce cas, les noeuds maîtres ne font pas partie de la CLL
+ {// cas des noeuds de l'element maitre
+ Vecteur phi = elfro.Phi();
+ for (int nn=1; nn<=tabnoeudf.Taille(); nn++)
+ { Noeud & noe = *(tabnoeudf(nn));
+ t_noeudCLL(nn+1)=&noe;
+ // récup du pointeur d'assemblage des noeuds de l'élément maitre -1
+ pointeur = noe.Pointeur_assemblage(X1,nb_assemb) -1;
+ #ifdef MISE_AU_POINT
+ if ( pointeur == -2 )
+ { cout << "\nErreur : ddl X1 inexistant pour le cas de charge " << nb_assemb
+ << '\n'
+ << "ElContact::ConditionLi(int nb_assemb) 3\n";
+ Sortie(1);
+ };
+ #endif
+ for (int i=1;i<= dim;i++,itab++)
+ { val(itab) = - N(i) * phi(nn);
+ pt(itab) = pointeur + i ; // ici il s'agit du pointeur d'assemblage des noeuds maitres
+ t_enu(itab) = Enum_ddl(posi+i);
+ };
+ };
+ };
+ Condilineaire condi_retour(t_enu,pt,val,0.,numX+indi,t_noeudCLL);
+ return condi_retour;
+ };
+
+// 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 false, sinon retourne true
+// en fonction de la méthode de contact, le noeud est ramené éventuellement sur la frontière
+bool ElContact::Actualisation()
+{ // comme le point est déjà en contact, son déplacement est grosso modo // à la surface
+ // donc on ne peut pas utiliser sa trajectoire et faire une intersection avec la surface, cela ne veut rien dire
+ // donc on cherche la projection du point sur la surface. Pour cela on calcule l'intersection d'une trajectoire qui a
+ // comme direction, la normale à la surface
+ // dans le cas d'un point avec ligne c'est idem
+
+ // recup des dernières différentes informations calculées au niveau de la cinématique de contact
+ Coordonnee M_impact,N; // le point d'impact, la normale
+ Vecteur phii;
+ RecupInfo(N,M_impact,phii,false);
+
+ // def de la pseudo-trajectoire a utiliser: ici ce sera une trajectoire normale à la surface maître
+ Coordonnee V = N;
+// // debug
+//if (noeud->Num_noeud() == 2)
+// {cout << "\n debug : ElContact::Actualisation() "
+// << " noeud: " << noeud->Num_noeud() <<" mailage:"<Num_Mail()
+// << " normale= "; V.Affiche();
+// cout << "\n coordonnée à t ";noeud->Coord1().Affiche();
+// cout << "\n coordonnée à tdt ";noeud->Coord2().Affiche();
+// cout <Num_noeud() == 2)
+// {cout << "\n debug : ElContact::Actualisation() "
+// << " intersection "; M1.Affiche();
+// // défaut de projection
+// Coordonnee Mtdt = noeud->Coord2();
+// Coordonnee deltaX = M1-Mtdt;
+// double gap = N * deltaX;
+// double diff = (deltaX - gap*N).Norme(); // on calcule pour vérifier
+// double N_deltaX = deltaX.Norme();
+// cout << "\n diff de projection : "<< diff ;
+// if(N_deltaX > ConstMath::trespetit)
+// {Coordonnee deltaX_N = deltaX.Normer();
+// cout << " deltaX_N: " << deltaX_N ;
+// };
+// cout <Eleme()); // pour commodite
+ // ici on recherche avec une précision donnée
+ double extra_in_surface = ParaGlob::param->ParaAlgoControleActifs().PointInternePrecThetaiInterne();
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ if (elfro.InSurf(extra_in_surface))
+ // l'intersection est ok pour l'element
+ // cote droite : contrairement a Intersection() , on oblige ici éventuellement en fonction du modèle de contact
+ // le point a etre sur la surface, car a priori il y a toujours contact
+ { Mtdt = M1; // sauvegarde
+/* // si l'élément n'est pas actuellement actif on regarde si le contact est valide c-a-d si le noeud est dans la matière
+ // si oui on active l'élément, sinon on laisse tel quel et on ne change pas le noeud par exemple.
+
+// if (!actif)
+// {if (!(elfro.BonCote_tdt(noeud->Coord2())))
+// // le point final est dans la matière finale, le contact est donc valide
+// { actif = 1; // init
+// if (ParaGlob::NiveauImpression() >= 6)
+// { Enum_type_geom type_front; // va être modifier par Num_frontiere
+// cout << "\n reactivation (element contact) de l'element de contact entre noeud " << noeud->Num_noeud()
+// << " du maillage " << noeud->Num_Mail()
+// << " et frontiere "
+// << elfront->Num_frontiere()
+// << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
+// << tabNoeud(2)->Num_Mail() << endl;
+// };
+// };
+// };
+ // gestion du retour
+// if (actif) */
+ { if ((contactType == 1)|| (contactType == 3)|| (contactType == 4))
+ { M_noeud_tdt_avant_projection = noeud->Coord2();
+ // on change les coordonnées s'ils sont libres sinon on laisse inchangé
+ int dim = M_noeud_tdt_avant_projection.Dimension();
+ switch (dim)
+ { case 3: if (!(noeud->Ddl_fixe(X3))) noeud->Change_val_tdt(X3,M1(3));
+ case 2: if (!(noeud->Ddl_fixe(X2))) noeud->Change_val_tdt(X2,M1(2));
+ case 1: if (!(noeud->Ddl_fixe(X1))) noeud->Change_val_tdt(X1,M1(1));
+ default:
+ break;
+ };
+// noeud->Change_coord2(M1);
+//noeud->Change_coord2(0.5*(M1+M_noeud_tdt_avant_projection));
+ if (niveau_commentaire > 6)
+ {cout << "\n actualisation du noeud esclave "
+ << noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
+ << " ancienne position " << M_noeud_tdt_avant_projection
+ << " nouvelle position " << noeud->Coord2();
+ };
+ };
+ return true;
+ }
+/* // else
+// {return false;}; // sinon pas de contact valide */
+ }
+ else
+ // l'intersection est en dehors de la surface ou courbe maitre, on essaie une projection sur
+ // l'element voisin
+ // on itere sur les elements voisins
+ {const Tableau * ta = elfront->TabMitoyen();
+/* // debug
+//cout << "\n debug Elcontact::Actualisation ";
+//elfro.InSurf(extra_in_surface);
+//// fin debug */
+ if (ta != NULL) // cas où il y a des éléments voisins !
+ {for (int i=1; i<= ta->Taille(); i++)
+ { ElContact elct((*ta)(i),noeud,fct_nD_contact); // on cree un element contact pour utiliser ses methodes
+ M1 = elct.Intersection(V,true);
+ // ici on recherche avec une précision donnée
+ double extra_in_surface = ParaGlob::param->ParaAlgoControleActifs().PointInternePrecThetaiInterne();
+ // dans le cas ou M1 a une dimension nulle, signifie qu'il n'y a pas d'intersection,
+ // on n'examine que le cas où la dimension est différente de 0
+ if (M1.Dimension() != 0)
+ { if (elct.Elfront()->Eleme()->InSurf(extra_in_surface))
+ // on a trouve une bonne intersection
+ { // --- changement d'element frontiere
+ // on commence par sauvegarder (*ta)(i)
+ Front* newelfront = new Front(*((*ta)(i)));
+ Libere(); // on supprime le elfront actuel, donc le tableau ta
+ elfront = newelfront; // on récupére le nouvelle élément créé
+ Construction_TabNoeud(); // on reconstruit le tableau de noeud global
+ Mtdt = M1;
+/* // si l'élément n'est pas actuellement actif on regarde si le contact est valide c-a-d si le noeud est dans la matière
+ // si oui on active l'élément, sinon on laisse tel quel et on ne change pas le noeud par exemple.
+// if (!actif)
+// {if (!(elfro.BonCote_tdt(noeud->Coord2())))
+// // le point final est dans la matière finale, le contact est donc valide
+// { actif = 1;
+// if (ParaGlob::NiveauImpression() >= 6)
+// { Enum_type_geom type_front; // va être modifier par Num_frontiere
+// cout << "\n reactivation de l'element de contact entre noeud " << noeud->Num_noeud()
+// << " du maillage " << noeud->Num_Mail()
+// << " et frontiere "
+// << elfront->Num_frontiere()
+// << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
+// << tabNoeud(2)->Num_Mail() << endl;
+// };
+// };
+// }; */
+ // gestion du retour
+ if ((contactType == 1)|| (contactType == 3)|| (contactType == 4))
+ { M_noeud_tdt_avant_projection = noeud->Coord2();
+ // on change les coordonnées s'ils sont libres sinon on laisse inchangé
+ int dim = M_noeud_tdt_avant_projection.Dimension();
+ switch (dim)
+ { case 3: if (!(noeud->Ddl_fixe(X3))) noeud->Change_val_tdt(X3,M1(3));
+ case 2: if (!(noeud->Ddl_fixe(X2))) noeud->Change_val_tdt(X2,M1(2));
+ case 1: if (!(noeud->Ddl_fixe(X1))) noeud->Change_val_tdt(X1,M1(1));
+ default:
+ break;
+ };
+// noeud->Change_coord2(M1);
+ if (niveau_commentaire > 6)
+ {cout << "\n actualisation du noeud esclave "
+ << noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
+ << " ancienne position " << M_noeud_tdt_avant_projection
+ << " nouvelle position " << noeud->Coord2();
+ };
+ };
+ return true;
+ };
+ };
+ };
+ };
+ };
+ // cas ou l'on n'a pas trouve d'intersection,
+ return false;
+};
+
+
+// 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 ElContact::Decol()
+{ // recup de la dimension
+ int dim = noeud->Dimension();
+ // recup du dernier plan tangent (ou droite)
+ // dimensionnement des variables de tangence
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ // calcul du dernier plan tangent
+ (elfront->Eleme())->DernierTangent(dr,pl,indic);
+ // recherche de la normale ,traitement suivant les different cas
+ Coordonnee N = Calcul_Normale(dim,pl,dr, indic); // elle pointe vers l'extérieur de l'élément
+ // donc vers l'intérieur de l'élément esclave
+ // def du decollement
+ double r = - force_contact * N;
+
+
+//----------- debug--------------
+/*{// a priori on suppose que le contact est collant --> calcul des efforts de contact
+Coordonnee Noe_atdt = noeud->Coord2(); // récup de la position actuelle du noeud projectile
+ // recup du dernier des différentes informations
+ Coordonnee M_impact,N; // le point d'impact, la normale
+ Vecteur phii;
+ RecupInfo(N,M_impact,phii);
+
+// calcul de la pénétration normale
+Coordonnee deltaX = Noe_atdt - M_impact;
+double gap= N * deltaX;
+
+cout << "\n noeud: " << noeud->Num_noeud() << ": gap= " << gap << ", F_N= " << r << endl;
+}*/
+//----------- fin debug--------------
+
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ // NB: nb_decol_tdt est également mis à 0 lors de l'inactivation ou de l'activation de l'élément: cf. Met_Inactif() et Met_actif()
+ if (r <= 0)
+ // ici cas classique on dit qu'il n'y a pas décolement car la réaction est négative
+ {nb_decol_tdt=0;return false;} // cas d'une compression
+ else // cas d'une traction
+ {nb_decol_tdt++; // cas d'une traction
+ int typededecolement = ParaGlob::param->ParaAlgoControleActifs().TypeDeDecolement();
+ if (!typededecolement) // dans le cas classique (==0), on regarde uniquement la réaction
+ { if (nb_decol_tdt >= ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise())
+ { if (niveau_commentaire >= 4)
+ cout << "\n cas d'une reaction positive: + nb decollement nb_decol_tdt= ("
+ << nb_decol_tdt << "): qui depasse le nombre de decollement ("
+ << ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise()
+ << ") tolere ";
+ if (niveau_commentaire >= 7)
+ {cout << "\n force de contact: "<< force_contact;
+ cout << "\n normale: "<< N;
+ cout << "\n intensite du contact (r = - force_contact * N;) "
+ << r ;
+ };
+ return true;
+ }
+ else {return false;};
+ }
+ else // sinon on dit qu'il y a décollement que si la non pénétration, est supérieur à une certaine valeur
+ // cependant, le facteur de pénalisation sera quasi-nulle ou même strictement nulle donc finalement, la force de réaction
+ // n'aura pas d'importance sur l'équilibre, par contre l'élément restera ce qui évite de le reconstruire
+ // et peut-être évite les oscillation
+ {if (gap_tdt > Dabs(borne_regularisation) * typededecolement)
+ {if (nb_decol_tdt >= ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise())
+ { if (niveau_commentaire >= 4)
+ cout << "\n cas d'un gap > Dabs(borne_regularisation) ("
+ << Dabs(borne_regularisation) << " * typededecolement ("
+ << typededecolement << ") : + nb decollement nb_decol_tdt= ("
+ << nb_decol_tdt << "): qui depasse le nombre de decollement ("
+ << ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise()
+ << ") tolere ";
+ if (niveau_commentaire >= 7)
+ {cout << "\n gap_tdt= " << gap_tdt
+ << ", force de contact: "<< force_contact;
+ cout << "\n normale: "<< N;
+ cout << "\n intensite du contact (r = - force_contact * N;) "
+ << r ;
+ };
+ return true;
+ }
+ else {return false;}; // pas encore de libération
+ }
+ else {return false; }; // sinon on maintient le contact, donc pas de décollement
+ };
+ };
+};
+
+// 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 ElContact::Change_force(const Coordonnee& force)
+ {force_contact = force;
+ // -- on met à jour également la partie force tangentielle et normale individuellement
+ // recup du dernier plan tangent (ou droite)
+ // dimensionnement des variables de tangence
+ int dim = noeud->Dimension();
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ elfro.DernierTangent(dr,pl,indic);
+ // calcul de la normale en fonction de differente conditions
+ Coordonnee N( Calcul_Normale(dim,pl,dr,indic));
+
+ F_N_max = Dabs(force_contact*N); // sauvegarde
+ F_T_max = sqrt(force_contact.Norme()-F_N_max*F_N_max);
+
+
+ };
+
+// 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 ElContact::Pas_de_temps_ideal()const
+{ double delta_optimal=ConstMath::tresgrand;
+ // récupération du temps
+ double delta_t = ParaAlgoControle::Variables_de_temps().IncreTempsCourant();
+ // limitation au niveau du gap
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ if (actif && (borne_regularisation < 0)
+ && ((contactType == 2) || (contactType == 4)|| (contactType == 41)|| (contactType == 42))
+ )
+ {if (gap_tdt < - Dabs(borne_regularisation))
+ delta_optimal = delta_t * Dabs(borne_regularisation / gap_tdt);
+ };
+ // 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;
+};
+
+
+// permet de modifier le contact entre collant ou non suivant "change"
+void ElContact::Change_contact_collant(bool change)
+ { // dans une première mouture c'est assez simple mais on définit une méthode
+ // interne car je pressent que cela pourrait se complexifier !
+ if (change )
+ {cas_collant = 1;}
+ else
+ {cas_collant = 0;};
+ };
+
+
+// récupération des ddl ou des grandeurs actives de tdt vers t
+void ElContact::TdtversT()
+ { Mt=Mtdt;gap_t = gap_tdt; nb_pene_t = nb_pene_tdt;
+ dep_T_t = dep_T_tdt;
+ mult_pene_t=mult_pene_tdt;
+ mult_tang_t=mult_tang_tdt;
+ type_trajectoire_t = type_trajectoire_tdt;
+ nb_decol_t = nb_decol_tdt;
+ nb_posi_esclave_stocker_t = nb_posi_esclave_stocker_tdt;
+ indice_stockage_glissant_t = indice_stockage_glissant_tdt;
+ force_contact_t=force_contact;
+ tabForce_cont_t=tabForce_cont;
+ F_N_max_t = F_N_max; F_T_max_t=F_T_max;
+ penalisation_t = penalisation;
+ penalisation_tangentielle_t = penalisation_tangentielle;
+ };
+// actualisation des ddl et des grandeurs actives de t vers tdt
+void ElContact::TversTdt()
+ { if (Mt.Dimension() != 0)
+ Mtdt=Mt;
+ gap_tdt = gap_t; nb_pene_tdt = nb_pene_t;
+ dep_T_tdt = dep_T_t;
+ mult_pene_tdt=mult_pene_t;
+ mult_tang_tdt=mult_tang_t;
+ type_trajectoire_tdt = type_trajectoire_t;
+ nb_decol_tdt = nb_decol_t;
+ nb_posi_esclave_stocker_tdt = nb_posi_esclave_stocker_t;
+ indice_stockage_glissant_tdt = indice_stockage_glissant_t;
+ force_contact=force_contact_t;
+ tabForce_cont=tabForce_cont_t;
+ F_N_max = F_N_max_t; F_T_max=F_T_max_t;
+ penalisation = penalisation_t;
+ penalisation_tangentielle = penalisation_tangentielle_t;
+ };
+
+//----- lecture écriture base info -----
+// lecture base info
+void ElContact::Lec_base_info_ElContact(ifstream& ent)
+ { // tout d'abord les données propres à l'élément
+ string toto;
+////debug
+// if (noeud->Num_noeud()==56)
+// {
+// cout << "\n debug : ElContact::Lec_base_info_ElContact: noeud 56"<< endl;
+// };
+//// fin debug
+ ent >> toto >> toto >> actif
+ >> toto >> Mt
+ >> toto >> energie_frottement
+ >> toto >> energie_penalisation
+ >> toto >> penalisation_t >> toto >> penalisation_tangentielle_t ;
+ penalisation = penalisation_t; penalisation_tangentielle = penalisation_tangentielle_t;
+ ent >> toto >> num_zone_contact >> toto >> cas_collant
+ >> toto >> phi_theta_0;
+ ent >> toto >> force_contact >> toto >> tabForce_cont
+ >> toto >> F_N_max >> toto >> F_T_max
+ >> toto >> gap_t >> toto >> nb_decol_t >> toto >> nb_pene_t
+ >> toto >> dep_T_t
+ >> toto >> mult_pene_t
+ >> toto >> mult_tang_t
+ >> toto >> type_trajectoire_t ;
+ ent >> toto >> N >> toto >> dep_tangentiel;
+ // on identifie les grandeurs à tdt
+ Mtdt = Mt;
+ nb_decol_tdt = nb_decol_t;
+ gap_tdt=gap_t;dep_T_tdt = dep_T_t;
+ nb_pene_tdt = nb_pene_t;
+ mult_pene_tdt = mult_pene_t;
+ mult_tang_tdt = mult_tang_t;
+ type_trajectoire_tdt = type_trajectoire_t;
+
+ // puis les données frontière
+ elfront->Lecture_base_info_front(ent);
+
+ };
+// écriture base info
+// ici comme les contacts peuvent apparaitre à tout moment, cela n'a pas de sens de faire des sauvegardes partielles
+// donc on sauvegarde toujours tout
+// on ne sauvegarde que ce qui est particulier à l'élément (en particulier ce qui est relatif au noeud esclave et à l'éléments finis
+// n'est évidemment pas sauvegardé ici)
+void ElContact::Ecri_base_info_ElContact(ofstream& sort)
+ { // écriture du type
+ sort << "\n Elcontact: ";
+ // les aspects liés au traitement du contact
+ sort << " actif= " << actif << " Mtdt= " << Mt << " ener_frot= " << energie_frottement
+ << " ener_penal= " << energie_penalisation
+ << " penalisation= " << penalisation_t
+ << " penalisation_tangentielle= " << penalisation_tangentielle_t;
+ sort << "\n num_zone_contact= " << num_zone_contact << " cas_collant= " << cas_collant
+ << " phi_theta_0= " << phi_theta_0;
+ sort << "\n F_cont= " << force_contact << " F_facette= "<< tabForce_cont
+ << " norme_F_N= " << F_N_max << " norme_F_T= " << F_T_max
+ << "\n gap= " << gap_t
+ << " nb_decol= " << nb_decol_t << " nb_pene= " << nb_pene_t
+ << " dep_T_t= " << dep_T_t
+ << " mult_pene_t= " << mult_pene_t
+ << " mult_tang_t= " << mult_tang_t
+ << " type_traj= " << type_trajectoire_t ;
+ sort << "\n normale: " << N << " dep_tangentiel: " << dep_tangentiel << " ";
+ // les données frontière
+ elfront->Ecriture_base_info_front(sort);
+ sort << " " ;
+ };
+
+
+void ElContact::Libere()
+ { //delete (elfront->Eleme());
+ delete elfront;
+ elfront = NULL;
+ };
+
+ // construction du tableau de tous les noeuds, le premier est celui esclave
+ // et mise à jour de ddlElement et de list_Ddl_global éventuellement
+void ElContact::Construction_TabNoeud()
+ { // def du tableau de l'element frontiere
+ Tableau & tabnoeuddd = (elfront->Eleme())->TabNoeud();
+ int taile = tabnoeuddd.Taille() +1;
+ // def du tableau tabNoeud
+ tabNoeud.Change_taille(taile);
+ tabNoeud(1) = noeud;
+ for (int i=2; i<= taile;i++)
+ tabNoeud(i) = tabnoeuddd(i-1);
+ // --- on ajoute les ddl de réaction, si jamais cela n'est pas fait
+ Enum_ddl enu_reac_1= R_X1; // le premier ddl
+ int dim = ParaGlob::Dimension();
+ // on crée les tableau de ddl de réaction à ajouter
+ Tableau ta(dim);
+ int posi = Id_nom_ddl("R_X1") -1;
+ for (int i=1;i<=dim;i++)
+ ta(i)= Ddl(Enum_ddl(i+posi),0.0,LISIBLE_FIXE);
+ // on ajoute les ddl si ils ne sont pas présents
+ Ddl_enum_etendu& ddl_reaction_normale=Ddl_enum_etendu::Tab_FN_FT()(1);
+ Ddl_enum_etendu& ddl_reaction_tangentielle=Ddl_enum_etendu::Tab_FN_FT()(2);
+ for (int i=1; i<= taile;i++)
+ { Noeud& noe = *tabNoeud(i); // pour simplifier
+ if (!noe.Existe_ici(enu_reac_1))
+ noe.PlusTabDdl(ta);
+ // on introduit également spécifiquement la réaction normale et la réaction tangentielle
+ if (!noe.Existe_ici_ddlEtendu(ddl_reaction_normale))
+ noe.AjoutUnDdl_etendu(ddl_reaction_normale);
+ if (!noe.Existe_ici_ddlEtendu(ddl_reaction_tangentielle))
+ noe.AjoutUnDdl_etendu(ddl_reaction_tangentielle);
+ };
+
+
+ // --- cas du tableau des DdlElement
+
+ // en fait tous les éléments du tableau sont identiques et il suffit qu'ils existent
+ // on commence par parcourir la liste pour trouver un bon candidat
+ list ::iterator ili,ilifin=list_Ddl_global.end();
+ bool trouve = false;
+ for (ili=list_Ddl_global.begin();ili !=ilifin; ili++)
+ if ((*ili).NbNoeud() == taile) // on a trouvé un candidat
+ {ddlElement_assemblage = &(*ili); trouve = true;};
+ // dans le cas où on n'a pas trouvé, on en cré un
+ if (!trouve)
+ { int dima = ParaGlob::Dimension();
+ // dans le cas où on est en axisymétrie il faut diminuer de 1
+ // car on ne fera pas d'assemblage suivant la direction 3
+ if (ParaGlob::AxiSymetrie())
+ dima--;
+ DdlElement tab_ddl(taile,dima);
+ int posi = Id_nom_ddl("X1") -1;
+ for (int i =1; i<= dima; i++)
+ for (int j=1; j<= taile; j++)
+ tab_ddl.Change_Enum(j,i,Enum_ddl(i+posi));
+ list_Ddl_global.push_front(tab_ddl);
+ ddlElement_assemblage = &(*list_Ddl_global.begin());
+ };
+ tabNoeud_pour_assemblage = tabNoeud; // cas général bidéformable
+ // on appel quand même la mise à jour car elle construit également cas_solide
+ // et réduit éventuellement ddlElement_assemblage
+ Mise_a_jour_ddlelement_cas_solide_assemblage();
+ };
+
+
+// méthode statique de modification éventuelle du type de contact utilisé localement
+// par exemple pour le type 4 en fonction des itérations
+int ElContact::Recup_et_mise_a_jour_type_contact()
+ {int contactType = ParaGlob::param->ParaAlgoControleActifs().ContactType();
+ // le contact 4 passe en 2 quand on dépasse un nombre donné d'itération
+ if (contactType == 4)
+ {if (fct_pilotage_contact4 == NULL)
+ {// on récupère le pointeur correspondant à la grandeur COMPTEUR_ITERATION_ALGO_GLOBAL
+ const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
+ if (pointe == NULL)
+ { cout << "\n *** pb ElContact::mise_a_jour_type_contact(... avec le cas contact 4 !! "
+ << " la variable globale "<< Nom_GrandeurGlobale(COMPTEUR_ITERATION_ALGO_GLOBAL)
+ << ", n'est pas disponible, on ne peut pas continuer "<Grandeur_pointee()); // pour simplifier
+ int nb_changement = 1; // valeur par défaut
+ if (*(gr.ConteneurEntier()) > nb_changement) // à partir du 2 ième itérations on passe en 41
+ {contactType = 41;}
+ else if (*(gr.ConteneurEntier()) > 2 * nb_changement) // on passe à 42 après une transition
+ {contactType = 42;}
+ }
+ else // on a un pilotage via une fonction nD
+ {Tableau & tava = fct_pilotage_contact4->Valeur_pour_variables_globales();
+//cout << "\n debug ElContact::mise_a_jour_type_contac: tava(1)= " << tava(1);
+ if (tava(1) == 1)
+ {contactType = 41;}
+ else if (tava(1) == 2)
+ {contactType = 42;}
+ };
+ };
+ // retour
+ return contactType;
+
+ };
+
+
diff --git a/contact/ElContact.h b/contact/ElContact.h
new file mode 100644
index 0000000..13ae0db
--- /dev/null
+++ b/contact/ElContact.h
@@ -0,0 +1,418 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 23/01/97 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: Element de contact. *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * 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
+ };
+
+ // 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_, int collant = 0);
+ // de copie
+ ElContact ( const ElContact & a);
+ // DESTRUCTEUR :
+ ~ElContact ();
+
+ // METHODES PUBLIQUES :
+
+ // 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;};
+
+ // 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
+ void Affiche() 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;};
+
+ // 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 & TabNoeud() {return tabNoeud;};
+ const Tableau & Const_TabNoeud() const {return tabNoeud;};
+ // ramene le tableau pour assemblage: dépend du Cas_solide()
+ // est cohérent avec TableauDdlCont
+ Tableau & 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;};
+ // 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 & 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 false, sinon retourne true
+ // en fonction de la méthode de contact, le noeud est ramené éventuellement sur la frontière
+ bool Actualisation();
+
+ // ramene un pointeur sur l'element frontiere
+ inline Front * Elfront() const { return elfront;};
+ // 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 & 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;}; // met en inactif
+ void Met_actif() { actif++;nb_decol_tdt=0;}; // 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é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);
+ // récup de l'information concernant le contact collant ou pas
+ int Collant() const {return cas_collant;};
+
+ // 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(int niveau)
+ {niveau_commentaire = niveau;};
+
+ // 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(ifstream& ent);
+ void Ecri_base_info_ElContact(ofstream& sort);
+
+
+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
+ Front* elfront; // un element frontiere
+ Noeud * noeud; // un pointeur de noeud
+ int num_zone_contact; // un stockage uniquement utilisé par les méthodes appelantes
+ // pour éviter de le construire à chaque demande on définit un tableau de tous les noeuds
+ Tableau tabNoeud; // tableau de tous les noeud, le premier est noeud
+ // le tableau des positions successives du noeud esclave, ceci pour effectuer une moyenne glissante
+ Tableau 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 ;
+ 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
+ int cas_collant; // prise en compte éventuelle d'un contact collant, si 0: contact normal
+ // = 1 : contact collant
+ Vecteur * residu; // residu local
+ Mat_pleine * raideur; // raideur locale
+ DdlElement * ddlElement_assemblage; // le ddlElement qui correspond
+ Tableau 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 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 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 list_Ddl_global; // liste de tous les DdlElements des éléments de contact
+ static list list_SM; // list de seconds membres locals: sert pour tous les éléments de contact
+ static list 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
+ 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 * 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) const;
+
+ };
+ /// @} // end of group
+
+#endif
diff --git a/contact/ElContact_2.cc b/contact/ElContact_2.cc
new file mode 100755
index 0000000..345eed1
--- /dev/null
+++ b/contact/ElContact_2.cc
@@ -0,0 +1,2655 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+
+#include "ElContact.h"
+#include "Droite.h"
+#include "ConstMath.h"
+#include "MathUtil.h"
+#include "ElemMeca.h"
+#include "Util.h"
+#include
+#include "TypeConsTens.h"
+#include "TypeQuelconqueParticulier.h"
+
+
+ // --- calcul des puissances virtuelles développées par les efforts de contact ----------
+ // et eventuellement calcul de la raideur associé
+ // -> explicite à tdt
+Vecteur* ElContact::SM_charge_contact()
+ {
+ if (niveau_commentaire > 5)
+ cout << "\n -- ElContact::SM_charge_contact: ";
+
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+//cout << "\n -- debug ElContact::SM_charge_contact: contactType= " << contactType;
+
+ // def de quelques dimensions pour simplifier
+ int dima = ParaGlob::Dimension();
+ int tab_taille = tabNoeud.Taille();
+ int nbddl = ddlElement_assemblage->NbDdl();
+ energie_penalisation = 0.;
+ energie_frottement.Inita(0.);
+ // récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
+ RecupPlaceResidu(nbddl);
+ Vecteur& SM_res = *residu; // pour simplifier
+ Mise_a_jour_ddlelement_cas_solide_assemblage(); // mise à jour de ddl element et de cas_solide
+
+ // la suite de la méthode ne fonctionne que pour les type 2 et 4 de contact,
+ // dans le cas contraire on revient directement
+ if (!((contactType == 2) || (contactType == 4) || (contactType == 41)|| (contactType == 42)))
+ return residu;
+ // ---- sinon .... cas du contact par pénalisation -----
+ // dans le cas 2: on calcul un facteur de pénalisation
+ // dans le cas 4: on déduit le facteur de pénalisation à partir des forces internes
+ // et de la condition cinématique de contact
+ // on considère ici que le point de contact est déterminé et on s'occupe de déterminer les
+ // efforts éventuels dus au contact ainsi que les énergies échangées sur le pas de temps
+
+ // a priori on suppose que le contact est collant --> calcul des efforts de contact
+ Coordonnee Noe_atdt = noeud->Coord2(); // récup de la position actuelle du noeud projectile
+ // recup des dernières différentes informations calculées au niveau de la cinématique de contact
+ Coordonnee M_impact; // le point d'impact, la normale
+ Vecteur phii;
+ RecupInfo(N,M_impact,phii,false);
+ // en fait due aux différents algos de recherche de contact, normalement la position de contact est sauvegardée
+ // dans l'élément, donc on utilise cette info, par contre on utilise RecupInfo pour calculer les autres infos : normale et phi
+
+ // changement éventuel par une moyenne glissante des positions successive du noeud esclave
+ // Noe_atdt est modifié éventuellement
+ ChangeEnMoyGlissante(Noe_atdt);
+
+ // calcul de la pénétration normale: deltaX=de la surface au point pénétré
+ Coordonnee deltaX(dima);
+ switch (contactType)
+ { case 2: // cas d'une pénalisation classique
+ case 41: case 42:// idem après le basculement du cas 4
+ { deltaX = Noe_atdt - M_impact;
+ break;
+ }
+ case 4: // cas ou le noeud à été projeté sur la surface
+ // normalement Noe_atdt est identique à M_impact
+ { deltaX = M_noeud_tdt_avant_projection - Noe_atdt;
+ break;
+ }
+ default: cout << "\n erreur, le cas contactType = " << contactType
+ << " ne devrait pas exister ici !! "<< endl;
+ Sortie(1);
+ break;
+ };
+
+ // le N sort de la surface maître, donc rentre dans la surface esclave
+ double gap= N * deltaX; // gap est négatif quand il y a pénétration
+ // récupération du facteur de pénalisation adaptée au cas de calcul et à la géométrie
+ double d_beta_gap=0.; // init de la dérivée du facteur de pénalisation / au gap
+ // calcul du facteur de pénalisation si le contact est de type 2
+ if (contactType == 2)
+ { penalisation = CalFactPenal(gap,d_beta_gap,contactType);}
+ // sinon dans le cas 41 on utilise la valeur qui est en cours pondéré dans une moyenne glissante
+ // avec le type 4
+ else if (contactType == 41) // après basculement du 4 on utilise la pénalisation
+ { double essai_penalisation = CalFactPenal(gap,d_beta_gap,contactType);
+ // maintenant on va calculer la moyenne glissante, de manière à lisser les variations
+ ElContact::Moyenne_glissante_penalisation(penalisation, essai_penalisation);
+ };
+ // si on est en 42, on conserve le facteur précédemment calculé
+ gap_tdt = gap; // sauvegarde
+
+
+/* // debug
+//cout << "\n noeud: " << noeud->Num_noeud() <<" mailage:"<Num_Mail()<< " : gap= " << gap <<" \n Noe_atdt ";Noe_atdt.Affiche(); cout << " Noe_a0:"; noeud->Coord0().Affiche();
+//cout << " Noe_at:"; noeud->Coord1().Affiche();
+//cout << "\n M_impact:"; M_impact.Affiche(); cout << "\n deltaX:"; deltaX.Affiche();
+//cout << "\n N:"; N.Affiche(); cout << " debug ElContact::SM_charge_contact()"<ParaAlgoControleActifs().Penetration_contact_maxi(); */
+ int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+
+
+// pour l'instant je supprime le cas de la limitation du déplacement, car je pense qu'il faudrait y adjoindre les forces
+// de réaction associées sinon l'équilibre est faux !! donc on commente pour l'instant
+ // méthode de limitation de la pénétration: opérationnelle si max_pene > 0
+ // si max_pene < 0 on intervient sur l'incrément de temps !!
+/* if (max_pene > 0)
+ {if ((gap < (- max_pene)) && (Dabs(gap) > ConstMath::trespetit))
+ // on modifie la position du noeud pour tenir compte de la pénalisation
+// { Coordonnee nevez_posi(M_impact - 2 * max_pene * N);
+ { Coordonnee nevez_posi(M_impact + (max_pene / deltaX.Norme()) * deltaX);
+ noeud->Change_coord2(nevez_posi);
+ gap = - max_pene;
+ };
+ };*/
+
+ // --- calcul de la force normale
+ // avec limitation éventuelle de l'intensité de la force de contact
+ double intens_force = 0. ; // init
+ bool force_limiter=false;
+ Coordonnee F_N(dima); // init
+
+ switch (contactType)
+ { case 2: // cas d'une pénalisation classique
+ case 41: case 42: // idem après basculement du cas 4
+ { intens_force = gap * penalisation; // négatif quand on a pénétration
+ double max_force_noeud;
+ if (fct_nD_contact.fct_nD_force_contact_noeud_maxi != NULL)
+ {max_force_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_contact_noeud_maxi);}
+ else {max_force_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_contact_noeud_maxi();}
+ if (Dabs(intens_force) > max_force_noeud)
+ {intens_force = max_force_noeud * Signe(intens_force);
+ force_limiter = true;
+ }
+ // F_N c'est la force qui appuie sur le noeud esclave d'où le - car intens_force est négatif
+ F_N = - N * intens_force; //(-gap * penalisation);
+ break;
+ }
+ case 4: // cas ou le noeud à été projeté sur la surface
+ // on récupère la force de contact via la puissance interne des éléments contenants
+ // le noeud exclave (le calcul des forces internes doit déjà avoir été effectué)
+ { TypeQuelconque_enum_etendu enu(FORCE_GENE_INT);
+ // récupération du conteneur pour lecture uniquement
+ const TypeQuelconque& typquel = noeud->Grandeur_quelconque(enu);
+ const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
+ // signe - car le contact doit s'opposer exactement à l'effort interne
+ F_N = - cofo.ConteneurCoordonnee_const(); // récup de - la réaction
+ // en fait on ne va garder que la partie normale à la facette, ce qui laissera le glissement possible
+ intens_force = - F_N * N; // 1) projection de la réaction
+ F_N = - N * intens_force; // 2) recalcul uniquement de la partie normale
+ // on va également tenter un calcul d'une pénalisation équivalente
+// penalisation = Dabs(intens_force / (Dabs(gap)));// + ConstMath::unpeupetit)) ;
+ double max_pene;
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
+ {max_pene = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi));}
+ else {max_pene = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi());}
+
+
+
+// double essai_penalisation; // variable intermédiaire
+// if (Dabs(gap) > max_pene)
+// {essai_penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
+// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
+// {essai_penalisation = Dabs(intens_force) / max_pene;
+// if (niveau_commentaire > 5) cout << "\n (penalisation limite) ";
+// };
+// // on tient compte d'un facteur multiplicatif éventuelle
+
+ // a priori c'est cette méthode qui est la plus performante (idem implicite)
+ double essai_penalisation = Dabs(intens_force) / max_pene;
+
+ // maintenant on va calculer la moyenne glissante
+ ElContact::Moyenne_glissante_penalisation(penalisation, essai_penalisation);
+
+
+// if (Dabs(gap) > max_pene)
+// {penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
+// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
+// {penalisation = Dabs(intens_force) / max_pene;
+// if (niveau_commentaire > 5) cout << "\n (penalisation limite) ";
+// };
+ if (niveau_commentaire > 6) cout << " F_N(pur)= " << F_N << " ";
+ break;
+ }
+ default: break; // déjà vu au dessus
+ };
+ F_N_max = Dabs(intens_force); // sauvegarde
+//cout << "\n SM_charge_contact: penalisation= "<< penalisation;
+ // -- ici on a un traitement différent suivant typ_cal ---
+ // Dans le cas du contact 4 on ne s'occupe pas du type de calcul de pénalisation
+ if (contactType != 4)
+ { switch (typ_cal)
+ {case 1: case 2: case 3: // cas le plus simple : pas de calcul particulier
+ if (gap > 0) // non ce n'est pas bizarre c'est le cas où le noeud décolle
+ // c'est aussi le cas où on a un type de calcul de la pénalisation = 4 (il y aura une très légère force de collage pour
+ // gap > 0 mais < borne_regularisation
+ // par contre on annulle effectivement le résidu
+ { //cout << "\n *** bizarre la penetration devrait etre negative ?? , on annule les forces de contact "
+ // << "\n ElContact::SM_charge_contact(...";
+ force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
+ // au cas où on met à 0 les forces de réaction sur la facette
+ int nb_n_facette = tabForce_cont.Taille();
+ for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
+ if (niveau_commentaire > 6)
+ { cout << "\n noeud: " << noeud->Num_noeud() << ": force collage non prise en compte " << force_contact
+ << " gap(positif)= " << gap << ", Normale= " << N;
+ cout << "\n deltaX " << deltaX
+ <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+ << " penalisation= " << penalisation
+ << " intensite force = " << intens_force ;
+ };
+ // on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
+ return residu; // les résidu + raideur sont nul à ce niveau de la méthode
+ };
+ break;
+ case 4: case 5:case 6:
+ if (gap > Dabs(borne_regularisation))
+ // on est sortie de la zone d'accostage donc on neutralise le contact
+ { force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
+ // au cas où on met à 0 les forces de réaction sur la facette
+ int nb_n_facette = tabForce_cont.Taille();
+ for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
+ if (niveau_commentaire >= 6)
+ { cout << "\n noeud: " << noeud->Num_noeud()
+ << ": force collage non prise en compte " << force_contact
+ << " gap(positif et > borne regularisation)= " << gap << ", Normale= " << N;
+ cout << "\n deltaX " << deltaX
+ <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+ << " penalisation= " << penalisation
+ << " intensite force = " << intens_force ;
+ };
+ // on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
+ return residu; // les résidu + raideur sont nul à ce niveau de la méthode
+ };
+ break;
+ case 7: case 8:
+ // par rapport aux autres cas, on neutralise rien
+ break;
+ default :
+ cout << "\n *** cas pas pris en compte !! \n SM_charge_contact() " << endl;
+ Sortie(1);
+ };
+ };
+ // -- fin du traitement différent suivant typ_cal ---
+
+/*
+////////debug
+// if (ParaGlob::NiveauImpression() >= 6)
+//// if (noeud->Num_noeud()==113)
+// {
+//// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113";
+// cout << "\n noeud: " << noeud->Num_noeud();
+// cout << "\n deltaX " << deltaX
+// <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+// <<"\n gap= " << gap << " N= " << N << " penalisation= " << penalisation << endl
+// ;
+// };
+////// fin debug
+//////debug
+// if (noeud->Num_noeud()==113)
+// {
+// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113"
+// << "\n force " << F_N << " force_limiter "<PtEI(); // récup de l'élément fini
+ CompFrotAbstraite* loiFrot = ((ElemMeca*) elemf)->LoiDeFrottement();
+ penalisation_tangentielle = 0.; // init
+ bool force_T_limiter = false; // init
+ if (loiFrot != NULL)
+ { // --- cas de l'existance d'une loi de frottement
+ // calcul du déplacement tangentiel
+ Coordonnee M_tatdt;
+ if (Mt.Dimension() != 0)
+ {M_tatdt = (Mtdt-Mt);} // déplacement total
+ // sinon Mt n'est pas encore définit donc on ne peut pas calculer le déplacement
+ // il est donc laissé à 0.
+ dep_tangentiel = M_tatdt- N * (M_tatdt*N); // on retire le deplacement normal éventuel
+ // calcul de la force tangentielle en supposant tout d'abord un contact collant
+ double penalisation_tangentielle;
+ if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
+ {penalisation_tangentielle = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle);}
+ else {penalisation_tangentielle = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
+// F_T =dep_tangentiel*(-ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact());
+ F_T =dep_tangentiel*(-penalisation_tangentielle);
+ // -- vérification en appelant le comportement en frottement ----
+ // tout d'abord on récupère le delta t pour le calcul de la vitesse
+ double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
+ double unSurDeltat=0;
+ if (Abs(deltat) >= ConstMath::trespetit)
+ {unSurDeltat = 1./deltat;}
+ else
+ // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
+ { // non un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
+ if (unSurDeltat < 0)
+ { cout << "\n le pas de temps est négatif !! "
+ << "\n ElContact::SM_charge_contact(...";
+ };
+ unSurDeltat = ConstMath::tresgrand;
+ };
+ // calcul des vitesses
+ Coordonnee vit_T = dep_tangentiel * unSurDeltat;
+ // appel de la loi de comportement: calcul de la force de frottement et des énergies échangées
+ Coordonnee nevez_force_frot;EnergieMeca energie;
+ bool glisse = loiFrot->Cal_explicit_contact_tdt(vit_T,N,F_N,F_T,energie,deltat,nevez_force_frot);
+
+ // if (vit_T * nevez_force_frot > 0)
+ // cout << "\n bizarre puissance de frottement positive !";
+
+
+ if (glisse) // on remplace la force de frottement si ça glisse sinon on conserve F_T
+ F_T = nevez_force_frot;
+ // --- calcul des énergies échangées
+ energie_frottement += energie;
+ }
+ else if ( cas_collant)
+ { // --- cas d'un contact collant sans loi de frottement explicite
+ // calcul du déplacement tangentiel par rapport au premier point de contact
+ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ const Coordonnee & M_C0 = elfro.Metrique()->PointM_tdt // ( stockage a tdt)
+ (elfro.TabNoeud(),phi_theta_0);
+ Coordonnee M_0atdt = (Noe_atdt-M_C0); // déplacement total à partir du point d'impact initial
+ // transportée via l'interpolation: c-a-d les phi_theta_0 qui restent constant
+ dep_tangentiel = M_0atdt- N * (M_0atdt*N); // on retire le deplacement normal éventuel
+ double dep_T = dep_tangentiel.Norme();
+ // calcul de la pénalisation
+ double d_beta_dep_T=0.; // init de la dérivée du facteur de pénalisation / au déplacement
+ // pour l'instant ne sert pas
+ penalisation_tangentielle = CalFactPenalTangentiel(dep_T,d_beta_dep_T);
+ dep_T_tdt = dep_T; // sauvegarde
+
+ // calcul de la force tangentielle en supposant un contact collant
+ F_T = -dep_tangentiel * penalisation_tangentielle;
+ // limitation éventuelle de la force
+ double max_force_T_noeud;
+ if (fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi != NULL)
+ {max_force_T_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi);}
+ else {max_force_T_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_tangentielle_noeud_maxi();}
+ double n_F_T = Dabs(penalisation_tangentielle * dep_T);
+ if (n_F_T > max_force_T_noeud)
+ {F_T *= max_force_T_noeud/n_F_T;
+ force_T_limiter = true;
+ };
+ F_T_max = F_T.Norme();
+ // --- calcul des énergies échangées
+ // ici il s'agit d'une énergie élastique, que l'on ajoute à la pénalisation normale
+ // énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
+ energie_penalisation += Dabs(0.5 * F_T * dep_tangentiel); // pour que le résultat soit > 0
+ energie_frottement.ChangeEnergieElastique(energie_penalisation);
+ }; // --- calcul des puissances virtuelles
+
+ force_contact = F_T + F_N;
+ if (niveau_commentaire >= 5)
+ { cout << "\n noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
+ if (force_limiter) cout << " force normale en limite " ;
+ if (force_T_limiter) cout << " force tangentielle en limite " ;
+ };
+/* ////debug
+// if (noeud->Num_noeud()==207)
+// {
+// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113";
+// cout << "\n noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
+// if (force_limiter) cout << " force en limite " ;
+// };
+//// fin debug
+// -- debug
+//double inten = force_contact.Norme();
+//if (inten > 0)
+// cout << "\n force_contact = " << force_contact << " (ElContact::SM_charge_contact())" << endl;
+// -- fin debug */
+
+ int posi = Id_nom_ddl("R_X1") -1; // préparation pour les réactions
+ Ddl_enum_etendu& ddl_reaction_normale=Ddl_enum_etendu::Tab_FN_FT()(1);
+ Ddl_enum_etendu& ddl_reaction_tangentielle=Ddl_enum_etendu::Tab_FN_FT()(2);
+ // une petite manip pour le cas axisymétrique: dans ce cas les ddl à considérer pour le résidu et la raideur
+ // doivent être uniquement x et y donc 2 ddl au lieu de 3. (rien ne dépend de z)
+ int nb_ddl_en_var = dima; // init
+ bool axi = false;
+ if (ParaGlob::AxiSymetrie())
+ { nb_ddl_en_var -= 1; axi = true;};
+ // a- cas du noeud projectile
+ int ism=1;
+ if ((cas_solide == 0 ) || (cas_solide == 1))
+ // cas où le noeud est libre
+ {for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++) // pour le noeud projectile la vitesse virtuelle associé est
+ { SM_res(ism)= force_contact(ix); // directement la vitesse du noeud
+ // on abonde au niveau de la réaction au noeud
+ noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
+ };
+ }
+ else
+ // on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
+ {for (int ix=1;ix<=dima;ix++) // pour le noeud projectile la vitesse virtuelle associé est
+ // on abonde au niveau de la réaction au noeud
+ noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
+ };
+ // dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+// if (axi) ism++; // qui n'est pas pris en compte // on abonde au niveau de la réaction normale et tangentielle pour le noeud esclave
+ noeud->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force;
+ double intensite_tangentielle = F_T.Norme();
+ noeud->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle;
+
+ // b- cas de la surface cible
+ if ((cas_solide == 0 ) || (cas_solide == 2))
+ // cas où la facette est libre
+ {for (int ir=1;ir<=tab_taille-1;ir++)
+ { Noeud* noe = tabNoeud(ir+1); // pour simplifier
+ tabForce_cont(ir) = -force_contact*phii(ir);
+ for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++)
+ { double force_imp = -force_contact(ix)*phii(ir);
+ SM_res(ism)= force_imp;
+ // on abonde au niveau de la réaction au noeud
+ noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
+ };
+ // dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+// if (axi) ism++; // qui n'est pas pris en compte
+ // on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
+ noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
+ noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
+ };
+ }
+ else
+ // on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
+ {for (int ir=1;ir<=tab_taille-1;ir++)
+ { Noeud* noe = tabNoeud(ir+1); // pour simplifier
+ tabForce_cont(ir) = -force_contact*phii(ir);
+ for (int ix=1;ix<=dima;ix++)
+ { double force_imp = -force_contact(ix)*phii(ir);
+ // on abonde au niveau de la réaction au noeud
+ noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
+ };
+ // on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
+ noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
+ noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
+ };
+ };
+ if (niveau_commentaire >= 7)
+ { cout << "\n =-=-=- bilan sur le calcul de l'element de contact: =-=-=- ";
+ this->Affiche();
+ };
+
+/* // retour
+////debug
+// cout << "\n debug : ElContact::SM_charge_contact()";
+//noeud->Affiche();
+//for (int ir=1;ir<=tab_taille-1;ir++)
+// tabNoeud(ir+1)->Affiche();
+//
+// cout << "\n residu " << *residu < implicite,
+Element::ResRaid ElContact::SM_K_charge_contact()
+ { if (niveau_commentaire > 5)
+ cout << "\n -- SM_K_charge_contact: ";
+ // le contact 4 passe en 41 ou 42 quand on dépasse un nombre donné d'itérations par exemple
+ int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
+ // préparation du retour
+ Element::ResRaid el;el.res=NULL;el.raid=NULL;
+ energie_penalisation = 0.;
+ energie_frottement.Inita(0.);
+ Mise_a_jour_ddlelement_cas_solide_assemblage(); // mise à jour de ddl element et de cas_solide
+ // dans le cas du modèle de contact cinématique, on n'a pas de contribution (pour l'instant) au second membre et à la raideur
+ // cela pourrait changer si l'on considérait le frottement, mais pour l'instant ce n'est pas le cas
+ // on retourne un pointeur null
+ if (contactType == 1)
+ return el;
+ // def de quelques dimensions pour simplifier
+ int dima = ParaGlob::Dimension();
+ int tab_taille = tabNoeud.Taille();
+ int nbddl = ddlElement_assemblage->NbDdl();
+ // récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
+ RecupPlaceResidu(nbddl);
+ Vecteur& SM_res = *residu; // pour simplifier
+ // idem pour la raideur
+ RecupPlaceRaideur(nbddl);
+ // ---- initialisation de SM et de la raideur
+ SM_res.Zero();raideur->Initialise(0.0);
+ el.res = residu;
+ el.raid = raideur;
+ // la suite de la méthode ne fonctionne que pour les type 2 et 4 de contact,
+ // dans le cas contraire on revient directement
+ if (!((contactType == 2) || (contactType == 4) || (contactType == 41) || (contactType == 42)))
+ return el;
+
+ // ---- sinon .... cas du contact par pénalisation -----
+ // dans le cas 2: on calcul un facteur de pénalisation
+ // dans le cas 4: on déduit le facteur de pénalisation à partir des forces internes
+ // et de la condition cinématique de contact
+ // on considère ici que le point de contact est déterminé et on s'occupe de déterminer les
+ // efforts éventuels dus au contact ainsi que les énergies échangées sur le pas de temps
+
+ // a priori on suppose que le contact est collant --> calcul des efforts de contact
+ Coordonnee Noe_atdt = noeud->Coord2(); // récup de la position actuelle du noeud projectile
+ // recup du dernier des différentes informations
+ Coordonnee M_impact; // le point d'impact, la normale
+ Vecteur phii;
+////debug
+// if (noeud->Num_noeud()==56)
+// {
+// cout << "\n debug : ElContact::SM_K_charge_contact(): noeud 409"
+// << endl;
+// };
+//// fin debug
+ Tableau * d_T_pt = (RecupInfo(N,M_impact,phii,true));
+ // en fait due aux différents algos de recherche de contact, normalement la position de contact est sauvegardée
+ // dans l'élément, donc on utilise cette info, par contre on utilise RecupInfo pour calculer les autres infos : normale et phi
+ // M_impact et Mtdt sont différents uniquement dans le cas d'un restart
+ // Mtdt est mis à jour pendant la recherche du contact
+ M_impact = Mtdt;
+ // changement éventuel par une moyenne glissante des positions successive du noeud esclave
+ // Noe_atdt est modifié éventuellement
+ ChangeEnMoyGlissante(Noe_atdt);
+
+ // calcul de la pénétration normale
+ Coordonnee deltaX(dima);
+ switch (contactType)
+ { case 2: // cas d'une pénalisation classique
+ case 41 : case 42: // idem après basculement du 4
+ { deltaX = Noe_atdt - M_impact;
+ break;
+ }
+ case 4: // cas ou le noeud à été projeté sur la surface
+ // normalement Noe_atdt est identique à M_impact
+ { deltaX = M_noeud_tdt_avant_projection - Noe_atdt;
+ break;
+ }
+ default: cout << "\n *** erreur, le cas contactType = " << contactType
+ << " ne devrait pas exister ici !! "<< endl;
+ Sortie(1);
+ break;
+ };
+
+
+ double gap= N * deltaX; // ce qui constitue la fonction g(ddl) à annuler voir à minimiser
+ if ((niveau_commentaire > 7) && (contactType==4))
+ {double a = (deltaX - gap*N).Norme(); // on calcule pour vérifier
+ cout << " diff_projX= "<< a; // l'erreur de projection normale
+ };
+////debug
+// if (noeud->Num_noeud()==56)
+// {
+// cout << "\n debug : ElContact::SM_K_charge_contact(): noeud 409"
+// << "\n deltaX " << deltaX
+// <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+// <<"\n gap= " << gap << " N= " << N << endl
+// ;
+// };
+//// fin debug
+ // récupération du facteur de pénalisation adaptée au cas de calcul et à la géométrie
+ double d_beta_gap=0.; // init de la dérivée du facteur de pénalisation / au gap
+ // calcul du facteur de pénalisation si le contact est de type 2
+ if (contactType == 2)
+ {penalisation = CalFactPenal(gap,d_beta_gap,contactType);}
+ // sinon dans le cas 41 ou 42 on utilise la valeur qui est en cours
+ // il n'y a pas de différence entre 41 et 42 en implicite
+ gap_tdt = gap; // sauvegarde
+ // limitation au niveau du gap à 2 fois la pénétration maxi
+// double max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
+
+//debug
+// if (noeud->Num_noeud()==7)
+// {double max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();
+// if ((gap_t > max_pene) && (gap_tdt > max_pene))
+// {cout << "\n debug : ElContact::SM_K_charge_contact(): noeud 7"
+// << "\n gap_t " << gap_t << " max_pene= " << max_pene
+// <<"\n gap_tdt= " << gap_tdt << " M_impact= " << M_impact
+// <<"\n gap= " << gap << " N= " << N << endl;
+// };
+// };
+// fin debug
+// pour l'instant je supprime le cas de la limitation du déplacement, car je pense qu'il faudrait y adjoindre les forces
+// de réaction associées sinon l'équilibre est faux !! donc on commente pour l'instant
+/* // méthode de limitation de la pénétration: opérationnelle si max_pene > 0
+ // si max_pene < 0 on intervient sur l'incrément de temps !!
+ if (max_pene > 0)
+ {if ((typ_cal == 5) && (gap < (- 2 * max_pene)))
+ // on modifie la position du noeud pour tenir compte de la pénalisation
+// { Coordonnee nevez_posi(M_impact - 2 * max_pene * N);
+ { Coordonnee nevez_posi(M_impact + (2. * max_pene / deltaX.Norme()) * deltaX);
+ noeud->Change_coord2(nevez_posi);
+ };
+ };*/
+
+ // --- calcul de la force normale
+ // limitation éventuelle de l'intensité de la force de contact
+ double intens_force = 0. ; // init
+ bool force_limiter=false;
+ Coordonnee F_N(dima); // init
+
+ double max_force_noeud;
+ if (fct_nD_contact.fct_nD_force_contact_noeud_maxi != NULL)
+ {max_force_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_contact_noeud_maxi);}
+ else {max_force_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_contact_noeud_maxi();}
+ switch (contactType)
+ { case 2: // cas d'une pénalisation classique
+ case 41: case 42: // idem après basculement du cas 4
+ { intens_force = gap * penalisation; // négatif quand on a pénétration
+ if (Dabs(intens_force) > max_force_noeud)
+ {intens_force = max_force_noeud * Signe(intens_force);
+ force_limiter = true;
+ };
+ // on recalcul la pénalisation associée
+ if ((Dabs(gap) > ConstMath::trespetit) && force_limiter)
+ {penalisation = intens_force / gap;
+ if (niveau_commentaire > 5)
+ {cout << " ** limitation penalisation= " << penalisation
+ << " intensite force = " << intens_force << flush;};
+ };
+ // F_N c'est la force qui appuie sur le noeud esclave d'où le - car intens_force est négatif
+ F_N = - N * intens_force; //(-gap * penalisation);
+ break;
+ }
+ case 4: // cas ou le noeud à été projeté sur la surface
+ // on récupère la force de contact via la puissance interne des éléments contenants
+ // le noeud exclave (le calcul des forces internes doit déjà avoir été effectué)
+ { TypeQuelconque_enum_etendu enu(FORCE_GENE_INT);
+ // récupération du conteneur pour lecture uniquement
+ const TypeQuelconque& typquel = noeud->Grandeur_quelconque(enu);
+ const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
+ // signe - car le contact doit s'opposer exactement à l'effort interne
+ F_N = - cofo.ConteneurCoordonnee_const(); // récup de - la réaction
+ if (niveau_commentaire > 6) cout << " F_N(force_interne)= " << F_N << " ";
+ // en fait on ne va garder que la partie normale à la facette, ce qui laissera le glissement possible
+ intens_force = - F_N * N; // 1) projection de la réaction
+ F_N = - N * intens_force; // 2) recalcul uniquement de la partie normale
+ // on va également tenter un calcul d'une pénalisation équivalente
+ double max_pene;
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
+ {max_pene = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi));}
+ else {max_pene = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi());}
+ // l'idée est de viser la pénétration max_pene, car en pénalisation, le fait
+ // de conserver la pénétration et la force constatées, ne va pas diminuer la pénétration
+ // or on aimerait une pénétration petite !! a priori celle = max_pene
+// // si cette grandeur est plus petite que gap
+// // si par contre max_pene est grand, (ou bien plus grand que gap) on utilise gap
+// penalisation = Dabs(intens_force) / (MiN(max_pene, Dabs(gap)));
+// if (Dabs(gap) > max_pene)
+// {penalisation = Dabs(intens_force) / max_pene; }
+// else
+// {penalisation = Dabs(intens_force) / Dabs(gap);}
+
+ // a priori c'est cette méthode qui est la plus performante
+ penalisation = Dabs(intens_force) / max_pene;
+
+// if (Dabs(gap) > max_pene)
+// {penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
+// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
+// {penalisation = Dabs(intens_force) / max_pene;
+// if (niveau_commentaire > 5) cout << "\n (penalisation limite) ";
+// };
+ if (niveau_commentaire > 6) cout << " F_N(pur)= " << F_N << " ";
+ break;
+ }
+ default: break; // déjà vu au dessus
+ };
+ F_N_max = Dabs(intens_force); // sauvegarde
+
+ if (niveau_commentaire > 5)
+ {cout << " noeud: " << noeud->Num_noeud();
+ cout << "\n deltaX " << deltaX
+ <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+ <<"\n gap= " << gap << " N= " << N << " penalisation= " << penalisation
+ << " intensite force = " << intens_force << flush;
+ };
+//cout << "\n SM_K_charge_contact: penalisation= "<< penalisation << " gap= " << gap << " FN= " << F_N ;
+
+
+////debug
+// if (F_N_max > 80.)
+// {
+// cout << "\n debug : ElContact::SM_K_charge_contact(): noeud " << noeud->Num_noeud()
+// << " zone: " << num_zone_contact
+// << "\n force " << F_N << " force_limiter "< 6)
+ { cout << " noeud: " << noeud->Num_noeud()
+ << ": force collage non prise en compte " << force_contact
+ << " gap(positif)= " << gap << ", Normale= " << N;
+ cout << "\n deltaX " << deltaX
+ <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+ << " penalisation= " << penalisation
+ << " intensite force = " << intens_force ;
+ };
+ // on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
+ return el; // les résidu + raideur sont nul à ce niveau de la méthode
+ };
+ break;
+ case 4: case 5: case 6:
+ if (gap > Dabs(borne_regularisation))
+ // on est sortie de la zone d'accostage donc on neutralise le contact
+ { force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
+ if (niveau_commentaire >= 7)
+ { cout << " noeud: " << noeud->Num_noeud()
+ << ": force collage non prise en compte " << force_contact
+ << " gap(positif et > borne regularisation)= " << gap << ", Normale= " << N;
+ cout << "\n deltaX " << deltaX
+ <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
+ << " penalisation= " << penalisation
+ << " intensite force = " << intens_force ;
+ };
+ // on ne contribue pas aux réactions aux niveaux des noeuds
+ // car la valeur que l'on devrait ajoutée est nulle
+ return el; // les résidu + raideur sont nul à ce niveau de la méthode
+ };
+ break;
+ case 7: case 8:
+ // par rapport aux autres cas, on neutralise rien
+ break;
+ default :
+ cout << "\n *** cas pas pris en compte !! \n SM_K_charge_contact() " << endl;
+ Sortie(1);
+ };
+ };
+
+
+ // énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
+ energie_penalisation = 0.5 * F_N_max * gap; // la partie déplacement normal
+ // on initialise la partie frottement avec au moins la partie pénalisation, ensuite
+ // ce sera éventuellement abondé par le glissement ? ou la force de collage .... en devenir
+ energie_frottement.ChangeEnergieElastique(energie_penalisation);
+ // -- maintenant on regarde s'il faut s'occuper du frottement
+ Coordonnee F_T(dima);
+ Element * elemf = elfront->PtEI(); // récup de l'élément fini
+ CompFrotAbstraite* loiFrot = ((ElemMeca*) elemf)->LoiDeFrottement();
+ penalisation_tangentielle = 0.; // init
+ bool force_T_limiter = false; // init
+ if (loiFrot != NULL)
+ { // --- cas de l'existance d'une loi de frottement
+ // calcul du déplacement tangentiel: là il s'agit du déplacement relatif entre l'ancien point projeté et le nouveau
+
+ Coordonnee M_tatdt;
+ if (Mt.Dimension() != 0)
+ {M_tatdt = (Mtdt-Mt);} // déplacement total
+ ; // sinon Mt n'est pas encore définit donc on ne peut pas calculer le déplacement
+ // il est donc laissé à 0.
+ dep_tangentiel = M_tatdt- N * (M_tatdt*N); // on retire le deplacement normal éventuel
+ // calcul de la force tangentielle en supposant tout d'abord un contact collant
+ double penalisation_tangentielle;
+ if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
+ {penalisation_tangentielle = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle);}
+ else {penalisation_tangentielle = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
+// F_T =dep_tangentiel*(-ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact());
+ F_T =dep_tangentiel*(-penalisation_tangentielle);
+ // -- verification en appelant le comportement en frottement ----
+ // tout d'abord on récupère le delta t pour le calcul de la vitesse
+ double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
+ double unSurDeltat=0;
+ if (Abs(deltat) >= ConstMath::trespetit)
+ {unSurDeltat = 1./deltat;}
+ else
+ // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
+ { // non un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
+ if (unSurDeltat < 0)
+ { cout << "\n le pas de temps est négatif !! "
+ << "\n ElContact::SM_charge_contact(...";
+ };
+ unSurDeltat = ConstMath::tresgrand;
+ };
+ // calcul des vitesses
+ Coordonnee vit_T = dep_tangentiel * unSurDeltat;
+ // appel de la loi de comportement: calcul de la force de frottement et des énergies échangées
+ Coordonnee nevez_force_frot;EnergieMeca energie;
+ bool glisse = loiFrot->Cal_explicit_contact_tdt(vit_T,N,F_N,F_T,energie,deltat,nevez_force_frot);
+
+ // if (vit_T * nevez_force_frot > 0)
+ // cout << "\n bizarre puissance de frottement positive !";
+
+
+ if (glisse) // on remplace la force de frottement si ça glisse sinon on conserve F_T
+ F_T = nevez_force_frot;
+ // --- calcul des énergies échangées
+ energie_frottement += energie;
+ }
+ else if ( cas_collant)
+ { // --- cas d'un contact collant sans loi de frottement explicite
+ // calcul du déplacement tangentiel par rapport au premier point de contact
+ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ const Coordonnee & M_C0 = elfro.Metrique()->PointM_tdt // ( stockage a tdt)
+ (elfro.TabNoeud(),phi_theta_0);
+////---- debug ----
+//{const Coordonnee & M_a0 = elfro.Metrique()->PointM_0 // ( stockage a tdt)
+// (elfro.TabNoeud(),phi_theta_0);
+// cout << "\n debug smK contact: M_a0: ";M_a0.Affiche_1(cout);
+// cout << " a tdt: ";M_C0.Affiche_1(cout);
+//}
+////---- debug ---
+ Coordonnee M_0atdt = (Noe_atdt-M_C0); // déplacement total à partir du point d'impact initial
+ // transportée via l'interpolation: c-a-d les phi_theta_0 qui restent constant
+ dep_tangentiel = M_0atdt- N * (M_0atdt*N); // on retire le deplacement normal éventuel
+////---- debug ----
+//{ cout << "\n dep_tangentiel: ";dep_tangentiel.Affiche_1(cout);
+// cout << "\n Noe_atdt: "; Noe_atdt.Affiche_1(cout);
+//}
+////---- debug ---
+ double dep_T = dep_tangentiel.Norme();
+ // calcul de la pénalisation
+ double d_beta_dep_T=0.; // init de la dérivée du facteur de pénalisation / au déplacement
+ // pour l'instant ne sert pas
+ penalisation_tangentielle = CalFactPenalTangentiel(dep_T,d_beta_dep_T);
+ dep_T_tdt = dep_T; // sauvegarde
+ // calcul de la force tangentielle en supposant un contact collant
+ F_T = -dep_tangentiel * penalisation_tangentielle;
+ // limitation éventuelle de la force
+ double max_force_T_noeud;
+ if (fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi != NULL)
+ {max_force_T_noeud = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi));}
+ else {max_force_T_noeud = Dabs(ParaGlob::param->ParaAlgoControleActifs().Force_tangentielle_noeud_maxi());}
+ double n_F_T = Dabs(penalisation_tangentielle * dep_T);
+////---- debug ----
+//{ cout << "\n n_F_T= " << n_F_T ;
+// cout << " F_T: ";F_T.Affiche_1(cout);
+//}
+////---- debug ---
+ if ((n_F_T > max_force_T_noeud) && (max_force_T_noeud > ConstMath::petit))
+ {F_T *= max_force_T_noeud/n_F_T;
+ force_T_limiter = true;
+ // on recalcul la pénalisation associée
+ if (Dabs(dep_T) > ConstMath::trespetit)
+ {penalisation_tangentielle = max_force_T_noeud / dep_T;}
+ if (niveau_commentaire >= 6)
+ {cout << " ** limitation penalisation tangentielle= " << penalisation_tangentielle
+ << " intensite force = " << max_force_T_noeud << flush;};
+ };
+ F_T_max = F_T.Norme(); // sauvegarde
+////---- debug ----
+//{ cout << "\n F_T_max= " << n_F_T ;
+// cout << " F_T: ";F_T.Affiche_1(cout);
+//}
+////---- debug ---
+ // --- calcul des énergies échangées
+ // ici il s'agit d'une énergie élastique, que l'on ajoute à la pénalisation normale
+ // énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
+ energie_penalisation -= 0.5 * F_T * dep_tangentiel; // - pour que le résultat soit > 0
+ energie_frottement.ChangeEnergieElastique(energie_penalisation);
+ };
+ // --- calcul des puissances virtuelles
+ force_contact = F_T + F_N;
+ if (niveau_commentaire > 5)
+ { cout << " noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
+ if (force_limiter) cout << " force normale en limite " ;
+ if (force_T_limiter) cout << " force tangentielle en limite " ;
+ };
+ if (niveau_commentaire > 6)
+ cout << "\n ==> force contact imposee au residu (noeud:" << noeud->Num_noeud()
+ << " maillage:"<< noeud->Num_Mail() << ") " << force_contact;
+ int posi = Id_nom_ddl("R_X1") -1; // préparation pour les réactions
+ Ddl_enum_etendu& ddl_reaction_normale=Ddl_enum_etendu::Tab_FN_FT()(1);
+ Ddl_enum_etendu& ddl_reaction_tangentielle=Ddl_enum_etendu::Tab_FN_FT()(2);
+ // une petite manip pour le cas axisymétrique: dans ce cas les ddl à considérer pour le résidu et la raideur
+ // doivent être uniquement x et y donc 2 ddl au lieu de 3. (rien ne dépend de z)
+ int nb_ddl_en_var = dima; // init
+ bool axi = false;
+ if (ParaGlob::AxiSymetrie())
+ { nb_ddl_en_var -= 1; axi = true;};
+ // récup du kronecker qui va bien
+ TenseurHB& IdHB = *Id_dim_HB(ParaGlob::Dimension());
+ // a- cas du noeud projectile
+ int ism=1; // init cas normale
+ if ((cas_solide == 0 ) || (cas_solide == 1))
+ // cas où le noeud est libre
+ {for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++) // pour le noeud projectile la vitesse virtuelle associé est
+ {SM_res(ism) += force_contact(ix); // directement la vitesse du noeud
+// F_N = force_contact
+// = - N * intens_force = - N * (gap * penalisation)
+// = - N * ( (N * deltaX) * penalisation );
+// donc force_contact(ix) = - N(ix) * ( (N * deltaX) * penalisation )
+// et d_force_contact(ix) / d ddl_iy = - N(ix) * ( (N * d_deltaX_d_ddl_iy ) * penalisation )
+// + d(- N(ix))_d_ddl_iy * ( (N * deltaX) * penalisation )
+// + - N(ix) * ( (d_N_d_ddl_iy * deltaX) * penalisation )
+// + - N(ix) * ( (N * deltaX) * d_penalisation_d_ddl_iy )
+// avec d_penalisation_d_ddl_iy = d_penalisation_d_gap * d_gap_d_ddl_iy
+// et sachant que d_gap_d_ddl_iy = N(iy) pour le noeud central
+
+ // on abonde au niveau de la réaction au noeud
+ noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
+ // tout d'abord les termes strictement relatifs au noeud esclave
+ int jsm=1;
+ if ( cas_collant)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
+ { (*raideur)(ism,jsm) += penalisation * N(ix)*N(iy) // partie classique
+ //+ N(ix) * ( gap * d_beta_gap * N(iy) ) // partie intégrant la variation de la pénalisation
+ + penalisation_tangentielle *(IdHB(ix,iy) - N(ix)*N(iy)) // partie collant
+ ;
+ };
+ }
+ else // sans frottement
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
+ { (*raideur)(ism,jsm) += penalisation * N(ix)*N(iy) // partie classique
+ //+ N(ix) * ( gap * d_beta_gap * N(iy) )
+ ; // partie intégrant la variation de la pénalisation
+ };
+ };
+ //--- fin raideur : noeud esclave - noeud esclave
+
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ // --- ensuite les termes de couplage noeud esclave - noeuds de la facette
+ if (cas_solide == 0) // cas du bi_déformable, sinon pas de terme de couplage
+ {int iddl_facette = 1;
+ if (d_T_pt != NULL) // car même si on l'a demandé, il peut être null s'il n'existe pas (ex cas 1D )
+ {Tableau & d_T = *d_T_pt; // pour simplifier
+ if ( cas_collant)
+ {if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ + gap * d_T(iddl_facette)(ix)
+ + N(ix) * (d_T(iddl_facette) * deltaX)
+ )
+ + penalisation_tangentielle * phi_theta_0(jr)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
+ ;
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ }
+ else // sinon deltax est normal à la facette et d_N * deltaX = 0
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ + gap * d_T(iddl_facette)(ix)
+ )
+ + penalisation_tangentielle * phi_theta_0(jr)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
+ ;
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+ // if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ };
+ }
+ else // sinon pas collant avec (d_T_pt != NULL)
+ {if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ + gap * d_T(iddl_facette)(ix)
+ + N(ix) * (d_T(iddl_facette) * deltaX)
+ );
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ }
+ else // sinon deltax est normal à la facette et d_N * deltaX = 0
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ + gap * d_T(iddl_facette)(ix)
+ );
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ };
+ };
+ }
+ else // sinon cas d_T_pt == NULL et (cas_solide == 0)
+ {if ( cas_collant)
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy))
+ + penalisation_tangentielle * phi_theta_0(jr)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)); // partie collant
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ };
+ }
+ else // sinon cas non collant
+ {for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
+ { for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
+ (*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy));
+ // dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
+ // if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ };
+ }; // fin du if (cas_collant)
+ }; // fin cas d_T_pt == NULL et (cas_solide == 0)
+ }; // fin du if (cas_solide == 0)
+ }; // fin de la boucle ix sur le noeud esclave
+ } // fin de la première partie de: if ((cas_solide == 0 ) || (cas_solide == 1))
+ else // sinon c-a-d: cas_solide différent de 0 et 1 c-a-d le noeud est bloaqué
+ // on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
+ {for (int ix=1;ix<=dima;ix++) // pour le noeud projectile la vitesse virtuelle associé est
+ // on abonde au niveau de la réaction au noeud
+ noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
+ };
+ // dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
+// if (axi) ism++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+
+ // on abonde au niveau de la réaction normale et tangentielle pour le noeud esclave
+ noeud->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force;
+ double intensite_tangentielle = F_T.Norme();
+ noeud->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle;
+
+ // b- cas de la surface cible
+ if ((cas_solide == 0 ) || (cas_solide == 2))
+ // cas où la facette est libre
+// pour les noeud de la facette maître, sachant que l'on a pour la force sur le noeud esclave
+// F_N = - N * intens_force = - N * (gap * penalisation) = - N * ( (N * deltaX) * penalisation )
+// = force_contact
+// donc sur les noeuds "s" de la facette on a :
+// F_N^s = phi_s * N * ( (N * deltaX) * penalisation )
+// d'autre part on a gap = N * (X(t+dt)-M_impact) = N * (X(t+dt)- phi_r * X(tdt)^r)
+// avec X(tdt)^r les coordonnées du noeud r de la facette
+// d'où la forme finale pour le noeud "s" de la facette :
+// F_N^s = phi_s * N * ( (N * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
+// = - phi_s * force_contact
+//
+// maintenant au niveau des raideurs:
+// les raideurs relativements au noeud esclave -> dF_N^s/dX(t+dt)(iy)
+// dF_N^s/dX(t+dt)(iy) = phi_s * N * (N(iy)) * penalisation
+//
+// les raideurs relativements entre noeuds de la facette
+// dF_N^s/dX(t+dt)(iy) = phi_s * N * ( (N(iy) * (- phi_r ) * penalisation )
+// + phi_s * d_N/dX(t+dt)(iy) * ( (N * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
+// + phi_s * N * (d_N/dX(t+dt)(iy) * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
+
+
+// donc force_contact(ix) = - N(ix) * ( (N * deltaX) * penalisation )
+// et d_force_contact(ix) / d ddl_iy = - N(ix) * ( (N * d_deltaX_d_ddl_iy ) * penalisation )
+// + d(- N(ix))_d_ddl_iy * ( (N * deltaX) * penalisation )
+// + - N(ix) * ( (d_N_d_ddl_iy * deltaX) * penalisation )
+// + - N(ix) * ( (N * deltaX) * d_penalisation_d_ddl_iy )
+// avec d_penalisation_d_ddl_iy = d_penalisation_d_gap * d_gap_d_ddl_iy
+// et sachant que d_gap_d_ddl_iy = N(iy) pour le noeud central
+ {for (int is=1;is<=tab_taille-1;is++)
+ { Noeud* noe = tabNoeud(is+1); // pour simplifier
+ if (niveau_commentaire >= 7)
+ cout << "\n reaction facette imposee au residu (noeud:" << noe->Num_noeud()
+ << " maillage:"<< noe->Num_Mail() << ") " ;
+ tabForce_cont(is) = -force_contact*phii(is);
+ for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++)
+ { double force_imp = -force_contact(ix)*phii(is);
+ SM_res(ism) += force_imp;
+ if (niveau_commentaire > 6)
+ cout << force_imp << " ";
+ // on abonde au niveau de la réaction au noeud
+ noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
+ int jsm = 1;
+ // tout d'abord le terme de couplage
+ if (cas_solide == 0) // on intervient que si c'est déformable-déformable
+ { if ( cas_collant)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
+ { (*raideur)(ism,jsm)
+ += - phii(is)
+ * (penalisation * (N(ix)*N(iy))
+ + penalisation_tangentielle * (IdHB(ix,iy) - N(ix)*N(iy))
+ // partie collant
+ );
+ }
+ }
+ else // cas non collant
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
+ { (*raideur)(ism,jsm) += - phii(is) * penalisation * N(ix)*N(iy);}
+ }
+ };
+
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+
+ // puis les termes facette - facette
+ int iddl_facette = 1;
+ if (d_T_pt != NULL) // car même si on l'a demandé, il peut être null s'il n'existe pas (ex cas 1D )
+ {Tableau & d_T = *d_T_pt; // pour simplifier
+ if (cas_collant)
+ {if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm)
+ += - phii(is) * ( penalisation
+ *(N(ix) * ( - phii(js) * N(iy))
+ + d_T(iddl_facette)(ix) * gap
+ + N(ix) * (d_T(iddl_facette) * deltaX)
+ )
+ + penalisation_tangentielle * phi_theta_0(js)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
+ );
+
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ } //fin cas actif == 1
+ else // sinon: actif diff de 1, deltax est normal à la facette et d_N * deltaX = 0
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm)
+ += - phii(is) * ( penalisation
+ * (N(ix) * ( - phii(js) * N(iy))
+ + d_T(iddl_facette)(ix) * gap
+ )
+ + penalisation_tangentielle * phi_theta_0(js)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
+ );
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ }; // fin cas actif != 1
+ }
+ else // sinon cas non collant
+ {if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm) += - phii(is) * penalisation * (
+ N(ix) * ( - phii(js) * N(iy))
+ + d_T(iddl_facette)(ix) * gap
+ + N(ix) * (d_T(iddl_facette) * deltaX)
+ );
+
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ } //fin cas actif == 1
+ else // sinon: actif diff de 1, deltax est normal à la facette et d_N * deltaX = 0
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm) += - phii(is) * penalisation * (
+ N(ix) * ( - phii(js) * N(iy))
+ + d_T(iddl_facette)(ix) * gap
+ );
+
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ }
+ }; // fin cas actif != 1
+ }; // fin du if then else sur : if (cas_collant)
+
+ } // fin du cas if (d_T_pt != NULL)
+ else
+ {if (cas_collant)
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm)
+ += - phii(is) * ( penalisation
+ * (N(ix) * ( - phii(js) * N(iy)))
+ + penalisation_tangentielle * phi_theta_0(js)
+ *(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
+ );
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ };
+ }
+ else // sinon cas non collant
+ {for (int js=1;js<=tab_taille-1;js++)
+ {for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
+ (*raideur)(ism,jsm) += - phii(is) * penalisation * (
+ N(ix) * ( - phii(js) * N(iy))
+ );
+ // dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
+// if (axi) jsm++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+
+ };
+ };
+ }; // fin du cas où d_T_pt == NULL
+ };
+ // dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
+// if (axi) ism++; // qui n'est pas pris en compte
+// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
+// du coup on ne décale plus
+ // on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
+ noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(is);
+ noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(is);
+ };
+ }
+ else // *** modif 23 juin 2015 , a virer si c'est ok
+ // on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
+ {for (int ir=1;ir<=tab_taille-1;ir++)
+ { Noeud* noe = tabNoeud(ir+1); // pour simplifier
+ tabForce_cont(ir) = -force_contact*phii(ir);
+ for (int ix=1;ix<=dima;ix++)
+ { double force_imp = -force_contact(ix)*phii(ir);
+ // on abonde au niveau de la réaction au noeud
+ noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
+ };
+ // on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
+ noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
+ noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
+ };
+ };
+ // retour
+// return residu; // SM est nul à ce niveau du programme
+//// --- debug
+//cout << "\n debug : ElContact::SM_K_charge_contact() ";
+//SM_res.Affiche();
+//raideur->Affiche();
+//// --- fin debug
+
+ return el;
+ };
+
+ //================================= methodes privées ===========================
+
+// calcul la normale en fonction de differente conditions
+Coordonnee ElContact::Calcul_Normale(int dim, Plan & pl, Droite & dr,int indic)
+ {
+ Coordonnee N(dim); // le vecteur normal initialisé à 0
+ if ( (dim == 3) && (indic == 2))
+ // cas 3d avec une surface
+ { N = pl.Vecplan();
+ return N;
+ }
+
+ else if ( ((dim == 2) && (indic == 1))
+ || (ParaGlob::AxiSymetrie() && (dim == 3) && (indic == 1))
+ )
+ // cas 2D avec une ligne, (ou 3D bloqué avec une ligne ??)
+ // ou 3D axisymétrique avec une ligne
+
+// else if((dim == 2) && (indic == 1))
+// // cas 2D ou 3D bloqué avec une ligne
+ { Coordonnee V = dr.VecDroite(); // le vecteur tangent
+ // ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
+ // car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
+ // donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
+ N(1) = V(2); N(2) = -V(1);
+ }
+
+ else if ( (dim == 3) && (indic == 1))
+ // cas 3d avec une ligne, on va considérer que la normale est la normale dans la direction
+ // du noeud esclave (si celui-ci est suffisemment externe à la ligne
+ { Coordonnee V = dr.VecDroite(); // On récupère le vecteur tangent à la ligne
+ Coordonnee A = noeud->Coord2() - tabNoeud(2)->Coord2(); // on construit un vecteur entre le premier point de ligne -> le noeud esclave
+ Coordonnee B = Util:: ProdVec_coor(V,A); // produit vectoriel
+ // on ne continue que si ce produit vectoriel n'est pas nul
+ if (B.Norme() > ConstMath::petit)
+ { N = Util:: ProdVec_coor(V,B);}
+ else // sinon cela veut dire que le noeud est sur la ligne, dans ce cas particulier, d'une manière arbitraire
+ // on prend la normale dans un des 3 plans de base, en commençant par le plan xy qui serait celui où par exemple
+ // on travaille en 3D, mais avec le z bloqué
+ { // on commence par voir si c'est possible en xy
+ if (DabsMaX(V(1),V(2)) > ConstMath::petit)
+ // là c'est ok la ligne n'est pas // à z
+ // ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
+ // car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
+ // donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
+ { N(1) = V(2); N(2) = -V(1);
+ N(3)=0.; // on pose z=0 d'où une normale dans le plan xy
+ }
+ else // sinon cela veut dire que l'on est suivant l'axe de z, on choisit x par défaut
+ { N(1)=1; N(2)=N(3)=0.;};
+ };
+ }
+ else if ( (dim == 1) && (indic == 0))
+ // cas 1D avec un point
+ { // la normale sortante de l'élément c'est soit 1 ou -1
+ // pour le déterminer on commence par trouver le coté de l'élément frontière qui va rentrer en contact
+ // on est obligé de considérer l'élément
+ // pour cela on cherche le noeud de l'élément qui correspond au noeud frontière
+ // qui normalement est le second noeud du global des noeuds de l'élément de contact
+ Noeud * no_front= tabNoeud(2); int num_no_front = no_front->Num_noeud();
+ const Tableau < Noeud * > t_N_elem = elfront->PtEI()->Tab_noeud_const();
+ int nbN_elem = t_N_elem.Taille(); int num_N=0;
+ for (int i=1;i<= nbN_elem;i++)
+ if (t_N_elem(i)->Num_noeud() == num_no_front)
+ {num_N = i;break;};
+ if (num_N == 0)
+ { cout << "\n *** warning on n'a pas trouve de frontiere correct pour le calcul de la normale "
+ << "\n cas du contact entre deux points ... le contact sera mal calcule " << endl;
+ };
+ // maintenant on prend au autre noeud de l'élément et on regarde le sens
+ for (int i=1;i<= nbN_elem;i++)
+ if (i != num_N)
+ {// il s'agit bien d'un autre noeud
+ if (t_N_elem(i)->Coord2()(1) > no_front->Coord2()(1) )
+ {N(1) = -1.;}
+ else {N(1) = 1.;}
+ break;
+ };
+ }
+ else
+ // autres cas non traite pour l'instant
+ { cout << "\n erreur, desole mais le cas de contact en dimension = " << dim
+ << ", avec ";
+ if (indic == 1)
+ cout << " une droite ";
+ else
+ cout << " un plan ";
+ cout << " n\'est pas actuellement traite "
+ << "ElContact::Normal(int dim, Plan & pl, Droite & dr, indic)" << endl;
+ Sortie(1);
+ };
+ return N;
+ };
+
+// récupération d'informations des classes internes
+// N: le vecteur normal
+// M_impact: le point d'impact sur la surface (ou ligne ou point)
+// 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 * ElContact::RecupInfo(Coordonnee& N,Coordonnee& M_impact,Vecteur& phii,bool avec_var)
+ { ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
+ // recup de la dimension
+ int dim = noeud->Dimension();
+ // recup du dernier plan tangent (ou droite)
+ // dimensionnement des variables de tangence
+ Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
+ Tableau * d_T = elfro.DernierTangent(dr,pl,indic,avec_var);
+ // different cas
+ N.Change_dim(dim); // le vecteur normal
+ if (ParaGlob::AxiSymetrie() && (dim == 3))
+ N(3) = 0.; // init pour le cas axi
+ if ( (dim == 3) && (indic == 2))
+ // cas 3d avec une surface
+ { N = pl.Vecplan();
+ M_impact = pl.PointPlan();
+ }
+ else if ( ((dim == 2) && (indic == 1))
+ || (ParaGlob::AxiSymetrie() && (dim == 3) && (indic == 1))
+ )
+ // cas 2D avec une ligne
+ // ou 3D axisymétrique avec une ligne
+ { Coordonnee V = dr.VecDroite(); // le vecteur tangent
+// N(1) = -V(2); N(2) = V(1); // un vecteur normal
+// !!!! pour l'instant il y a une erreur de numérotation: on utilise en fait une numérotation
+// exactement inverse de la doc !!!
+ N(1) = V(2); N(2) = -V(1); // un vecteur normal
+ // en axi N(3) est déjà initialisé à 0
+ M_impact = dr.PointDroite();
+ }
+ else if ( (dim == 3) && (indic == 1))
+ // cas 3d avec une ligne, on va considérer que la normale est la normale dans la direction
+// **** a revoir car c'est problématique quand le noeud esclave est très proche de la ligne
+// du coup on peut avoir une normale qui oscille d'un coté à l'autre de la ligne ce qui fait que l'on va
+// avoir ensuite une force de contact ou de collage !!! aléatoire !!! pas bon du tout
+// sans doute trouver autre chose : peut-être que c'est ok quand le point est franchement hors de la ligne
+// pas pas autrement
+ // du noeud esclave (si celui-ci est suffisemment externe à la ligne
+ { Coordonnee V = dr.VecDroite(); // On récupère le vecteur tangent à la ligne
+ Coordonnee A = noeud->Coord2() - tabNoeud(2)->Coord2(); // on construit un vecteur entre le premier point de ligne -> le noeud esclave
+ Coordonnee B = Util:: ProdVec_coor(V,A); // produit vectoriel
+ // on ne continue que si ce produit vectoriel n'est pas nul
+ if (B.Norme() > ConstMath::petit)
+ { N = Util:: ProdVec_coor(V,B).Normer();}
+ else // sinon cela veut dire que le noeud est sur la ligne, dans ce cas particulier, d'une manière arbitraire
+ // on prend la normale dans un des 3 plans de base, en commençant par le plan xy qui serait celui où par exemple
+ // on travaille en 3D, mais avec le z bloqué
+ { // on commence par voir si c'est possible en xy
+ if (DabsMaX(V(1),V(2)) > ConstMath::petit)
+ // là c'est ok la ligne n'est pas // à z
+ // ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
+ // car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
+ // donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
+ { N(1) = V(2); N(2) = -V(1);
+ N(3)=0.; // on pose z=0 d'où une normale dans le plan xy
+ }
+ else // sinon cela veut dire que l'on est suivant l'axe de z, on choisit x par défaut
+ { N(1)=1; N(2)=N(3)=0.;};
+ };
+ M_impact = dr.PointDroite();
+ }
+// else if ( (dim == 2) && (indic == 1))
+// // cas 2D avec une ligne
+// { Coordonnee V = dr.VecDroite(); // le vecteur tangent
+//// N(1) = -V(2); N(2) = V(1); // un vecteur normal
+//// !!!! pour l'instant il y a une erreur de numérotation: on utilise en fait une numérotation
+//// exactement inverse de la doc !!!
+// N(1) = V(2); N(2) = -V(1); // un vecteur normal
+// M_impact = dr.PointDroite();
+// }
+ else if ( (dim == 1) && (indic == 0))
+ // cas 1D avec un point
+ { // la normale sortante de l'élément c'est soit 1 ou -1
+ // pour le déterminer on commence par trouver le coté de l'élément frontière qui va rentrer en contact
+ // on est obligé de considérer l'élément
+ // pour cela on cherche le noeud de l'élément qui correspond au noeud frontière
+ // qui normalement est le second noeud du global des noeuds de l'élément de contact
+ Noeud * no_front= tabNoeud(2); int num_no_front = no_front->Num_noeud();
+ const Tableau < Noeud * > t_N_elem = elfront->PtEI()->Tab_noeud_const();
+ int nbN_elem = t_N_elem.Taille(); int num_N=0;
+ for (int i=1;i<= nbN_elem;i++)
+ if (t_N_elem(i)->Num_noeud() == num_no_front)
+ {num_N = i;break;};
+ if (num_N == 0)
+ { cout << "\n *** warning on n'a pas trouve de frontiere correct pour le calcul de la normale "
+ << "\n cas du contact entre deux points ... le contact sera mal calcule " << endl;
+ };
+ // maintenant on prend au autre noeud de l'élément et on regarde le sens
+ for (int i=1;i<= nbN_elem;i++)
+ if (i != num_N)
+ {// il s'agit bien d'un autre noeud
+ if (t_N_elem(i)->Coord2()(1) > no_front->Coord2()(1) )
+ {N(1) = -1.;}
+ else {N(1) = 1.;}
+ break;
+ };
+// non erreur !! M_impact = N; // sera modifié ensuite, la valeur n'a pas d'importance
+ // a priori le point d'impact c'est le noeud frontière
+ M_impact = no_front->Coord2();
+ }
+ else if ( (dim == 1) && (indic == 1))
+ // cas 1D avec une droite
+ { N(1) = 1.; // le vecteur normal, qui correspond au seul vecteur disponible
+ M_impact = dr.PointDroite();;
+ }
+ else
+ // autres cas non traite pour l'instant
+ { cout << "\n erreur, desole mais le cas de contact en dimension = " << dim
+ << ", avec ";
+ if (indic == 1)
+ cout << " une droite ";
+ else
+ cout << " un plan ";
+ cout << " n\'est pas actuellement traite " << "ElContact::RecupInfo(.."<< endl;
+ Sortie(1);
+ };
+ // récup des fonctions phi
+ phii = elfro.Phi();
+ // retour
+ return d_T;
+ };
+
+ // mise à jour de cas_solide et donc de ddlElement en fonction de l'activité des ddl
+void ElContact::Mise_a_jour_ddlelement_cas_solide_assemblage()
+{cas_solide = 0; // init par défaut: déformable-déformable
+ // on regarde l'activité des noeuds
+ // 1-- cas du noeud esclave
+ int dim = ParaGlob::Dimension();
+ bool esclave_solide = true;
+ switch (dim)
+ {case 3: esclave_solide = noeud->Ddl_fixe(X3) && esclave_solide ;
+ case 2: esclave_solide = noeud->Ddl_fixe(X2) && esclave_solide ;
+ case 1: esclave_solide = noeud->Ddl_fixe(X1) && esclave_solide ;
+ };
+
+ // 2-- la frontière
+ int tal = tabNoeud.Taille();
+ bool front_solide = true;
+ for (int i=2;i<=tal;i++)
+ { Noeud* noe = tabNoeud(i);
+ switch (dim)
+ {case 3: front_solide = noe->Ddl_fixe(X3) && front_solide ;
+ case 2: front_solide = noe->Ddl_fixe(X2) && front_solide ;
+ case 1: front_solide = noe->Ddl_fixe(X1) && front_solide ;
+ };
+ };
+
+ // maintenant on traite les différents cas
+ int dim_ddlelement = 0;
+ if (esclave_solide && front_solide)
+ {cas_solide = 3;dim_ddlelement=0;}
+ else if (esclave_solide) {cas_solide = 2;dim_ddlelement=tal-1;}
+ else if (front_solide) {cas_solide = 1;dim_ddlelement=1;}
+ else {cas_solide = 0;dim_ddlelement=tal;};
+
+ // maintenant on dimensionne ddlElement éventuellement
+ if (ddlElement_assemblage->NbNoeud() != dim_ddlelement)
+ // il faut redimensionner
+ {
+ // en fait tous les éléments du tableau sont identiques et il suffit qu'ils existent
+ // on commence par parcourir la liste pour trouver un bon candidat
+ list ::iterator ili,ilifin=list_Ddl_global.end();
+ bool trouve = false;
+ for (ili=list_Ddl_global.begin();ili !=ilifin; ili++)
+ if ((*ili).NbNoeud() == dim_ddlelement) // on a trouvé un candidat
+ {ddlElement_assemblage = &(*ili); trouve = true;};
+ // dans le cas où on n'a pas trouvé, on en cré un
+ if (!trouve)
+ { int dima = ParaGlob::Dimension();
+ // dans le cas où on est en axisymétrie il faut diminuer de 1
+ if (ParaGlob::AxiSymetrie())
+ dima--;
+ DdlElement tab_ddl(dim_ddlelement,dima);
+ int posi = Id_nom_ddl("X1") -1;
+ for (int i =1; i<= dima; i++)
+ for (int j=1; j<= dim_ddlelement; j++)
+ tab_ddl.Change_Enum(j,i,Enum_ddl(i+posi));
+ list_Ddl_global.push_front(tab_ddl);
+ ddlElement_assemblage = &(*list_Ddl_global.begin());
+ };
+
+ // ensuite il faut s'occuper du tableau d'assemblage tabNoeud_pour_assemblage.Change_taille(0);
+ switch (cas_solide)
+ {case 0: tabNoeud_pour_assemblage = tabNoeud; // c'est le cas le plus complet
+ break;
+ case 1: tabNoeud_pour_assemblage.Change_taille(1); // seulement le noeud libre
+ tabNoeud_pour_assemblage(1)=noeud;
+ break;
+ case 2: tabNoeud_pour_assemblage.Change_taille(tal-1); // la facette seule est libre
+ for (int i=2;i<=tal;i++)
+ tabNoeud_pour_assemblage(i-1) = tabNoeud(i);
+ break;
+ case 3: tabNoeud_pour_assemblage.Change_taille(0); // tout est bloqué
+ break;
+ };
+ };
+};
+
+
+ // récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
+void ElContact::RecupPlaceResidu(int nbddl)
+ { // tout d'abord on vérifie que la place actuelle ne convient pas
+ if (residu != NULL)
+ {if (residu->Taille() == nbddl)
+ {residu->Zero(); return; } // cas courant
+ };
+ // dans tous les autres cas il faut soit récupérer une place qui convient soit en créé une autre
+ // on commence par parcourir la liste pour trouver un bon candidat
+ list ::iterator ilv,ilvfin=list_SM.end();
+ bool trouve = false;
+ for (ilv=list_SM.begin();ilv !=ilvfin; ilv++)
+ if ((*ilv).Taille() == nbddl) // on a trouvé un candidat
+ {residu = &(*ilv); residu->Zero();trouve = true;};
+ // dans le cas où on n'a pas trouvé, on en cré un
+ if (!trouve)
+ { Vecteur interv(nbddl,0.); // vecteur mis à 0 par défaut
+ list_SM.push_front(interv);
+ residu = &(*list_SM.begin());
+ };
+ };
+
+ // récup d'une place pour la raideur locale et mise à jour de list_raideur éventuellement
+void ElContact::RecupPlaceRaideur(int nbddl)
+ { // tout d'abord on vérifie que la place actuelle ne convient pas
+ if (raideur != NULL)
+ {if (raideur->Nb_ligne() == nbddl)
+ {raideur->Initialise(0.); return; } // cas courant
+ };
+ // dans tous les autres cas il faut soit récupérer une place qui convient soit en créé une autre
+ // on commence par parcourir la liste pour trouver un bon candidat
+ list ::iterator ilv,ilvfin=list_raideur.end();
+ bool trouve = false;
+ for (ilv=list_raideur.begin();ilv !=ilvfin; ilv++)
+ if ((*ilv).Nb_ligne() == nbddl) // on a trouvé un candidat
+ {raideur = &(*ilv); raideur->Initialise(0.);trouve = true;};
+ // dans le cas où on n'a pas trouvé, on en cré un
+ if (!trouve)
+ { Mat_pleine interv(nbddl,nbddl,0.); // init à 0 par défaut
+ list_raideur.push_front(interv);
+ raideur = &(*list_raideur.begin());
+ };
+ };
+
+// 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
+// sauvegarde du gap
+// é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 ElContact::CalFactPenal(const double& gap,double & d_beta_gap,int contact_type)
+{ // récup du facteur donné par l'utilisateur
+ double fact_penal=0.; // init par défaut
+ if (fct_nD_contact.fct_nD_penalisationPenetration != NULL)
+ {fact_penal = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationPenetration);}
+ else {fact_penal = ParaGlob::param->ParaAlgoControleActifs().PenalisationPenetrationContact();}
+ double facteur=1.; // un facteur
+ // choix en fonction du type de calcul
+ int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
+
+ // --- premier choix en fonction de typ_cal ---
+ if (typ_cal != 0)
+ {if (contact_type != 41)
+ {switch (typ_cal)
+ { case 1: // cas le plus simple : pas de calcul particulier
+ break; // on ne fait rien
+ case 2: case 3: case 4: case 5: case 6: case 7: case 8:// calcul du type ls-dyna avec la compressibilité du maître
+ { // on choisit en fonction de la géométrie si il existe une compressibilité
+ ElFrontiere* elfrontiere = elfront->Eleme(); // pour simplifier l'écriture
+ const Element * elem = elfront->PtEI(); // idem
+ if (((const ElemMeca*) elem)->CompressibiliteMoyenne() > 0.)
+ { switch (elfrontiere->Type_geom_front())
+ { case SURFACE:
+ if (elem->ElementGeometrie(X1).Dimension()==3)
+ { // cas d'une surface frontière d'un volume
+ double surf = elfrontiere->SurfaceApprox();
+ double volume = elem->Volume();
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenal()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==2)
+ { // cas d'une surface frontière d'un élément coque ou plaque
+ double surf = elfrontiere->SurfaceApprox();
+ double maxdiag = elfrontiere->MaxDiagonale_tdt();
+ if (maxdiag <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, la surface de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenal()";
+ facteur = maxdiag;
+ }
+ else // sinon c'est bon
+ {facteur = surf/maxdiag;}
+ };
+ break;
+ // pour mémoire pour la suite POINT_G = 1 , LIGNE , SURFACE, VOLUME, RIEN_TYPE_GEOM
+
+ //******** partie en construction
+
+ case LIGNE:
+ if (ParaGlob::AxiSymetrie())
+ // cas où l'on est en axisymétrique,
+ { // on regarde la dimension de l'élément associé
+ if (elem->ElementGeometrie(X1).Dimension()==2)
+ // élément 2D en axi donc 3D en réalité
+ { // récup de la longueur de la frontière
+ double longueur = elfrontiere->LongueurApprox();
+ // on calcul la surface associée
+ // M_impact(1) = x donc = le rayon car on est axi autour de y
+ //// double surf = longueur * M_impact(1) * ConstMath::Pi * 2.;
+ // 9 nov 2016: je crois qu'ici il y a une incompréhension. en fait il s'agit de la surface du maître
+ // donc il ne faut pas tenir compte du point d'impact ?? sinon par exemple si le point est au centre
+ // M_impact(1) = 0 et on n'a pas de surf !!
+ // mais plus généralement, le pt d'impact ne doit pas interférer à mon avis
+ double surf = longueur * ConstMath::Pi * 2.;
+ // on récupère la surface de l'élément qui a créé la frontière
+ double volume = elem->Volume();
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenal()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else // sinon ce n'est pas pris en charge
+ {cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << " contact sur une ligne axisyme trique"
+ << " \n ElContact::CalFactPenal() ";
+ Sortie(1);
+ };
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==3)
+ // cas d'une ligne frontière d'un élément coque ou plaque
+ {
+ // il faut finir la fonction ElFrontiere::LongueurApprox()
+ // cf le laïus qui est écrit dans la méthode
+
+
+ double surf = elfrontiere->SurfaceApprox();
+ double volume = elem->Volume();
+
+ // virtual double EpaisseurMoyenne(Enum_dure )
+
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenal()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==2)
+ // cas d'une ligne frontière d'une plaque
+ { double longueur = elfrontiere->LongueurApprox();
+ double epais = 0.; // init
+ if (!ParaGlob::AxiSymetrie()) // si on n'est pas en axi
+ {epais = ((ElemMeca*) elem)->EpaisseurMoyenne(TEMPS_tdt );}
+ else // si on est en axi
+ {epais = 1.;};
+ double surf = elem->Volume() / epais;
+ facteur = surf/longueur;
+ };
+ break;
+
+ //******** fin partie en construction
+ case POINT_G:
+ // on ne considère que le cas d'une dimension 1D non axi, qui est un cas d'école
+ // pour les autres cas, on considère que l'on ne doit pas prendre en compte des frontières
+ // de type point, du coup on génèrera une erreur
+ if (ParaGlob::Dimension() == 1 )
+ {// on veut calculer Ke * Ae * Ae / vol , comme on est dans le cas d'une barre
+ // vol = long * section, et Ae = section , du coup:
+ // Ke * Ae * Ae / vol = Ke * vol / (long * long) avec long = la longueur de l'élément
+ double longueur = elem->LongueurGeometrique(1);
+ double volume = elem->Volume();
+ facteur = volume / (longueur * longueur);
+ }
+ else
+ {cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << "\n contact en dimension " << ParaGlob::Dimension()
+ << " \n ElContact::CalFactPenal() ";
+ Sortie(1);
+ };
+ break;
+
+ default:
+ cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << " \n ElContact::CalFactPenal() ";
+ Sortie(1);
+ };
+ // on tiens compte maintenant de la compressibilité (moyenne) de l'élément
+ facteur *= ((const ElemMeca*) elem)->CompressibiliteMoyenne();
+ }// fin du test d'existance d'une compressibilité
+ else
+ // on n'interdit pas car on pourrait avoir plusieurs maîtres, certains bien définit et
+ // d'autres sans comportement donc sans compressibilité:
+ {if (niveau_commentaire >5)
+ cout << "\n contact: *** attention le module de compressibilite n'est (encore?) pas defini "
+ << " on n'en tient pas compte (pour l'instant) pour le calcul du facteur de penalite normal ! ";
+ };
+ break;
+ }
+ default:
+ cout << "\n **** erreur cas de calcul du facteur de penalisation en penetration non existant "
+ << " typ_cal= " << typ_cal
+ << "\n ElContact::CalFactPenal()";
+ Sortie(1);
+ };
+ // --- deuxième choix en fonction de typ_cal ---
+ // on calcul la valeur final du facteur
+ switch (typ_cal)
+ { case 1: case 2:
+ { fact_penal *= facteur;d_beta_gap = 0.;
+ if (niveau_commentaire >= 5)
+ cout << "\n fact_penal= " << fact_penal ;
+ break;
+ }
+ case 3: // on fait varier le coef de pénalisation en fonction de l'enfoncement
+ { if ((gap < gap_t) && (gap < 0.)) // la première fois gap_t = 0. donc on a forcément nb_pene_tdt >= 1 après le test
+ { nb_pene_tdt++;}
+ else if ((gap > gap_t ) && (gap < 0.)) // on diminue que si gap diminue,
+ { if (nb_pene_tdt > 1) // on limite à 1 pour le calcul correcte de la puissance
+ { nb_pene_tdt--;
+ // cout << "\n ************* on diminue np_pene_tdt *************** ";
+ };
+ };
+ // l'évolution du facteur prend en compte le nombre de fois où la pénétration augmente
+ // 2**10 = 10^2, 2**100 = 10^30 !!
+ const double a = 1.2; const double b=2.;
+ fact_penal *= pow(a,nb_pene_tdt*b); //PUISSN(2.,nb_pene_tdt); // on modifie en conséquence le facteur
+ d_beta_gap = 0.; // a priori on n'a pas vraiment de dérivée calculable ...
+ if (niveau_commentaire >= 5)
+ cout << "\n fact_penal= " << fact_penal << " nb_pene_tdt= "
+ << nb_pene_tdt << " pow("<ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ double max_pene;
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
+ {max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi);}
+ else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
+ // on calcul un facteur de majoration en fonction de la pénétration du pas précédent
+ // double mult_pene = MaX(1., -gap_t/max_pene);
+ double mult_pene = MaX(1., (-gap_t/max_pene)*mult_pene_t); // il faut appliquer au facteur précédent !
+ mult_pene_tdt = 0.5*(mult_pene_t + mult_pene); // on fait une moyenne glissante de 2
+ //////debug
+ //if (mult_pene_tdt == 1)
+ // {cout << "\n debug ElContact::CalFactPenal() temps " << ParaGlob::Variables_de_temps().TempsCourant();
+ // };
+ ////fin debug
+ if (niveau_commentaire > 5)
+ cout << "\n mult_pene_tdt= " << mult_pene_tdt ;
+ // on calcul un facteur en fonction de la distance: thèse dominique chamoret, page 94 formule (3.3)
+ if (gap <= (-borne_regularisation))
+ { fact_penal *= facteur*mult_pene_tdt;d_beta_gap = 0.;}
+ else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
+ // { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
+ { fact_penal *= facteur *mult_pene_tdt * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
+ d_beta_gap = facteur *mult_pene_tdt * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ }
+ else
+ { fact_penal = 0;d_beta_gap = 0.;};
+ break;
+ }
+ case 5:case 7: // on fait varier le coef de pénalisation lorsque l'enfoncement est plus petit qu'un maxi
+ { // ON récupe la pénétration maxi
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ // on calcul un facteur en fonction de la distance: thèse dominique chamoret, page 94 formule (3.3)
+ if (gap <= (-borne_regularisation))
+ {fact_penal *= facteur;d_beta_gap = 0.;}
+ else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
+ // { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
+ { fact_penal *= facteur * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
+ d_beta_gap = facteur * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ }
+ else
+ { fact_penal = 0;d_beta_gap = 0.;};
+ break;
+ }
+ case 6: // idem cas 5 mais avec une fonction différente
+ { // on récupère la pénétration maxi
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation));}
+ else {borne_regularisation = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation());}
+ // on calcul un facteur en fonction de la distance: = (0.5*(tanh(4.*gap/borne)-1.))
+ // 0.25*exp(-gap/(0.25*borne))
+ if (gap <= (-borne_regularisation))
+ {fact_penal *= facteur;d_beta_gap = 0.;}
+ else if (Dabs(gap) < borne_regularisation)
+ { fact_penal *= -facteur * 0.5 * (tanh(gap*4./borne_regularisation)-1.); // formule du même type
+ d_beta_gap = 4.*(1.-fact_penal*fact_penal)/borne_regularisation; //
+ }
+ else
+ { fact_penal = 0;d_beta_gap = 0.;};
+ break;
+ }
+ case 8: // idem 4 mais pour un contact collant: quelque soit le sens de gap
+ // on fait varier le coef de pénalisation lorsque l'enfoncement est plus petit qu'un maxi
+ {
+ // //------ essai à virer
+ // fact_penal *= facteur;d_beta_gap = 0.;
+ // if (niveau_commentaire >= 5)
+ // cout << "\n fact_penal= " << fact_penal ;
+ // break;
+ // //------ fin essai
+
+ // ON récupe la pénétration maxi
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ double max_pene;
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
+ {max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi);}
+ else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
+ // on calcul un facteur de majoration en fonction de la pénétration du pas précédent
+ // double mult_pene = MaX(1., -gap_t/max_pene);
+ double mult_pene = MaX(1., (Dabs(gap_t)/max_pene)*mult_pene_t); // il faut appliquer au facteur précédent !
+ mult_pene_tdt = 0.5*(mult_pene_t + mult_pene); // on fait une moyenne glissante de 2
+ //////debug
+ //if (mult_pene_tdt == 1)
+ // {cout << "\n debug ElContact::CalFactPenal() temps " << ParaGlob::Variables_de_temps().TempsCourant();
+ // };
+ ////fin debug
+ if (niveau_commentaire > 5)
+ cout << "\n mult_pene_tdt= " << mult_pene_tdt ;
+ // on calcul un facteur en fonction de la distance: thèse dominique chamoret, page 94 formule (3.3)
+ if (Dabs(gap) > borne_regularisation)
+ { fact_penal *= facteur*mult_pene_tdt;d_beta_gap = 0.;}
+ else // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
+ // { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
+ { fact_penal *= facteur *mult_pene_tdt * Sqr((-Dabs(gap)-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
+ d_beta_gap = facteur *mult_pene_tdt * (-Dabs(gap)-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ }
+ break;
+ }
+
+ default:
+ cout << "\n **** erreur 2 cas de calcul du facteur de penalisation en penetration non existant "
+ << " typ_cal= " << typ_cal
+ << "\n ElContact::CalFactPenal()";
+ Sortie(1);
+ };
+ }
+ else if (contact_type == 41)// si == 41, on utilise une mise à jour de la pénalisation
+ { // la méthode est analogue au cas: typ_cal == 4
+ // ON récupe la pénétration maxi
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation();}
+ double max_pene;
+ if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
+ {max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi);}
+ else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
+ // on calcul un facteur de majoration en fonction de la pénétration du pas précédent
+ double mult_pene = MaX(1., (-gap_t/max_pene)); // il faut appliquer au facteur précédent !
+ if (niveau_commentaire > 5)
+ cout << "\n mult_pene_tdt= " << mult_pene ;
+ // on calcul un facteur en fonction de la distance:
+ // if (gap <= (-borne_regularisation))
+ { fact_penal *= penalisation * mult_pene;d_beta_gap = 0.;}
+ // else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
+ // { fact_penal *= penalisation * mult_pene * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
+ // d_beta_gap = penalisation * mult_pene * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ // }
+ // else // sinon on annule tout
+ // { fact_penal = 0;d_beta_gap = 0.;};
+ }
+ else if (contact_type == 42)// si == 41, on utilise une mise à jour de la pénalisation
+ {
+
+ };
+ };
+
+ // retour
+ return fact_penal;
+};
+
+
+// calcul du facteur de pénalisation en tangentiel, en fonction de la géométrie
+// du module de compressibilité et des différents possibles
+// sauvegarde du dep_T = déplacement tangentiel
+// éventuellement, calcul de la dérivée: d_beta_dep_Tdu, du facteur par rapport au dep_T
+// la sensibilité dépend du type de calcul du facteur de pénalisation
+// suis la même logique que pour la pénétration
+double ElContact::CalFactPenalTangentiel(const double& dep_T,double & d_beta_dep_T)
+{ // récup du facteur donné par l'utilisateur
+ double fact_penal = 0.; // init par défaut
+ if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
+ {fact_penal = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle);}
+ else {fact_penal = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
+ double facteur=1.; // un facteur
+ // choix en fonction du type de calcul
+ int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationTangentielle();
+ // --- premier choix en fonction de typ_cal ---
+ if (typ_cal != 0)
+ {switch (typ_cal)
+ { case 1: // cas le plus simple : pas de calcul particulier
+ break; // on ne fait rien
+ case 2: case 3: case 4: case 5: case 6: case 7: case 8:// calcul du type ls-dyna avec la compressibilité du maître
+ { // on choisit en fonction de la géométrie
+ ElFrontiere* elfrontiere = elfront->Eleme(); // pour simplifier l'écriture
+ const Element * elem = elfront->PtEI(); // idem
+ if (((const ElemMeca*) elem)->CompressibiliteMoyenne() > 0.)
+ { switch (elfrontiere->Type_geom_front())
+ { case SURFACE:
+ if (elem->ElementGeometrie(X1).Dimension()==3)
+ { // cas d'une surface frontière d'un volume
+ double surf = elfrontiere->SurfaceApprox();
+ double volume = elem->Volume();
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenalTangentiel()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==2)
+ { // cas d'une surface frontière d'un élément coque ou plaque
+ double surf = elfrontiere->SurfaceApprox();
+ double maxdiag = elfrontiere->MaxDiagonale_tdt();
+ if (maxdiag <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, la surface de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenalTangentiel()";
+ facteur = maxdiag;
+ }
+ else // sinon c'est bon
+ {facteur = surf/maxdiag;}
+ };
+ break;
+ // pour mémoire pour la suite POINT_G = 1 , LIGNE , SURFACE, VOLUME, RIEN_TYPE_GEOM
+
+ //******** partie en construction
+
+ case LIGNE:
+ if (ParaGlob::AxiSymetrie())
+ // cas où l'on est en axisymétrique,
+ { // on regarde la dimension de l'élément associé
+ if (elem->ElementGeometrie(X1).Dimension()==2)
+ // élément 2D en axi donc 3D en réalité
+ { // récup de la longueur de la frontière
+ double longueur = elfrontiere->LongueurApprox();
+ // on calcul la surface associée
+ double surf = longueur * ConstMath::Pi * 2.;
+ // on récupère la surface de l'élément qui a créé la frontière
+ double volume = elem->Volume();
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenalTangentiel()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else // sinon ce n'est pas pris en charge
+ {cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << " contact sur une ligne axisyme trique"
+ << " \n ElContact::CalFactPenalTangentiel() ";
+ Sortie(1);
+ };
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==3)
+ // cas d'une ligne frontière d'un élément coque ou plaque
+ {
+ // il faut finir la fonction ElFrontiere::LongueurApprox()
+ // cf le laïus qui est écrit dans la méthode
+
+
+ double surf = elfrontiere->SurfaceApprox();
+ double volume = elem->Volume();
+
+ // virtual double EpaisseurMoyenne(Enum_dure )
+
+ if (Dabs(volume) <= ConstMath::pasmalpetit)
+ { if (niveau_commentaire > 1)
+ cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
+ << elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
+ if (niveau_commentaire > 4)
+ cout << "\n ElContact::CalFactPenalTangentiel()";
+ facteur = elfrontiere->MaxDiagonale_tdt();
+ }
+ else // sinon c'est bon
+ {facteur = surf*surf/volume;}
+ }
+ else if (elem->ElementGeometrie(X1).Dimension()==2)
+ // cas d'une ligne frontière d'une plaque
+ { double longueur = elfrontiere->LongueurApprox();
+ double epais = 0.; // init
+ if (!ParaGlob::AxiSymetrie()) // si on n'est pas en axi
+ {epais = ((ElemMeca*) elem)->EpaisseurMoyenne(TEMPS_tdt );}
+ else // si on est en axi
+ {epais = 1.;};
+ double surf = elem->Volume() / epais;
+ facteur = surf/longueur;
+ };
+ break;
+
+ //******** fin partie en construction
+ case POINT_G:
+ // on ne considère que le cas d'une dimension 1D non axi, qui est un cas d'école
+ // pour les autres cas, on considère que l'on ne doit pas prendre en compte des frontières
+ // de type point, du coup on génèrera une erreur
+ if (ParaGlob::Dimension() == 1 )
+ {// on veut calculer Ke * Ae * Ae / vol , comme on est dans le cas d'une barre
+ // vol = long * section, et Ae = section , du coup:
+ // Ke * Ae * Ae / vol = Ke * vol / (long * long) avec long = la longueur de l'élément
+ double longueur = elem->LongueurGeometrique(1);
+ double volume = elem->Volume();
+ facteur = volume / (longueur * longueur);
+ }
+ else
+ {cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << "\n contact en dimension " << ParaGlob::Dimension()
+ << " \n ElContact::CalFactPenalTangentiel() ";
+ Sortie(1);
+ };
+ break;
+
+ default:
+ cout << "\n *** erreur: cas non pris en charge pour l'instant: "
+ << " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
+ << " \n ElContact::CalFactPenalTangentiel() ";
+ Sortie(1);
+ };
+ // on tiens compte maintenant de la compressibilité (moyenne) de l'élément
+ facteur *= ((const ElemMeca*) elem)->CompressibiliteMoyenne();
+ }// fin du test d'existance d'une compressibilité
+ else
+ // on n'interdit pas car on pourrait avoir plusieurs maîtres, certains bien définit et
+ // d'autres sans comportement donc sans compressibilité:
+ {if (niveau_commentaire >5)
+ cout << "\n contact: *** attention le module de compressibilite n'est (encore?) pas defini "
+ << " on n'en tient pas compte (pour l'instant) pour le calcul du facteur de penalite tangentiel ! ";
+ };
+ break;
+ }
+ default:
+ cout << "\n **** erreur cas de calcul du facteur de penalisation tangentielle non existant "
+ << " typ_cal= " << typ_cal
+ << "\n ElContact::CalFactPenalTangentiel()";
+ Sortie(1);
+ };
+ // --- deuxième choix en fonction de typ_cal ---
+ // on calcul la valeur final du facteur
+ switch (typ_cal)
+ { case 1: case 2:
+ { fact_penal *= facteur;d_beta_dep_T = 0.;
+ if (niveau_commentaire >= 5)
+ cout << "\n fact_penal= " << fact_penal ;
+ break;
+ }
+ case 5:case 7: // on fait varier le coef de pénalisation lorsque le déplacement est plus petit qu'une borne
+ { // de régularisation
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation();}
+ // on calcul un facteur en fonction de la distance
+ if (Dabs(dep_T) > borne_regularisation)
+ {fact_penal *= facteur;d_beta_dep_T = 0.;}
+ else
+ { fact_penal *= facteur * Sqr((dep_T-borne_regularisation)/borne_regularisation) * 0.25;
+ d_beta_dep_T = facteur * (dep_T-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ };
+ break;
+ }
+ case 6: // idem cas 5 mais avec une fonction différente
+ { // on récupère le déplacement maxi
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
+ {borne_regularisation = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation));}
+ else {borne_regularisation = Dabs(ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation());}
+ // on calcul un facteur en fonction de la distance: = (0.5*(tanh(4.*dep_T/borne)-1.))
+ // 0.25*exp(-dep_T/(0.25*borne))
+ if (Dabs(dep_T) > borne_regularisation)
+ {fact_penal *= facteur;d_beta_dep_T = 0.;}
+ else
+ { fact_penal *= -facteur * 0.5 * (tanh(dep_T*4./borne_regularisation)-1.); // formule du même type
+ d_beta_dep_T = 4.*(1.-fact_penal*fact_penal)/borne_regularisation; //
+ };
+ break;
+ }
+ case 4: case 8: // quelque soit le sens de dep_T
+ // on fait varier le coef de pénalisation lorsque le déplacement est plus petit qu'un maxi
+ {
+ ////------ essai à virer
+ //fact_penal *= facteur;d_beta_dep_T = 0.;
+ // if (niveau_commentaire >= 5)
+ // cout << "\n fact_penal= " << fact_penal ;
+ // break;
+ ////------ fin essai
+ double borne_regularisation;
+ if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
+ {borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation);}
+ else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation();}
+ double max_dep_T;
+ if (fct_nD_contact.fct_nD_tangentielle_contact_maxi != NULL)
+ {max_dep_T = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_contact_maxi);}
+ else {max_dep_T = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_contact_maxi();}
+ // on calcul un facteur de majoration en fonction du déplacement du pas précédent
+ // double mult_tang = MaX(1., -dep_T_t/max_pene);
+ double mult_tang = MaX(1., (Dabs(dep_T_t)/max_dep_T)*mult_tang_t); // il faut appliquer au facteur précédent !
+ mult_tang_tdt = 0.5*(mult_tang_t + mult_tang); // on fait une moyenne glissante de 2
+ //////debug
+ //if (mult_tang_tdt == 1)
+ // {cout << "\n debug ElContact::CalFactPenalTangentiel() temps " << ParaGlob::Variables_de_temps().TempsCourant();
+ // };
+ ////fin debug
+ if (niveau_commentaire >= 5)
+ cout << "\n mult_tang_tdt= " << mult_tang_tdt ;
+ // on calcul un facteur en fonction de la distance: du même genre que pour la pénétration
+ // sauf qu'ici c'est vrai quelque soit la direction du déplacement
+ if (Dabs(dep_T) > borne_regularisation)
+ { fact_penal *= facteur * mult_tang_tdt; d_beta_dep_T = 0.;}
+ else
+ { fact_penal *= facteur * mult_tang_tdt * Sqr((-Dabs(dep_T)-borne_regularisation)/borne_regularisation) * 0.25;
+ d_beta_dep_T = facteur * mult_tang_tdt * (-Dabs(dep_T)-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
+ };
+ break;
+ }
+
+ default:
+ cout << "\n **** erreur 2 cas d'un calcul du facteur de penalisation tangentiel non existant "
+ << " typ_cal= " << typ_cal
+ << "\n ElContact::CalFactPenalTangentiel()";
+ Sortie(1);
+ };
+ };
+
+// dep_T_tdt = dep_T; // sauvegarde
+ // retour
+ return fact_penal;
+};
+
+// calcul éventuel de la moyenne glissante des positions successive du noeud esclave
+// et changement des coordonnées du point passé en paramètre
+void ElContact::ChangeEnMoyGlissante(Coordonnee& Noe_atdt)
+{ // pour simplifier
+ int taille_moyenne_glissante = ParaGlob::param->ParaAlgoControleActifs().Nb_moy_glissant();
+ // on dimensionne éventuellement le tableau des positions successives
+ if (tab_posi_esclave.Taille() != taille_moyenne_glissante)
+ tab_posi_esclave.Change_taille(taille_moyenne_glissante,Coordonnee(ParaGlob::Dimension()));
+
+ // on calcul éventuellement la moyenne glissante
+ if (taille_moyenne_glissante > 1)
+ { if (nb_posi_esclave_stocker_t < taille_moyenne_glissante)
+ { // c'est le cas où la moyenne n'est pas finalisée
+ nb_posi_esclave_stocker_tdt = nb_posi_esclave_stocker_t+1;
+ indice_stockage_glissant_tdt=1;
+ tab_posi_esclave(nb_posi_esclave_stocker_tdt) = noeud->Coord2();
+ // calcul de la moyenne
+ Noe_atdt=tab_posi_esclave(1); // init
+ for (int i=2;i<=nb_posi_esclave_stocker_tdt;i++)
+ Noe_atdt += tab_posi_esclave(i);
+ Noe_atdt /= nb_posi_esclave_stocker_tdt;
+ }
+ else // cas ou la moyenne est finalisée
+ { tab_posi_esclave(indice_stockage_glissant_t) = noeud->Coord2();
+ indice_stockage_glissant_tdt=indice_stockage_glissant_t+1; // mise à jour de l'indice pour le prochain stockage
+ // si l'indice dépasse la taille du taille, on remet au début
+ if (indice_stockage_glissant_tdt > taille_moyenne_glissante) indice_stockage_glissant_tdt = 1;
+ // calcul de la moyenne
+ Noe_atdt=tab_posi_esclave(1); // init
+ for (int i=2;i<=taille_moyenne_glissante;i++)
+ Noe_atdt += tab_posi_esclave(i);
+ Noe_atdt /= taille_moyenne_glissante;
+ };
+ };
+
+};
+
+
+// calcul de la moyenne glissante de la pénalisation
+void ElContact::Moyenne_glissante_penalisation(double& penalisation, double& essai_penalisation)
+ { // penalisation = la somme pondérée
+ int tai_val_penal = val_penal.Taille();
+ // on vérifie que la taille n'a pas changée
+ if (fct_pilotage_contact4 != NULL)
+ {if (fct_pilotage_contact4->NbComposante() == 2)
+ {Tableau & tava = fct_pilotage_contact4->Valeur_pour_variables_globales();
+ int nouvelle_taille = tava(2);
+ if (nouvelle_taille != tai_val_penal)
+ {if (nouvelle_taille > tai_val_penal)
+ // on se contente d'augmenter la taille de stockage
+ {val_penal.Change_taille(nouvelle_taille);}
+ else
+ // on va changer la taille en gardant les dernières valeurs (= les plus récentes)
+ {int diff = tai_val_penal-nouvelle_taille;
+ for (int i=1;i<= nouvelle_taille;i++)
+ val_penal(i) = val_penal(i+diff);
+ val_penal.Change_taille(nouvelle_taille);
+ if (pt_dans_val_penal > nouvelle_taille) pt_dans_val_penal = 1;
+ tai_val_penal = nouvelle_taille;
+ };
+ if (niveau_commentaire > 2)
+ cout << "\n -> Moyenne_glissante_penalisation: change taille "
+ << tai_val_penal << " -> " << nouvelle_taille;
+ };
+ };
+ };
+
+ if (val_penal(tai_val_penal) == 0.)
+ // cas où le tableau n'est pas complètement rempli
+ { penalisation *= (pt_dans_val_penal-1); // correspond à la somme
+ penalisation = (penalisation+essai_penalisation)/pt_dans_val_penal;
+ val_penal(pt_dans_val_penal)=essai_penalisation;
+ // pour pt_dans_val_penal == 1 cela donne directement essai_penalisation
+ }
+ else // sinon le tableau est rempli, on effectue des remplacements
+ { penalisation *= tai_val_penal; // la somme
+ penalisation = (penalisation - val_penal(pt_dans_val_penal) + essai_penalisation )/tai_val_penal;
+ val_penal(pt_dans_val_penal) = essai_penalisation;
+ }
+ pt_dans_val_penal++; // mise en place du retour périodique
+ if (pt_dans_val_penal > tai_val_penal) pt_dans_val_penal = 1;
+
+ };
+
+// calcul d'une fonction nD relative à des données de contact
+double ElContact::Valeur_fct_nD(Fonction_nD * pt_fonct) const
+ { // on commence par récupérer les conteneurs des grandeurs à fournir
+ List_io & li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
+ List_io & li_quelc = pt_fonct->Li_equi_Quel_evolue();
+ // on passe en revue les grandeurs pour les renseigner
+
+ // --- on balaie maintenant la liste des grandeurs à sortir
+ // 1) tout d'abord les ddl étendues
+ Tableau val_ddl_enum (li_enu_scal.size());
+ List_io::const_iterator ie,iefin=li_enu_scal.end();
+ int it; // it est l'indice dans le tableau de retour
+ for (it=1,ie=li_enu_scal.begin(); ie!=iefin;ie++,it++)
+ { // si c'est un ddl pure, on regarde si elle est définie au noeud
+ const Ddl_enum_etendu& enu = (*ie); // pour simplifier
+ bool trouver = false;
+ // on regarde d'abord s'il s'agit d'une info spécifique au contact
+ int posi = (*ie).Position()-NbEnum_ddl();
+ switch (posi)
+ { case 90: // reaction_normale -> en fait pas nécessaire, mais je laisse
+ // car existe au noeud en contact
+ {val_ddl_enum(it) = force_contact * N; trouver=true; break;}
+ // case 91: // reaction_tangentielle déjà stockée au noeud
+ // donc sera traité par le noeud en contact
+
+///**** en fait les cas X1, X1_t et X1_t0 ne vont pas être traités ici
+/// mais vont être traités en grandeurs quelconques car il s'agit de vecteur
+// Je laisse quand même mais on ne passera sans doute jamais ici
+ case 123: // "X1_t"
+ { val_ddl_enum(it) = noeud->Coord1()(1);trouver=true; break;}
+ case 124: // "X2_t"
+ { val_ddl_enum(it) = noeud->Coord1()(2);trouver=true; break;}
+ case 125: // X3_t
+ { val_ddl_enum(it) = noeud->Coord1()(3);trouver=true; break;}
+ case 126: // X1_t0
+ { val_ddl_enum(it) = noeud->Coord0()(1);trouver=true; break;}
+ case 127: // X2_t0
+ { val_ddl_enum(it) = noeud->Coord0()(2);trouver=true; break;}
+ case 128: // X3_t0
+ { val_ddl_enum(it) = noeud->Coord0()(3);trouver=true; break;}
+//*** fin
+
+ default: // sinon on le stock en ddl_étendu
+ trouver=false; break;
+ };// fin du switch
+
+ // si l'on n'a pas trouver, on regarde si l'info est dispo au noeud en contact
+ if (!trouver)
+ {if (enu.Position() <= NbEnum_ddl()) // cas d'un ddl pur
+ {if (noeud->Existe_ici(enu.Enum()))
+ {val_ddl_enum(it) = noeud->Ddl_noeud_tdt(enu.Enum()).Valeur();
+ trouver = true;
+ };
+ }
+ else // cas d'un ddl étendu
+ { if (noeud->Existe_ici_ddlEtendu(enu))
+ {val_ddl_enum(it) = noeud->DdlEtendue(enu).ConstValeur();
+ trouver = true;
+ };
+ };
+ };
+
+ // si on n'a rien trouvé
+ if (!trouver)
+ {cout << "\n erreur***: le ddl " << enu.Nom_plein()
+ << " n'existe pas pour le noeud en contact "
+ << " la fonction nD " << pt_fonct->NomFonction()
+ << " ne peut pas etre renseignee " << flush;
+ if (niveau_commentaire > 2)
+ {this->Affiche();
+ pt_fonct->Affiche();
+ }
+ Sortie(1);
+ };
+
+ };// -- fin de la boucle sur la liste de Ddl_enum_etendu
+
+ // 2) puis les grandeurs quelconques
+ List_io::iterator ipq,ipqfin=li_quelc.end();
+ for (ipq=li_quelc.begin();ipq!=ipqfin;ipq++)
+ { bool trouver = false;
+ TypeQuelconque& enuTQ = (*ipq); // pour simplifier
+ const TypeQuelconque_enum_etendu& en_ET_TQ = enuTQ.EnuTypeQuelconque().EnumTQ();
+
+ // on regarde tout d'abord les grandeurs spécifiques à l'élément contact
+ switch (enuTQ.EnuTypeQuelconque().EnumTQ())
+ { // il y a des grandeurs vectorielles qui pour l'instant ne sont pas prises en compte
+ // cf. fct nD
+ // NORMALE_CONTACT, GLISSEMENT_CONTACT ,PENETRATION_CONTACT,FORCE_CONTACT,
+ case CONTACT_NB_DECOL:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = nb_decol_tdt;
+ trouver = true;
+ break;
+ }
+ case CONTACT_PENALISATION_N:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = penalisation;
+ trouver = true;
+ break;
+ }
+ case CONTACT_PENALISATION_T:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = penalisation_tangentielle;
+ trouver = true;
+ break;
+ }
+ case CONTACT_NB_PENET:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = nb_pene_tdt;
+ trouver = true;
+ break;
+ }
+ case CONTACT_CAS_SOLIDE:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = cas_solide;
+ trouver = true;
+ break;
+ }
+ case CONTACT_ENERG_GLISSE_ELAS:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = energie_frottement.EnergieElastique();
+ trouver = true;
+ break;
+ }
+ case CONTACT_ENERG_GLISSE_PLAS:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = energie_frottement.DissipationPlastique();
+ trouver = true;
+ break;
+ }
+ case CONTACT_ENERG_GLISSE_VISQ:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = energie_frottement.DissipationVisqueuse();
+ trouver = true;
+ break;
+ }
+ case CONTACT_ENERG_PENAL:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurDouble()) = energie_penalisation;
+ trouver = true;
+ break;
+ }
+ case NOEUD_PROJECTILE_EN_CONTACT:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ if (actif)
+ {*(gr.ConteneurDouble()) = 100.;}
+ else
+ {*(gr.ConteneurDouble()) = -0.1; };
+ trouver = true;
+ break;
+ }
+ case NOEUD_FACETTE_EN_CONTACT:
+ { Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
+ int NBNF = tabNoeud.Taille();
+ if (actif)
+ { for (int i=2;i<=NBNF;i++)
+ *(gr.ConteneurDouble()) += 100.;
+ }
+ else
+ { for (int i=2;i<=NBNF;i++)
+ *(gr.ConteneurDouble()) -= 0.1;
+ };
+ trouver = true;
+ break;
+ }
+ case NUM_NOEUD:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = noeud->Num_noeud();
+ trouver = true;
+ break;
+ }
+ case NUM_MAIL_NOEUD:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = noeud->Num_Mail();
+ trouver = true;
+ break;
+ }
+ case POSITION_GEOMETRIQUE:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= noeud->Coord2();
+ trouver = true;
+ break;
+ }
+ case POSITION_GEOMETRIQUE_t:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= noeud->Coord1();
+ trouver = true;
+ break;
+ }
+ case POSITION_GEOMETRIQUE_t0:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= noeud->Coord0();
+ trouver = true;
+ break;
+ }
+ // *** pour l'instant la suite n'est pas opérationelle car il s'agit de vecteur
+ // dont les composantes n'ont pas d'équivalent en ddl_enum_etendu
+ // il faudrait les définir si on veut pouvoir s'en servir
+ case PENETRATION_CONTACT:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= Mtdt-noeud->Coord2();
+ trouver = true;
+ break;
+ }
+ case PENETRATION_CONTACT_T:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= Mt-noeud->Coord1();
+ trouver = true;
+ break;
+ }
+ case GLISSEMENT_CONTACT:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= dep_tangentiel;
+ trouver = true;
+ break;
+ }
+ case GLISSEMENT_CONTACT_T:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= dep_T_t;
+ trouver = true;
+ break;
+ }
+ case NORMALE_CONTACT:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= N;
+ trouver = true;
+ break;
+ }
+ case FORCE_CONTACT:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= force_contact;
+ trouver = true;
+ break;
+ }
+ case FORCE_CONTACT_T:
+ {Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
+ (*gr.ConteneurCoordonnee())= force_contact_t;
+ trouver = true;
+ break;
+ }
+ case CONTACT_COLLANT:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = cas_collant;
+ trouver = true;
+ break;
+ }
+ case NUM_ZONE_CONTACT:
+ { Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
+ *(gr.ConteneurEntier()) = num_zone_contact;
+ trouver = true;
+ break;
+ }
+ //*** fin
+
+
+ default:
+ trouver = false;
+ break;
+ };
+
+ // si l'on n'a pas trouver, on regarde si l'info est dispo au noeud en contact
+ if (!trouver)
+ {if (noeud->Existe_ici(en_ET_TQ))
+ { (*(enuTQ.Grandeur_pointee())) = (*noeud->Grandeur_quelconque(en_ET_TQ).Const_Grandeur_pointee());
+ trouver = true;
+ };
+ };
+
+ // si on n'a rien trouvé
+ if (!trouver)
+ {cout << "\n erreur***: la grandeur " << en_ET_TQ.NomPlein()
+ << " n'existe pas pour le noeud en contact "
+ << " la fonction nD " << pt_fonct->NomFonction()
+ << " ne peut pas etre renseignee " << flush;
+ if (niveau_commentaire > 2)
+ {this->Affiche();
+ pt_fonct->Affiche();
+ }
+ Sortie(1);
+ };
+
+ };
+
+ // calcul de la valeur et retour dans tab_ret
+ Tableau & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
+ #ifdef MISE_AU_POINT
+ if (tab_val.Taille() != 1)
+ { cout << "\nErreur : la fonction nD " << pt_fonct->NomFonction()
+ << " doit calculer un scalaire or le tableau de retour est de taille "
+ << tab_val.Taille() << " ce n'est pas normal !\n" << flush;
+ if (niveau_commentaire > 2 )
+ cout << "\n ElContact::Valeur(... \n";
+ Sortie(1);
+ };
+ #endif
+ // on récupère le premier élément du tableau uniquement
+ return tab_val(1);
+ };
+
+
+
+
diff --git a/contact/LesContacts.cc b/contact/LesContacts.cc
new file mode 100644
index 0000000..01c1b81
--- /dev/null
+++ b/contact/LesContacts.cc
@@ -0,0 +1,2193 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+
+#include "LesContacts.h"
+#include
+#include "ReferenceNE.h"
+#include "ReferenceAF.h"
+#include "CharUtil.h"
+
+#include "Enum_TypeQuelconque.h"
+#include "TypeQuelconqueParticulier.h"
+
+
+// --------------- variables statiques ---------
+ MotCle LesContacts::motCle; // liste des mots clés
+
+//------------------------- la classe ReactCont -------------
+// surcharge de l'operator de lecture
+//istream & operator >> (istream & ent, LesContacts::ReactCont & a)
+istream & operator >> (istream & ent, LesContacts::ReactCont & )
+ { // lecture du type et vérification
+ string nom_type; ent >> nom_type;
+ if (nom_type != "LesContacts::ReactCont")
+ Sortie(1);
+ // les infos **** pb de la reconnaissance du noeud ***
+ /* EN CHANTIER
+ ent >> a.noe->Num_Mail() >> a.noe->Num_noeud() << " ";
+ // la force
+ sort << a.force;
+ // les noeuds de la frontière maitre
+ int taille = tabNoeud.Taille();
+ for (int i=1;i<=taille;i++)
+ sort << a.tabNoeud(i)->Num_Mail()
+ << " " << a.tabNoeud(i)->Num_noeud() << " ";
+ // les réactions de la frontière maître
+ int taille2 = tabForce.Taille();
+ for (int i=1;i<=taille2;i++)
+ sort << a.tabForce(i); */
+ return ent ;
+ };
+// surcharge de l'operator d'ecriture
+ostream & operator << (ostream & sort , const LesContacts::ReactCont & a)
+ { // écriture du type
+ sort << "LesContacts::ReactCont ";
+ // les infos
+ sort << a.noe->Num_Mail() << " " << a.noe->Num_noeud() << " ";
+ // la force
+ sort << a.force;
+ // les noeuds de la frontière maitre
+ int taille = a.tabNoeud.Taille();
+ for (int i=1;i<=taille;i++)
+ sort << a.tabNoeud(i)->Num_Mail()
+ << " " << a.tabNoeud(i)->Num_noeud() << " ";
+ // les réactions de la frontière maître
+ int taille2 = a.tabForce.Taille();
+ for (int i=1;i<=taille2;i++)
+ sort << a.tabForce(i);
+ return sort ;
+ };
+
+// constructeur par defaut
+LesContacts::ReactCont::ReactCont() : force(),tabNoeud(),tabForce() { noe = NULL; };
+// constructeur en fonction des datas du noeud esclave seul
+LesContacts::ReactCont::ReactCont(Noeud* no,const Coordonnee& forc) :
+ force(forc),tabNoeud(),tabForce() { noe = no;};
+// constructeur en fonction des datas de tous les noeuds
+LesContacts::ReactCont::ReactCont
+ (Noeud* no,const Coordonnee& forc,Tableau tN,const Tableau & tFor)
+ : force(forc),tabNoeud(tN),tabForce(tFor) { noe = no;};
+// constructeur de copie
+LesContacts::ReactCont::ReactCont(const ReactCont& a) : force(a.force),tabNoeud(a.tabNoeud),tabForce(a.tabForce)
+ { noe = a.noe;};
+// affectation
+LesContacts::ReactCont& LesContacts::ReactCont::operator = (const LesContacts::ReactCont& a)
+ { force =a.force;noe = a.noe;tabNoeud = a.tabNoeud;tabForce = a.tabForce;
+ return *this;};
+// test
+bool LesContacts::ReactCont::operator == (const LesContacts::ReactCont& a)
+ { if ((force == a.force) &&(noe == a.noe) &&
+ (tabNoeud == a.tabNoeud) &&(tabForce == a.tabForce))
+ return true; else return false;};
+bool LesContacts::ReactCont::operator != (const LesContacts::ReactCont& a)
+ { if (*this == a) return false; else return true; };
+
+//------------------------- fin la classe ReactCont -------------
+ // CONSTRUCTEURS :
+// constructeur par defaut
+LesContacts::LesContacts () :
+ tabCoLin(),tabReacCont(),listContact()//,numtesN()
+ ,sauve_lesFonctionsnD(NULL),fct_nD_contact()
+ ,listContact_nouveau_tatdt(),listContact_efface_tatdt()
+ ,nom_ref_zone_contact()
+ ,t_listFront(),nb_mail_Esclave(),nbmailautocontact(0),nbmailMaitre()
+ ,tesctotal(),tesN_encontact()
+ ,tesN_collant()
+ ,nb_contact_actif(0),indice(),cont_solide_defor(),liQ_en_sortie()
+ ,t_connectionCLL()
+ ,liste_elemens_front(),tempsContact()
+ {};
+// constructeur de copie
+LesContacts::LesContacts (const LesContacts& a):
+ tabCoLin(a.tabCoLin),tabReacCont(a.tabReacCont)
+ ,sauve_lesFonctionsnD(a.sauve_lesFonctionsnD),fct_nD_contact(a.fct_nD_contact)
+ ,listContact(a.listContact)//,numtesN(a.numtesN)
+ ,listContact_nouveau_tatdt(a.listContact_nouveau_tatdt),listContact_efface_tatdt(a.listContact_efface_tatdt)
+ ,nom_ref_zone_contact(a.nom_ref_zone_contact)
+ ,t_listFront(a.t_listFront),nb_mail_Esclave(a.nb_mail_Esclave),nbmailautocontact(a.nbmailautocontact)
+ ,nbmailMaitre(a.nbmailMaitre),tesctotal(a.tesctotal),tesN_encontact(a.tesN_encontact)
+ ,tesN_collant(a.tesN_collant)
+ ,nb_contact_actif(a.nb_contact_actif),indice(a.indice),cont_solide_defor(a.cont_solide_defor)
+ ,liste_elemens_front(a.liste_elemens_front),liQ_en_sortie(),tempsContact(a.tempsContact)
+ ,t_connectionCLL(a.t_connectionCLL)
+ {};
+ // DESTRUCTEUR :
+LesContacts::~LesContacts ()
+ { };
+
+ // METHODES PUBLIQUES :
+
+// initialisation des zones de contacts éventuelles à partir des éléments de frontières et des noeuds esclaves
+// sauf les frontières qui sont les mêmes pendant tout le calcul
+ // --- en entrée:
+ // les maillages, les ref et les fonctions nD
+ // -- en sortie:
+ // cas du contact type 4 : on renseigne éventuellement une fonction de pilotage --> fct_pilotage_contact4
+ // récup de: nb_mail_Esclave, nbmailMaitre,
+ // récup du tableau "indice" : = la liste pour chaque noeud, des éléments qui contient ce noeud
+ // création des conteneurs internes : tesctotal, tesN_collant, t_listFront, tesN_encontact
+
+void LesContacts::Init_contact(LesMaillages& lesMail
+ ,const LesReferences& lesRef
+ ,LesFonctions_nD* lesFonctionsnD)
+ {
+ tempsContact.Mise_en_route_du_comptage(); // temps cpu
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ // on met à jour le niveau de commentaire dans les éléments de contact
+ ElContact::Mise_a_jour_niveau_commentaire(niveau_commentaire_contact);
+ if (niveau_commentaire_contact >= 7)
+ cout << "\n -- LesContacts::Init_contact: ";
+
+ // sauvegarde de la liste des fonctions nD
+ sauve_lesFonctionsnD = lesFonctionsnD;
+ Creation_Fct_nD_contact(); // récupération des fonctions de pilotage éventuelles
+
+ // --- récup info maillage
+ // tescin : a la dimension du nombre de maillage esclave
+ // comme les maillages esclaves sont les premiers dans le .info,
+ // tescin(i) correspond aux noeuds des frontières du maillage i
+ // listFrontiere (i) : tous les frontières des maillages, (peut-être vide pour certains maillages sans frontières)
+ // correspond aux frontières du maillage i: dabord pour les esclaves puis les maîtres
+ // nbEscla : nb de maillage esclave
+ // ind : pour tous les maillages, la liste des éléments qui contiennent chaque noeud
+ // (mis à jour lors de la création des frontières)
+ Tableau < Tableau *> tescin = lesMail.Tab_noeud_frontiere_esclave();
+ Tableau *>& listFrontiere = lesMail.ListFrontiere();
+ const Tableau < const Tableau > *>& ind = lesMail.Indice();
+
+
+ // dans le cas d'un contact de type 4 on renseigne éventuellement une fonction de pilotage
+ string nom_fct4 = ParaGlob::param->ParaAlgoControleActifs().Fct_nD_bascul_contact_type_4();
+ if ((ParaGlob::param->ParaAlgoControleActifs().ContactType() == 4)
+ && (nom_fct4 != "_")
+ )
+ {// on va récupérer la fonction
+ if (lesFonctionsnD->Existe(nom_fct4))
+ { Fonction_nD * pt_fonct = lesFonctionsnD->Trouve(nom_fct4);
+ // on vérifie pour l'instant que c'est bien une fonction de grandeurs globales
+ if (pt_fonct->NbVariable_locale() != 0) // cas où il n'y a pas que des variables globales
+ { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
+ << " du type de contact 4 : " << nom_fct4
+ << " n'utilise pas que des variables globales !! ";
+ Sortie(1);
+ }
+ else if (pt_fonct->NbComposante() > 2)
+ { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
+ << " du type de contact 4 : " << nom_fct4
+ << " ramene plus de 2 composantes !! ";
+ Sortie(1);
+ }
+ else // sinon ok
+ {ElContact::Init_fct_pilotage_contact4(pt_fonct);}
+ }
+ else
+ { cout << "\n *** erreur dans la definition de la fonction nD de pilotage "
+ << " du type de contact 4 , le nom : " << nom_fct4
+ << " ne correspond pas a une fonction nD existante !! ";
+ Sortie(1);
+ };
+ };
+
+ /* // ----pour le débug
+ //{int nbMaillageTotal = listFrontiere.Taille();
+ //for (int nbmail=1;nbmail<=nbMaillageTotal;nbmail++)
+ // {int nbfront = listFrontiere(nbmail)->size();
+ // cout << "\n maillage " << nbmail << " -------- ";
+ // LaLIST ::iterator iff,iffin = listFrontiere(nbmail)->end();
+ // iff=listFrontiere(nbmail)->begin();
+ //// for (iff=listFrontiere(nbmail)->begin();iff !=iffin;iff++)
+ // Front& titi = (*iff);
+ // titi.Affiche(); cout << "\n";
+ //
+ // };
+ //
+ // Sortie(1);
+ //};
+ //// fin débug */
+ // dans le tableau de listes de frontière on a d'abord les elements frontieres
+ // esclaves puis les elements maitres
+ int ntmail = listFrontiere.Taille(); // nb maxi de maillages
+ nb_mail_Esclave = lesMail.NbEsclave(); // def du nombre de maillages esclaves
+ // les maillages mixtes (ou en autocontact) font partie de la liste des nbEscla
+ // d'où si par exemple tous les éléments peuvent entrer en auto-contact
+ // -> nbEscla == ntmail == nbmailautocontact == nbmailMaitre
+ nbmailMaitre = ntmail-(nb_mail_Esclave-nbmailautocontact); // def du nombre de maillage maitres
+ // dans le cas d'auto-contact, on vérifie la cohérence
+ if (nbmailautocontact != 0)
+ {if ((nbmailautocontact <1) || (nbmailautocontact > nb_mail_Esclave))
+ // nbmailautocontact doit etre >= 0 et < nb_mail_Esclave
+ { cout << "\n ** incoherence dans le nombre de maillage en auto contact !! "
+ << ", le nombre de maillage en auto contact lu : " << nbmailautocontact
+ << ", n\'est pas acceptable, il est soit negatif soit superieur au nombre de maillage esclave ( "
+ << nb_mail_Esclave << " ) "
+ << endl;
+ if (niveau_commentaire_contact >= 0)
+ cout << "\n LesContacts::Init_contact(... " << endl;
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ };
+ // on récupère le tableau indice
+ indice = ind;
+ if (niveau_commentaire_contact >2 )
+ cout << "\n >>>> Information : Initialisation du contact: ";
+ // dimensionnement du premier niveau des tableaux
+ tesctotal.Change_taille(nb_mail_Esclave);
+ tesN_collant.Change_taille(nb_mail_Esclave);
+ t_listFront.Change_taille(nbmailMaitre);
+ // --- on s'occupe du deuxième niveau de tesN_encontact
+ // une map vide par défaut
+ std::map::iterator > > map_vide;
+ tesN_encontact.Change_taille(nb_mail_Esclave,map_vide);
+
+ // --- on s'occupe maintenant des niveaux 2 et 3 des tableaux tesctotal et tesN_collant
+ // on regarde si la zone de contact est restreinte
+ if (nom_ref_zone_contact.size() == 0)
+ { // cas d'un contact non restreint
+ // cela correspond finalement à une seule zone de contact
+ // 1-- cas des noeuds esclaves
+ for (int ii=1;ii<= nb_mail_Esclave;ii++)
+ { int taille = tescin(ii)->Taille(); // nombre de noeuds esclave
+ // tescin -> tous les noeuds possiblement en esclave donc en contact
+ tesctotal(ii).Change_taille(1);tesctotal(ii)(1).Change_taille(taille);
+ tesN_collant(ii).Change_taille(1);tesN_collant(ii)(1).Change_taille(taille);
+ for (int itai=1;itai<=taille;itai++)
+ {// ici, la seule zone c'est "tout" les noeuds esclaves, du coup le numéro d'ordre
+ // de stockage c'est le numéro dans tescin(ii), c-a-d le numéro de classement des noeuds esclaves
+ // pour le maillage ii
+ tesctotal(ii)(1)(itai) = (*tescin(ii))(itai);
+ tesN_collant(ii)(1)(itai) = 0; // pas de contact collant car le contact est non restreint
+ };
+ if (niveau_commentaire_contact >2 )
+ cout << "\n mail. esclave "< & lis_fronta = (t_listFront(ilistfront)(1));
+ LaLIST ::iterator iMi,iMifin=(*listFrontiere(jf)).end();
+ for (iMi = (*listFrontiere(jf)).begin();iMi != iMifin; iMi++)
+ lis_fronta.push_back((*iMi));
+ if (niveau_commentaire_contact >2 )
+ cout << "\n mail. maitre "<::iterator il,ilfin=nom_ref_zone_contact.end();
+ int nb_zone = nom_ref_zone_contact.size();
+ if (niveau_commentaire_contact >2 )
+ cout << "\n --> nombre de zone de contact: " << nb_zone;
+ // --- tout d'abord on s'occupe des noeuds esclaves
+ // on va boucler sur les zones pour être sûr de définir complètement toutes les zones
+ int izone=1;
+ for (il=nom_ref_zone_contact.begin(); il!=ilfin;il++,izone++) // boucle sur les références de zone_contact
+ { // recup de la reference correspondant au mot cle
+ string * nom_mail_noe=NULL;
+ string nom_inter;
+ if ((*il).nom1.length())
+ {nom_inter = ((*il).nom1);
+ nom_mail_noe = &nom_inter;
+ }
+ const Reference & ref = lesRef.Trouve((*il).nom2,nom_mail_noe);
+ // on continue que si c'est une référence de noeud
+ if (ref.Indic() != 1)
+ { // ce n'est pas normal -> message d'erreur
+ cout << "\n *** erreur la reference de zone de contact n'est pas "
+ << " une reference de noeud ! ";
+ ref.Affiche();
+ cout << "\n LesContacts::Init_contact(..." << endl;
+ Sortie(1);
+ };
+ // on peut maintenant utiliser de manière sûre une ref NE
+ const ReferenceNE & refNE = ((ReferenceNE &) ref);
+ // maintenant on va boucler sur les noeuds esclaves pour trouver
+ // les noeuds de la ref
+ bool zone_definie = false;
+ for (int intot = 1;intot<= nb_mail_Esclave;intot++)
+ {// on dimensionne le niveaux 2 des tableaux
+ tesctotal(intot).Change_taille(nb_zone);
+ tesN_collant(intot).Change_taille(nb_zone);
+ // et maintenant le niveau 3 c-a-d le troisième niveau
+ //Les zones définies sont prises telles qu'elle, elles peuvent donc
+ // définir des noeuds potentiels au contact en dehors de ceux définis
+ // par la construction automatique des frontières dans lesMaillages
+ // -> donc ici on ne considère pas tescin (modif: 16 mai 2020)
+ int nb_noe = refNE.Taille(); // init
+ tesctotal(intot)(izone).Change_taille(nb_noe);
+ tesN_collant(intot)(izone).Change_taille(nb_noe);
+ // maintenant on va remplir
+ for (int no_dans_ref = 1; no_dans_ref<= nb_noe;no_dans_ref++)
+ {int num_noe_ref = refNE.Numero(no_dans_ref);
+ tesctotal(intot)(izone)(no_dans_ref)= &(lesMail.Noeud_LesMaille(ref.Nbmaille(),num_noe_ref));
+ tesN_collant(intot)(izone)(no_dans_ref)= (*il).n;
+ }; // -- fin de la boucle sur les noeuds de la référence
+ if (niveau_commentaire_contact >2 )
+ cout << "\n maillage esclave "< " << nb_noe << " noeuds esclaves pour contact ";
+ // arrivée ici, c'est que la zone a été définie
+ zone_definie = true;
+ }; // -- fin de la boucle sur intot c-a-d les maillages esclave
+ // message d'erreur si la zone n'a pas été définie
+ if (!zone_definie)
+ { cout << "\n *** erreur dans la construction de la zone de contact "< donc ici on ne considère pas "listFrontiere" (modif: 16 mai 2020)
+
+ Tableau < int > zone_frontiere(nb_zone,0); // le nb d'elem dans chaque zone
+ // on initialise la liste
+ // on parcours les elements maitres
+ int ilistfront = 1; // compteur pour le tableau t_listFront
+ //à cause d'un auto contact éventuelle on peut avoir des maillages esclaves qui jouent le rôle également de
+ // maillages maitres
+ for (int jlf=ntmail-nbmailMaitre+1;jlf<=ntmail;jlf++,ilistfront++) // boucle sur les maillages maitres
+ {// on dimensionne le niveaux 2 des tableaux
+ t_listFront(ilistfront).Change_taille(nb_zone);
+ int izone = 1; // init compteur de zone
+ for (il=nom_ref_zone_contact.begin(); il!=ilfin;il++,izone++) // boucle sur les références de zone_contact
+ { // recup de la reference correspondant au mot cle
+ string * nom_mail_face=NULL;
+ if (((*il).nom3.length()))
+ nom_mail_face = &(*il).nom3;
+ // on regarde si la référence existe
+ string nom_ref = (*il).nom4;
+ if (!lesRef.Existe(nom_ref,nom_mail_face))
+ { cout << "\n *** erreur la reference "<< nom_ref;
+ if (nom_mail_face != NULL)
+ cout << " du maillage " << *nom_mail_face;
+ cout << " n'existe pas !! ";
+ cout << "\n LesContacts::Init_contact(..." << endl;
+ Sortie(1);
+ };
+
+ const Reference & ref = lesRef.Trouve((*il).nom4,nom_mail_face);
+ // on continue si le maillage de la ref est bien celui du maître que l'on consulte actuellement
+ if (ref.Nbmaille() == jlf)
+ {// --- on balaie les frontières potentielles
+ LaLIST_io & list_fronta = (t_listFront(ilistfront)(izone)); // pour simplifier
+ switch (ref.Indic())
+ {case 3: // cas d'une frontière de type surface,
+ {const ReferenceAF & refAF = ((ReferenceAF &) ref);
+ int nb_fr = refAF.Taille();
+ for (int i_fr = 1; i_fr <= nb_fr;i_fr++)
+ {int num_fr = refAF.NumeroFA(i_fr); // le numéro de la frontière
+ int num_ele = refAF.NumeroElem(i_fr); // le numéro de l'élément associé
+ int num_mail = refAF.Nbmaille();
+ Element& ele = lesMail.Element_LesMaille(num_mail, num_ele);
+ // récupération ou création de la frontière
+ ElFrontiere* fro = ele.Frontiere_surfacique(num_fr);
+ // création et ajout de la frontière
+ list_fronta.push_back(Front (*fro,&ele,num_fr)) ;
+ zone_frontiere(izone)++;
+ };
+ break;
+ }
+ case 4: // cas d'une frontière de type arête
+ {const ReferenceAF & refAF = ((ReferenceAF &) ref);
+ int nb_fr = refAF.Taille();
+ for (int i_fr = 1; i_fr <= nb_fr;i_fr++)
+ {int num_fr = refAF.NumeroFA(i_fr); // le numéro de la frontière
+ int num_ele = refAF.NumeroElem(i_fr); // le numéro de l'élément associé
+ int num_mail = refAF.Nbmaille();
+ Element& ele = lesMail.Element_LesMaille(num_mail, num_ele);
+ // récupération ou création de la frontière
+ ElFrontiere* fro = ele.Frontiere_lineique(num_fr);
+ // création et ajout de la frontière
+ list_fronta.push_back(Front (*fro,&ele,num_fr)) ;
+ zone_frontiere(izone)++;
+ };
+ break;
+ }
+ default:
+ // ici la frontière peut-être n'importe quoi: point, arête, surface
+ // on vérifie que ce ne sont pas des ref Indic 5 ou 6 ou plus ou 1 ou 2
+ { cout << "\n *** erreur la reference de zone de frontiere de contact n'est pas "
+ << " une reference acceptable ! "
+ << " seules les ref d'aretes ou de surface sont possibles " ;
+ ref.Affiche();
+ cout << "\n LesContacts::Init_contact(..." << endl;
+ Sortie(1);
+ break;
+ };
+ }; // fin du switch sur le type de frontière
+ };
+ }; //-- fin de la boucle sur zone de contact
+ }; //-- fin de la boucle sur les maillages maîtres
+ // petit message si nécessaire
+ if (niveau_commentaire_contact >2 ) //&& (list_fronta.size() > 0))
+ { for (int i=1;i<= nb_zone;i++) // boucle sur les références de zone_contact
+ { cout << "\n zone de contact: " << i << " => "
+ << zone_frontiere(i)
+ << " frontieres prises en compte pour le contact ";
+ if (zone_frontiere(i) == 0)
+ cout << "\n *** warning c'est un peu etrange qu'il y ait 0 frontiere, cela veut dire "
+ << " que cette zone ne sera pas utilisable !! ";
+ };
+ };
+
+ }; //-- fin du else : cas d'une zone restreinte de contact
+
+ // Pour diminuer le temps de recherche, et aussi les messages on va constituer une liste des éléments
+ // qui contiennent les frontières
+ int nb_zone = MaX(1,nom_ref_zone_contact.size());
+ liste_elemens_front.clear(); // init de la liste
+ for (int i=1;i<=nbmailMaitre;i++)
+ { for (int j=1;j<=nb_zone;j++)
+ { LaLIST_io & list_fronta = (t_listFront(i)(j)); // pour simplifier
+ LaLIST ::iterator iM,iMfin=list_fronta.end();
+ for (iM = list_fronta.begin();iM != iMfin; iM++) // boucle sur les frontières enregistrées
+ liste_elemens_front.push_back((*iM).PtEI());
+ };
+ };
+ // on ordonne la liste puis on supprime les doublons
+ liste_elemens_front.sort(); // ordonne
+ liste_elemens_front.unique(); // supprime les doublons
+
+ // --- cas des contacts collants avec suppression des gaps ----
+ // suppression du gap de contact pour les noeuds "collant avec suppression de gap"
+ Suppression_gap_pour_noeud_collant();
+
+ ////--- debug
+ //{ for (int jf=ntmail-nbmailMaitre+1;jf<=ntmail;jf++)
+ // { LaLIST ::iterator iM,iMfin=(*listFrontiere(jf)).end();
+ // for (iM = (*listFrontiere(jf)).begin();iM != iMfin; iM++) // boucle sur les fronts maitres
+ // { ElFrontiere* elemf = (*iM).Eleme(); // pour simplifier
+ // if (((*iM).Num_frontiere() == 1) && ((*iM).PtEI()->Num_elt()== 3130)
+ // && ((*iM).PtEI()->Num_maillage() == 4))
+ // { cout << "\n debug : frontiere 1 de l'element 3130";
+ // }
+ // }
+ // }
+ //}
+ ////-- fin debug
+
+ tempsContact.Arret_du_comptage(); // fin cpu
+ };
+
+
+// verification qu'il n'y a pas de contact avant le premier increment de charge
+void LesContacts::Verification()
+{ // on va iterer sur les noeuds esclaves pour savoir s'ils sont internes
+ // a un element c-a-d a l'interieur d'un element qui contiend un element
+ // frontiere
+ int nb_zone = MaX(1,nom_ref_zone_contact.size());
+
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact >= 7)
+ cout << "\n -- LesContacts::Verification: ";
+ // mise à jour les boites d'encombrement des éléments frontière
+ {LaLIST_io ::iterator iM,iMfin;
+ for (int i=1;i<=nbmailMaitre;i++)
+ for (int j=1;j<= nb_zone;j++)
+ { iMfin=(t_listFront(i)(j)).end();
+//debug
+//cout << "\n les elements frontières: " << t_listFront(jjf) << " ";
+// fin debug
+ for (iM = (t_listFront(i)(j)).begin() ; iM != iMfin; iM++)
+ (*iM).Boite_encombrement_frontiere(TEMPS_t,0.); // au début pas de déplacement -> 0.
+ };
+ };
+
+
+ list ::iterator ilfele, ilfelefin = liste_elemens_front.end();
+ for (int intot = 1;intot<= nb_mail_Esclave;intot++)
+ for (int j=1;j<= nb_zone;j++)
+ { const Tableau & tesc= tesctotal(intot)(j); // pour simplifier la notation
+ const Tableau tesN_col = tesN_collant(intot)(j); // pour simplifier
+ int tesc_taille=tesc.Taille();
+ for (int inesc = 1;inesc<= tesc_taille;inesc++)
+ { Noeud* noee = tesc(inesc); // pour simplifier
+ const Coordonnee& pt_esc = noee->Coord1(); // position du noeud esclave à l'instant t
+//debug
+//cout << "\n pt_esc= " << pt_esc << " "<< endl ;
+// fin debug
+ int num_mail_noe_esclave = noee->Num_Mail();
+ // on parcours les elements maitres
+ for (ilfele = liste_elemens_front.begin(); ilfele != ilfelefin; ilfele++)
+ { Element & elem = *(*ilfele); // l'element qui contiend la frontiere
+ // dans le cas où l'élément et le noeud appartienne au même maillage, on est
+ // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
+ // qui ne contiennent pas le noeud esclave
+ if (elem.Num_maillage() == num_mail_noe_esclave)
+ { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(noee->Num_noeud()); // pour simplifier
+ if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
+ break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
+ };
+ // on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ if (elem.In_boite_emcombrement_elem(pt_esc))
+ // on teste alors plus précisemment
+ {//compteur++;
+ if ((elem.Interne_t(pt_esc)==1) && (niveau_commentaire_contact >= 3))
+ { cout << "\n attention, noeud esclave dans elem. "
+ << "avant incre. 1 charge";
+ if (niveau_commentaire_contact > 2)
+ cout << "\n LesContacts::Verification(..)";
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n -> noeud " << tesc(inesc)->Num_noeud() << " du maillage " << tesc(inesc)->Num_Mail()
+ << " dans l'element " << elem.Num_elt() << " du maillage " << num_mail_elem ;
+ if (tesN_col(inesc)) cout << " (contact collant) ";
+//elem.Interne_t(pt_esc); // debug
+ //cout << endl;
+ // elem.Affiche();tesc(inesc)->Affiche();
+//--- on laisse pour voir continuer Sortie(1);
+ };
+ };
+ }; // -- fin de la boucle sur ifele
+ }; // -- fin de la boucle sur inesc
+ }; //-- fin de la boucle sur les zones
+// cout << "\n compteur = " << compteur << endl;
+// Sortie(1);
+};
+
+
+// definition des elements de contact eventuels
+// dep_max : déplacement maxi des noeuds du maillage
+// cette méthode est utilisée au début du calcul, ensuite c'est Nouveau()
+// qui prend le relais
+// ramène true s'il y a effectivement création d'élément de contact
+bool LesContacts::DefElemCont(double dep_max)
+ {
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ bool retour = false; // init par défaut
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact > 2)
+// if (max(ParaGlob::NiveauImpression(),niveau_commentaire_contact)> 4)
+ cout << "\n ==> LesContacts::Def Elem Cont, initialement "<ParaAlgoControleActifs().DistanceMaxiAuPtProjete());
+
+
+ // on va iterer sur les noeuds esclaves pour savoir s'ils ont une trajectoire
+ // qui cree un contact avec les elements maitres, ou l'inverse, c-a-d s'ils sont
+ // dans de la matiere
+ LaLIST_io ::iterator iM,iMfin; // des itérator de travail
+
+// la mise à jour des boites d'encombrement n'est pas nécessaire car elle est faite dans l'algo avant le contact
+// *** si car ici on tient compte du déplacement et pas dans le prog principale
+// *** à voir si on ne peut pas le faire dans le prog princ, mais il faut faire un cas mini
+// car pour les points on se retrouve avec une boite de dim nulle !!
+
+ // mise à jour les boites d'encombrement des éléments frontière
+ {LaLIST_io ::iterator iM,iMfin;
+ for (int i=1;i<=nbmailMaitre;i++)
+ for (int j=1;j<= nb_zone;j++)
+ { iMfin=(t_listFront(i)(j)).end();
+ for (iM = (t_listFront(i)(j)).begin() ; iM != iMfin; iM++)
+ (*iM).Boite_encombrement_frontiere(TEMPS_t,dep_max_pratique); // au début pas de déplacement -> 0.
+ };
+ };
+
+ LaLIST ::iterator icont_inter; // sert pour la recherche de doublon
+// list ::iterator inumtesN; // " " "
+ for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
+ for (int j=1;j<=nb_zone;j++)
+ {const Tableau & tesc= tesctotal(intot)(j); // pour simplifier la notation:
+ const Tableau tesN_col = tesN_collant(intot)(j); // pour simplifier
+ int tesc_taille=tesc.Taille(); // tab des noeuds esclaves à considérer
+ for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
+ {Noeud* noee = tesc(inesc); // pour simplifier
+ int num_mail_noe_esclave = noee->Num_Mail();
+ int n_noee = noee->Num_noeud();
+ {int nb_contact=0; //au début pas de contact pour le noeud (pour gérer les doublons en contact)
+
+// const Coordonnee& pt_esc = noee->Coord2(); // position du noeud esclave
+ const Coordonnee pt_esc = noee->Coord2(); // position du noeud esclave
+ for (int jlf=1;jlf<=nbmailMaitre;jlf++) // boucle sur les maillages maitres
+ {LaLIST_io & t_listFront_jlf_j = t_listFront(jlf)(j);
+ iMfin= t_listFront_jlf_j.end();
+ for (iM = t_listFront_jlf_j.begin() ; iM != iMfin; iM++) // boucle sur les front
+ {
+ std::map::iterator > >& tesN_encontact_ii = tesN_encontact(num_mail_noe_esclave);
+ // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
+ // car autrement on crée automatiquement une liste avec un élément vide
+ std::map::iterator > >::iterator it_liste;
+ bool a_considerer = true; // init par défaut
+ if (tesN_encontact_ii.find(noee) != tesN_encontact_ii.end())
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[noee];
+ LaLIST < LaLIST::iterator >::iterator pl,plfin=list_tesN.end();
+ nb_contact = list_tesN.size();
+ for (pl = list_tesN.begin();pl != plfin;pl++)
+ {ElContact& elc = (*(*pl));
+ if ( elc.Elfront()->MemeOrigine(*iM))
+ {a_considerer=false;break;}
+ };
+ };
+
+ // donc on ne continue que si la face n'est pas déjà en contact avec le noeud
+ if (a_considerer)
+ {// on regarde si le noeud esclave est dans la boite d'encombrement de l'élément frontière
+ Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
+ // dans le cas où l'élément et le noeud appartienne au même maillage, on est
+ // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
+ // qui ne contiennent pas le noeud esclave
+ if (elem.Num_maillage() == num_mail_noe_esclave)
+ { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(n_noee); // pour simplifier
+ if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
+ break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
+ };
+
+ // ---- finalement on ne va pas considérer le point frontière comme particulier ---
+ // du coup, il ne sera jamais pris en compte et on
+ // bool dans_la_boite=false; // init
+ // // on prend en compte le cas particulier de frontière point
+ // if ((*iM)->Eleme()->Type_geom_front() == POINT_G)
+ // // on utilise la boite d'encombrement de l'élément car pour l'instant
+ // // je ne vois pas de solution plus pertinente
+ // // bool In_boite_emcombrement_elem(const Coordonnee& M,double depass = 0.)
+ // { dans_la_boite = elem.In_boite_emcombrement_elem(pt_esc);}
+ // else // sinon c'est le cas normal, on test la boite de la frontière
+ // { dans_la_boite = (*iM)->In_boite_emcombrement_front(pt_esc);};
+ // if (dans_la_boite)
+
+ bool plus_en_avant = false; // init
+ if (tesN_col(inesc)) // si collant: on projete systématiquement avec de grandes bornes
+ { if ((*iM).In_boite_emcombrement_front(pt_esc,dist_max))
+ plus_en_avant = true;
+ }
+ else if ((*iM).In_boite_emcombrement_front(pt_esc)) // cas non collant
+ { plus_en_avant = true;};
+
+ if (plus_en_avant)
+ // on teste alors plus précisemment
+ {// constitution d'un element de contact intermediaire
+ ElContact elcont(&(*iM),tesc(inesc),fct_nD_contact,tesN_col(inesc));
+ elcont.Num_zone_contact()=j; // affectation du numéro de zone
+ // calcul du contact, et translation (éventuelle) du noeud sur la surface si le contact existe
+ // bool ret = elcont.Contact(indice);
+ bool init_inter = true; // on est en phase d'initialisation
+////----debug
+//{if ((elcont.Esclave()->Num_noeud() == 12)
+// && ((*iM).Num_frontiere() == 1) && (elem.Num_elt()== 3130))
+// { cout << "\n debug : frontiere 1 de l'element 3130";}
+//}
+////----fin debug
+ bool ret = elcont.Contact(init_inter);
+ if (niveau_commentaire_contact > 5)
+ { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n recherche du contact entre noeud " << elcont.Esclave()->Num_noeud()
+ << " du maillage " << elcont.Esclave()->Num_Mail()
+ << " et frontiere " << (*iM).Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem;
+ if (ret) cout << "\n --> contact trouve ";
+ else cout << "\n --> pas de contact ";
+ if ((niveau_commentaire_contact > 6)
+ && ((*iM).In_boite_emcombrement_front(pt_esc))
+ )
+ {Noeud* noeud = tesc(inesc);
+ // --- sortie d'info pour vérifier l'appartenance à la boite ou non
+ cout << ", coordonnee noeud esclave : " ; noeud->Coord2().Affiche();
+ cout << "\n boite d'encombrement de l'element qui contient la frontiere:\n mini -> ";
+ elem.RecupBoite_encombre_element().Premier().Affiche();
+ cout << " maxi -> ";
+ elem.RecupBoite_encombre_element().Second().Affiche();
+ cout << "\n boite d'encombrement de la frontiere:\n mini -> ";
+ (*iM).Encom_mini_FR().Affiche();
+ cout << " maxi -> ";
+ (*iM).Encom_maxi_FR().Affiche();
+ };
+ cout << endl;
+ };
+
+ if (ret)
+ //sauvegarde éventuelle de l'element contact
+ {// on regarde s'il n'y a pas un autre élément de contact avec le même noeud
+ if (nb_contact == 0)
+ { // c'est le premier élément en contact, on l'enregistre
+ listContact.push_front(elcont);
+ retour = true;
+ listContact_nouveau_tatdt.push_front(listContact.begin()); // mémorisation
+ // et ajout dans la liste associé au noeud esclave
+ tesN_encontact_ii[noee].push_front(listContact.begin());
+ nb_contact_actif++ ; // a priori le contact est actif
+ nb_contact++;
+ if (niveau_commentaire_contact > 3)
+ { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\ncontact entre noeud " ;
+ if (tesN_col(inesc)) cout << " collant ";
+ cout << elcont.Esclave()->Num_noeud()
+ << " du maillage " << elcont.Esclave()->Num_Mail()
+ << " et frontiere " << (*iM).Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << "(zone"< 4)
+ {cout << "\n pt intersection: " << elcont.Point_intersection() ;
+ elcont.Elfront()->Affiche();
+ cout << flush;
+ };
+ // -- debug
+ // cout << "\n elem " << elem.Num_elt() << " maillage " << elem.Num_maillage() << " frontiere N= " ;
+ // for (int i=1;i<= (elcont.TabNoeud()).Taille();i++) cout << (elcont.TabNoeud())(i)->Num_noeud() << " ";
+ // cout << "\n boite "; elcont.Elfront()->Encom_mini_FR().Affiche(); elcont.Elfront()->Encom_maxi_FR().Affiche();
+ // cout << "\n noeud esclave: " << elcont.Esclave()->Coord2();
+ // cout << " LesContacts::DefElemCont( " << endl;
+ //-- fin débug
+
+ };
+ }
+ else
+ { // on a déjà un élément en contact
+ // on peut alors utiliser une ref sur l'élément de la map, sans craindre d'en créer
+ // un nouveau
+ LaLIST < LaLIST::iterator >::iterator pl =
+ tesN_encontact_ii[noee].begin(); // le pointeur du premier de la liste
+ ElContact& elc = (*(*pl));
+ // on va retenir l'élément dont le point de contact est le plus proche du point à t
+ //***: on retient ici le plus proche, mais dans nouveau on gardera tous les contacts
+ // ici il s'agit essentiellement de l'initialisation (à voir ensuite si c'est tenable !)
+ // --> permet aussi de coller sur un élément bien déterminé, s'il s'agit d'un collage
+ if ((elcont.Point_intersection()-pt_esc).Norme()
+ < (elc.Point_intersection()-pt_esc).Norme())
+ {// cas où le nouvel élément en contact est plus proche que celui enregistré
+ listContact_efface_tatdt.push_front(elc); // mémorise
+
+ // il faut utiliser erase et non remove car il n'y a pas d'opérateur =
+ // pour les éléments de contact
+ listContact.erase(*pl); // on efface l'ancien
+ listContact_nouveau_tatdt.remove(*pl);
+ // il faut supprimer dans tesN_encontact
+ tesN_encontact_ii[noee].erase(pl);
+ // puis on met le nouveau
+ listContact.push_front(elcont);
+ retour = true;
+ listContact_nouveau_tatdt.push_front(listContact.begin());
+ tesN_encontact_ii[noee].push_front(listContact.begin());
+ // NB: on ne modifie pas le nb_contact_actif car on a supprimé un et remis un autre
+ // on n'intervient pas sur tesN_encontact, car ça ne change pas
+ if (niveau_commentaire_contact >= 4)
+ { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n --- changement d'element en contact ---";
+ cout << "\ncontact entre noeud " ;
+ if (tesN_col(inesc)) cout << " collant ";
+ cout << elcont.Esclave()->Num_noeud()
+ << " du maillage " << elcont.Esclave()->Num_Mail()
+ << " et frontiere " << (*iM).Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << "(zone"< 2) // ==> LesContacts::
+ { cout << "\n apres Def Elem Cont: "<< listContact.size() << " elem contact ";
+ if ( listContact_nouveau_tatdt.size())
+ cout <<", "<< listContact_nouveau_tatdt.size() << " nouveau(x) ";
+ if (listContact_efface_tatdt.size())
+ cout <<", "<ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ int nb_zone = MaX(1,nom_ref_zone_contact.size());
+
+ // on sauvegarde la liste au départ
+ int taille_list_contact_nouveau_au_debut = listContact_nouveau_tatdt.size();
+
+ if (niveau_commentaire_contact > 3)
+// if (max(ParaGlob::NiveauImpression(),niveau_commentaire_contact)> 4)
+ cout << "\n ==> LesContacts::Nouveau: temps= " << ParaGlob::Variables_de_temps().TempsCourant();
+ // on montre les noeuds actuellement en contact
+ if (niveau_commentaire_contact > 4)
+ {cout << "\n >> bilan des noeud(s) actuellement en contact: ";
+ for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
+ for (int j=1;j<= nb_zone;j++)
+ {const Tableau & tesc= tesctotal(intot)(j); // pout simplifier la notation
+ const Tableau tesN_col = tesN_collant(intot)(j); // pour simplifier
+ int tesc_taille=tesc.Taille();
+ for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
+ {if (niveau_commentaire_contact > 5)
+ { Noeud* no = tesc(inesc);
+ int n_noee = no->Num_noeud();
+ int num_mail_noe_esclave = no->Num_Mail();
+ // if (no->Num_noeud()==495)
+ cout << "\n noeud " << no->Num_noeud() << " du maillage " << no->Num_Mail();
+ cout << " coord2= "; no->Coord2().Affiche_1(cout);
+// #ifdef MISE_AU_POINT
+// if (tesN_encontact(num_mail_noe_esclave).find(no)
+// == tesN_encontact(num_mail_noe_esclave).end() )
+// { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
+// << n_noee << " du maillage " << num_mail_noe_esclave
+// << " la suite n'est pas possible "
+// << " LesContacts::Nouveau(.. \n";
+// tempsContact.Arret_du_comptage(); // fin cpu
+// Sortie(1);
+// };
+// #endif
+ std::map::iterator > >& tesN_encontact_ii = tesN_encontact(num_mail_noe_esclave);
+ // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
+ // car autrement on crée automatiquement une liste avec un élément vide
+ std::map::iterator > >::iterator it_liste;
+ if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[no];
+ LaLIST < LaLIST::iterator >::iterator pl,plfin=list_tesN.end();
+ cout << "\n --> noeud actuellement en contact ";
+ if (tesN_collant(num_mail_noe_esclave)(j)(inesc)) cout << " collant ";
+ }
+ else {cout << "\n --> noeud actuellement pas en contact ";};
+ cout << flush;
+ };
+ };
+ };
+ };
+ // on met à jour les boites des éléments qui contiennent les frontières
+ Mise_a_jour_boite_encombrement_element_contenant_front();
+ // on met à jour le déplacement maxi toléré pour la classe ElContact
+ double coef_mult_dep_max = 3.; // comme un noeud peut se déplacer de dep_max et que l'on
+ double dep_max_pratique = coef_mult_dep_max * dep_max;
+ // peut avoir la cible "et" le noeud qui se déplace de dep_max, on doit considérer 2*dep_max
+ // pour être sûr, on considère 3 fois
+ ElContact::Change_dep_max(dep_max_pratique);
+ // --- 1) on va tout d'abord parcourir les éléments inactifs et regarder s'ils sont en contact
+ // si oui on les valide, sinon on les supprimes. Il faut le faire avant de prospecter car
+ // ces éléments inactifs ne vont pas être pris en compte car tesN_encontact(num_mail_noe_esclave)(inesc) = 0
+ // mais ils pourraient redevenir actifs, dans ce cas on aurait un noeud avec deux contacts
+ { // ++ encapsulage
+ LaLIST ::iterator iE ;
+ // on met .end(), car cette borne peut changer au gré des suppression
+ for (iE = listContact.begin(); iE != listContact.end(); iE++)
+ if (!((*iE).Actif()) // on intervient si le contact est déclaré inactif
+ && !((*iE).Collant()) // et si ce n'est pas collant: si collant, on ne change rien
+ )
+ { LaLIST ::iterator iiE = iE;
+ if ((*iE).Contact())
+ { // on valide si le contact est ok
+ int num_mail = (*iE).Esclave()->Num_Mail();
+ int num_noeud = (*iE).Esclave()->Num_noeud();
+// tesN_encontact(num_mail)(num_noeud) += 1; // mise à jour de l'indicateur
+ (*iE).Met_actif();
+ nb_contact_actif++;
+ if (niveau_commentaire_contact > 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\nreactivation (dans newcontact) contact entre noeud " << (*iiE).Esclave()->Num_noeud()
+ << " du maillage " << (*iiE).Esclave()->Num_Mail()
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+ };
+ }
+ else
+ { // sinon on supprime car il n'y a pas de contact
+ iE--; // pointe sur le precedent element
+ int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
+ int num_noeud = (*iiE).Esclave()->Num_noeud();
+ if (niveau_commentaire_contact > 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\neffacement contact (dans newcontact) entre noeud " << num_noeud
+ << " du maillage " << num_mail_esclave
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+ };
+ listContact_efface_tatdt.push_front(*iiE); // mémorise
+ #ifdef MISE_AU_POINT
+ if (tesN_encontact((*iiE).Esclave()->Num_Mail()).find((*iiE).Esclave())
+ == tesN_encontact((*iiE).Esclave()->Num_Mail()).end() )
+ { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
+ << (*iiE).Esclave()->Num_noeud()
+ << " du maillage " << (*iiE).Esclave()->Num_Mail()
+ << " la suite n'est pas possible "
+ << " LesContacts::Nouveau(.. \n";
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ #endif
+ LaLIST < LaLIST::iterator > & list_tesN
+ = tesN_encontact((*iiE).Esclave()->Num_Mail())[(*iiE).Esclave()];
+// tesN_encontact(num_mail_esclave)(num_noeud).remove(iiE);
+ list_tesN.remove(iiE);
+ listContact.erase(iiE); // efface l'element
+ // on ne change pas nb_contact_actif car on ne supprime que des inactifs
+ };
+ };
+ }; // ++ fin encapsulage
+ // --fin 1)
+
+ // on va iterer sur les noeuds esclaves pour savoir s'ils ont une trajectoire
+ // qui cree un contact avec les elements maitres, ou l'inverse, c-a-d s'ils sont
+ // dans de la matiere
+ bool retour = false; // init du retour
+ LaLIST_io ::iterator iM,iMfin;
+ LaLIST ::iterator icont_inter; // sert pour la recherche de doublon
+ list ::iterator inumtesN; // " " "
+ for (int jjf=1;jjf<=nbmailMaitre;jjf++)
+ for (int j=1;j<= nb_zone;j++)
+ { iMfin=(t_listFront(jjf)(j)).end();
+ // tout d'abord on met à jour les boites d'encombrement des éléments frontière
+ for (iM = (t_listFront(jjf)(j)).begin() ; iM != iMfin; iM++)
+ (*iM).Boite_encombrement_frontiere(TEMPS_tdt,dep_max);
+ };
+ for (int intot = 1;intot<= nb_mail_Esclave;intot++) // boucle sur les maillages esclaves
+ {for (int j=1;j<= nb_zone;j++)
+ {const Tableau & tesc= tesctotal(intot)(j); // pout simplifier la notation
+ const Tableau tesN_col = tesN_collant(intot)(j); // pour simplifier
+ int tesc_taille=tesc.Taille();
+ for (int inesc = 1;inesc<= tesc_taille;inesc++) // boucle sur les noeuds esclaves
+ // si le noeud est collant on ne fait rien
+ {if (!tesN_col(inesc))
+
+ {Noeud* no = tesc(inesc);
+ int n_noee = no->Num_noeud();
+ int num_mail_noe_esclave = no->Num_Mail();
+/* / #ifdef MISE_AU_POINT
+// if (tesN_encontact(num_mail_noe_esclave).find(no)
+// == tesN_encontact(num_mail_noe_esclave).end() )
+// { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
+// << n_noee << " du maillage " << num_mail_noe_esclave
+// << " la suite n'est pas possible "
+// << " LesContacts::Nouveau(.. \n";
+// tempsContact.Arret_du_comptage(); // fin cpu
+// Sortie(1);
+// };
+// #endif */
+ std::map::iterator > >& tesN_encontact_ii
+ = tesN_encontact(num_mail_noe_esclave);
+ // on regarde si la liste existe, si oui on peut tester les membres sinon, on ne fait rien
+ // car autrement on crée automatiquement une liste avec un élément vide
+ std::map::iterator > >::iterator it_liste;
+ int nb_contact=0;
+ if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[no];
+ LaLIST < LaLIST::iterator >::iterator pl,plfin=list_tesN.end();
+ nb_contact = list_tesN.size();
+ };
+ if (niveau_commentaire_contact > 5)
+ { cout << "\n (re) examen eventuel : contact du noeud " << n_noee << " du maillage " << num_mail_noe_esclave;
+ cout << " coord2= "; no->Coord2().Affiche_1(cout);
+ if (niveau_commentaire_contact > 5)
+ {cout << " num_mail_dans_contact = " << num_mail_noe_esclave <<" inesc(num N local)= " << inesc
+// << "\n tesN_encontact= " << tesN_encontact(num_mail_noe_esclave)(n_noee).size()
+ << "\n tesN_encontact= " << nb_contact
+ << " contacts enregistres";
+ };
+ // on dit si un des contacts est actif
+ int actif = 0;
+ if (nb_contact)
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[no];
+ LaLIST < LaLIST::iterator >::iterator il, ilfin = list_tesN.end();
+ for (il = list_tesN.begin();il != ilfin; il++)
+ if ( (*(*il)).Actif() )
+ actif++;
+ if (actif)
+ {cout << "\n noeud actuellement en contact dans " << actif << " element(s) ";
+ if (tesN_collant(num_mail_noe_esclave)(j)(inesc)) cout << " collant ";
+ }
+ else cout << "\n noeud actuellement pas en contact ";
+ int icont = 1;
+ for (il = list_tesN.begin();il != ilfin; il++,icont++)
+ {Front* elfront = (*(*il)).Elfront();
+ Element * elem = elfront->PtEI(); // l'element qui contiend la frontiere
+ cout << "\n elem_contact: "<Num_frontiere()
+ << " de l'element " << elem->Geometrie() << " : " << elfront->PtEI()->Num_elt()
+ << ", type: " << Nom_type_geom(elfront->Eleme_const()->Type_geom_front())
+ << " du maillage :" << elfront->PtEI()->Num_maillage();
+ };
+ };
+// il y a un pb, car un noeud pourrait-être collant pour une zone et non collant pour une autre
+// ce n'est peut-être pas un pb, mais il faudra peut-être avoir le niveau de zone en plus dans tesN_encontact ??
+// cout << endl;
+ };
+
+ {
+ Coordonnee pt_esc = no->Coord2(); // position du noeud esclave
+ // maintenant on regarde les frontieres maitres
+ int num_frontiere=1; // pour le debug
+ for (int jlf=1;jlf<=nbmailMaitre;jlf++) // boucle sur les maillages maîtres
+ {LaLIST_io & t_listFront_jlf_j = t_listFront(jlf)(j);
+ iMfin= t_listFront_jlf_j.end();
+ for (iM = t_listFront_jlf_j.begin() ; iM != iMfin; iM++,num_frontiere++) // boucle sur les front maitres
+ // on parcours les elements maitres de la zone
+ // si le noeud esclave est déjà en contact avec la frontière ce n'est pas la peine de tester
+ {// donc on passe en revue les éléments en contact
+
+ bool a_considerer = true; // init par défaut
+ if (tesN_encontact_ii.find(no) != tesN_encontact_ii.end())
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[no];
+ LaLIST < LaLIST::iterator >::iterator pl,plfin=list_tesN.end();
+ for (pl = list_tesN.begin();pl != plfin;pl++)
+ {ElContact& elc = (*(*pl));
+ Front& elfront = (*iM);
+ Front* eltest = elc.Elfront();
+ if (eltest->MemeOrigine(elfront) )
+ {a_considerer=false;break;}
+ };
+ };
+ // donc on ne continue que si la face n'est pas déjà en contact avec le noeud
+ if (a_considerer)
+ {// on regarde si le noeud esclave est dans la boite d'encombrement de l'élément
+ // qui contient l'élément frontière (car l'élément frontière à une épaisseur nulle!)
+ Element & elem = *((*iM).PtEI()); // l'element qui contiend la frontiere
+ Front& elfront = (*iM);
+ if (niveau_commentaire_contact > 5)
+ {// --- sortie d'info pour vérifier l'appartenance à la boite ou non
+ cout << "\n rappel: coordonnee noeud esclave : " ; no->Coord2().Affiche_1(cout);
+ cout << "\n boite d'encombrement de l'element maitre qui contient la frontiere:\n mini -> ";
+ elem.RecupBoite_encombre_element().Premier().Affiche();
+ cout << " maxi -> ";
+ elem.RecupBoite_encombre_element().Second().Affiche();
+ };
+
+ // dans le cas où l'élément et le noeud appartienne au même maillage, on est
+ // dans le cas d'un auto-contact. Dans ce cas on ne considère que les éléments
+ // qui ne contiennent pas le noeud esclave
+
+ if (elem.Num_maillage() == num_mail_noe_esclave)
+ { List_io < Element* > indice_m = (*indice(num_mail_noe_esclave))(n_noee); // pour simplifier
+ if (find(indice_m.begin(),indice_m.end(),&elem) != indice_m.end())
+ break; // on arrête la boucle si on trouve l'élément parmi ceux contenant le noeud
+ };
+
+ if (niveau_commentaire_contact > 5)
+ { cout << "\n frontiere: " << elfront.Num_frontiere() << " (nb loc: "<Type_geom_front())
+ << " de l'element " << elem.Geometrie() << " : "
+ << elfront.PtEI()->Num_elt()
+ << " du maillage :"
+ << elfront.PtEI()->Num_maillage() ;
+ };
+
+ if (elem.In_boite_emcombrement_elem(pt_esc,dep_max_pratique))
+ // on teste alors plus précisemment
+ // on regarde si cela pourrait conduire à un élément de contact identique
+ // à un élément que l'on vient juste d'effacer, si oui, on ne crée pas d'élément et
+ // on attend un prochain incrément, si effectivement l'élément doit se créer, il sera alors créé
+ {LaLIST ::iterator ila,ilafin=listContact_efface_tatdt.end();
+ bool vraiment_nouveau_element=true; // par défaut
+ for (ila = listContact_efface_tatdt.begin();ila != ilafin;ila++)
+ { if (((*ila).Esclave()->Num_noeud() == n_noee)
+ && ((*((*ila).Elfront()->Eleme())) == (*((*iM).Eleme())))
+ && ((*ila).Esclave()->Num_Mail() == num_mail_noe_esclave))
+ { vraiment_nouveau_element = false; break;};
+ };
+
+ if (niveau_commentaire_contact > 5)
+ {//cout << "\n 2debug LesContacts::Nouveau( " ;
+ LaLIST ::iterator ila,ilafin=listContact_efface_tatdt.end();
+ for (ila = listContact_efface_tatdt.begin();ila != ilafin;ila++)
+ { cout << "\n " << n_noee << " " << (*ila).Esclave()->Num_noeud()
+ << " " ;
+ (*ila).Elfront()->Affiche();
+ (*iM).Affiche();
+ cout << "\n ((*ila).Esclave()->Num_noeud() == noee->Num_noeud()) "
+ << ((*ila).Esclave()->Num_noeud() == n_noee);
+ cout << "\n ((*((*ila).Elfront()->Eleme())) == (*((*iM)->Eleme()))) "
+ << ((*((*ila).Elfront()->Eleme())) == (*((*iM).Eleme())));
+ cout << "\n ((*ila).Esclave()->Num_Mail() == noee->Num_Mail()) "
+ << ((*ila).Esclave()->Num_Mail() == n_noee);
+ cout << "\n vraiment_nouveau_element= " << vraiment_nouveau_element << endl;
+ };
+ };
+ // on ne continue que si c'est un vrai nouvel élément
+ if (vraiment_nouveau_element)
+ { // on passe en revue les éléments de contact déjà existant associé
+ // et s'il y a déjà un élément qui correspond, on arête la création
+ bool creation = true; // init
+
+ if (nb_contact)
+ {LaLIST < LaLIST::iterator > & list_tesN = tesN_encontact_ii[no];
+ LaLIST < LaLIST::iterator >::iterator il, ilfin = list_tesN.end();
+ for (il = list_tesN.begin();il != ilfin; il++)
+ { ElContact& con = (*(*il));
+ if (con.Elfront()->MemeOrigine(elfront))
+ creation = false;
+ };
+ };
+ // on ne continue que s'il n'existe pas d'élément de contact du même type
+ if (creation)
+ { ElContact elcont(&(*iM),tesc(inesc),fct_nD_contact);
+ elcont.Num_zone_contact()=j; // affectation du numéro de zone
+
+ // vérification que l'on a bien les frontières bien connectées
+ if (niveau_commentaire_contact > 5)
+ { Front* elfront = elcont.Elfront();
+ cout << "\n examen plus precis: frontiere: " << elfront->Num_frontiere()
+ << ", type: " << Nom_type_geom(elfront->Eleme_const()->Type_geom_front())
+ << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
+ << elfront->PtEI()->Num_maillage() ;
+ if (niveau_commentaire_contact > 7)
+ elcont.Affiche();
+ };
+
+ // calcul du contact, et translation éventuelle du noeud sur la surface
+ // si le contact existe, ceci en fonction de la méthode de contact
+ bool ret = elcont.Contact();
+ if (ret)
+ //sauvegarde éventuelle de l'element contact
+ { listContact.push_front(elcont);
+ //numtesN.push_front(TroisEntiers(num_mail_noe_esclave,j,n_noee));
+ tesN_encontact_ii[no].push_front(listContact.begin());
+ listContact_nouveau_tatdt.push_front(listContact.begin());
+ nb_contact_actif++; // à ce stade le nouveau contact est actif
+ retour=true; // on valide le retour
+ if (niveau_commentaire_contact > 3)
+ { int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n newcontact entre noeud " ;
+ if (tesN_col(inesc)) cout << " collant ";
+ cout << elcont.Esclave()->Num_noeud()
+ << " du maillage " << elcont.Esclave()->Num_Mail()
+ << " et frontiere " << (*iM).Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << flush;
+ };
+ }
+ else
+ { if (niveau_commentaire_contact > 5)
+ cout << " --> pas de contact " ;
+ } ;
+
+ // { listContact.push_back(elcont);numtesN.push_back(DeuxEntiers(intot,inesc));
+ // if (niveau_commentaire_contact >= 6)
+ // { Enum_type_geom type_front; Element & elem = *elcont.Elfront()->PtEI();
+ // int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ // cout << "\nnewcontact entre noeud " << elcont.Esclave()->Num_noeud()
+ // << " du maillage " << elcont.Esclave()->Num_Mail()
+ // << " et frontiere " << (*iM)->Num_frontiere()
+ // << " de l'element " << elem.Num_elt() << " du maillage "
+ // << num_mail_elem << flush;
+ // }
+ // retour = true;
+ // break; // on arrête la boucle sur les fronts car on a trouvé un contact
+
+ }; // fin du test if creation
+ // sinon il n'y a pas de contact
+ } // -- fin du test sur examen if (vraiment_nouveau_element)
+ }; //-- fin du test sur la boite_encombrement
+ }; // -- fin du test : if (a_considerer)
+ }; // -- boucle sur iM
+ }; // -- boucle sur jlf
+ }; // -- fin du test tesN_encontact(intot)(inesc)
+ } //-- fin du test non collant: if (!tesN_col(inesc))
+ };// -- boucle sur inesc
+ };// -- boucle sur intot
+ }// -- fin de la boucle sur les zones for (int j=1;j<= nb_zone;j++)
+ if (niveau_commentaire_contact > 3)
+ { cout << "\nbilan: "<< listContact.size() << " elem contact ";
+ if ( listContact_nouveau_tatdt.size())
+ cout <<", "<< (listContact_nouveau_tatdt.size()-taille_list_contact_nouveau_au_debut)
+ << " nouveau(x) ";
+ if (listContact_efface_tatdt.size())
+ cout <<", "<::iterator iE ;
+// list ::iterator iden = numtesN.begin();
+ // on met .end(), car cette borne peut changer au gré des suppressions
+ for (iE = listContact.begin(); iE != listContact.end(); iE++)//,iden++)
+ {if (!((*iE).Actif()) // on intervient si le contact est déclaré inactif
+ && ((*iE).Collant()) // et si c'est collant: ce n'est pas normal, on le remet actif
+ )
+ {(*iE).Met_actif(); // on valide l'activation
+ nb_contact_actif++;
+ }
+ else if (!((*iE).Actif()) // on intervient si le contact est déclaré inactif
+ && !((*iE).Collant()) // et si ce n'est pas collant: si collant, on ne change rien
+ )
+ { LaLIST ::iterator iiE = iE;
+// list ::iterator iiden = iden;
+ int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
+ int num_noeud = (*iiE).Esclave()->Num_noeud();
+ if (niveau_commentaire_contact > 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\neffacement contact entre noeud " << num_noeud
+ << " du maillage " << num_mail_esclave
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+ };
+ iE--; // pointe sur le precedent element
+ listContact_efface_tatdt.push_front(*iiE);
+ #ifdef MISE_AU_POINT
+ if (tesN_encontact(num_mail_esclave).find((*iiE).Esclave())
+ == tesN_encontact(num_mail_esclave).end() )
+ { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
+ << (*iiE).Esclave()->Num_noeud() << " du maillage " << num_mail_esclave
+ << " la suite n'est pas possible "
+ << " LesContacts::SuppressionDefinitiveElemInactif(.. \n";
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ #endif
+ LaLIST < LaLIST::iterator > & list_tesN
+ = tesN_encontact(num_mail_esclave)[(*iiE).Esclave()];
+ list_tesN.remove(iiE);
+// tesN_encontact(num_mail_esclave)(num_noeud).remove(iiE); // mise à jour de l'indicateur
+ listContact.erase(iiE); // efface l'element
+ nb_effacement++;
+ // on ne change pas nb_contact_actif car on ne supprime que des inactifs
+ change = true;
+// iden--;
+// numtesN.erase(iiden);
+ }
+//**** j'ai l'impression que la ligne qui suit ne sert à rien, car le if précédent était uniquement pour les inactifs, donc si on va à la ligne qui suit
+// c'est que l'élément est actif, donc cela ne sert à rien de le réactiver ???? ceci dit cela ne génère pas une erreur a priori
+ else {(*iE).Met_actif();}; // on valide l'activation
+ };
+ // info
+ if (niveau_commentaire_contact > 2)
+ { if (nb_effacement)
+ cout << "\n sup: "<< nb_effacement << " effacement(s) definitif(s) de contact ";
+ };
+ if ((niveau_commentaire_contact > 6) && (nb_effacement==0))
+ cout << " aucun effacement ";
+
+ tempsContact.Arret_du_comptage(); // fin cpu
+ // retour du tableau
+ return change;
+};
+
+// relachement des noeuds collés
+// ramène true s'il y a des noeuds qui ont été relachés
+bool LesContacts::RelachementNoeudcolle()
+{
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact > 6)
+ cout << "\n -- LesContacts::RelachementNoeudcolle(): ";
+ bool change = false;
+// return change; //------- pour le débug
+ LaLIST ::iterator iE ;
+// list ::iterator iden = numtesN.begin();
+ // on met .end(), car cette borne peut changer au gré des suppression
+ for (iE = listContact.begin(); iE != listContact.end(); iE++)//,iden++)
+ // on ne test que les éléments actifs, pour lesquels les calculs sont à jour
+ if ( ((*iE).Actif()) // on intervient si le contact est déclaré actif
+ && !((*iE).Collant()) // et si ce n'est pas collant: si collant, on ne fait rien
+ )
+ if ((*iE).Decol())
+ // le décolement est testé soit sur la réaction, qui a été calculée
+ // au pas précédent, ou soit sur une position géométrique en dehors d'une zone d'accostage.
+ //S'il y a décolement on ne doit plus tenir compte du contact et donc on inactive l'élément de contact
+ { LaLIST ::iterator iiE = iE;
+// list ::iterator iiden = iden;
+ int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
+ int num_noeud = (*iiE).Esclave()->Num_noeud();
+ if (niveau_commentaire_contact >= 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\ninactivation (relachement) pour cause de decollement du contact"
+ << "\n entre noeud " << num_noeud
+ << " du maillage " << num_mail_esclave
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+////------ debug
+//{cout << "\n debug: LesContacts::RelachementNoeudcolle() ";
+// (*iE).Decol();
+//}
+//// ------- fin debug
+
+ };
+ nb_contact_actif--;
+ change = true;
+ (*iE).Met_Inactif();
+ };
+ if ((!change)&& (niveau_commentaire_contact > 6))
+ cout << " aucun noeud relache ";
+
+ tempsContact.Arret_du_comptage(); // fin cpu
+ // retour
+ return change;
+};
+
+// definition des conditions lineaires de contact
+// casAssemb : donne le cas d'assemblage a prendre en compte
+// et marquage des ddl imposé par le contact
+const Tableau & LesContacts::ConditionLin(const Nb_assemb& casAssemb)
+ {
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ // on crée des conditions linéaires dans le cas du type 1: contact cinématique
+ // mais aussi dans les autres cas pour l'optimisation de largeur de bande par exemple
+// if (ParaGlob::param->ParaAlgoControleActifs().ContactType() == 1)
+// definition du tableau
+// int tail = listContact.size();//(int) listContact.size();
+// tabCoLin.Change_taille(tail);
+ {Recalcul_Nb_contact_actif();
+ tabCoLin.Change_taille(nb_contact_actif);
+//cout << "\n nb actif pour condlin = " << nb_contact_actif;
+ // on boucle sur les elements de contact
+ int i=1;
+ LaLIST ::iterator iE,iEfin=listContact.end() ;
+ for (iE = listContact.begin(); iE != iEfin; iE++)
+ if ((*iE).Actif()) // on n'intervient que si le contact est actif
+ // appel de la fonction de construction de condition lineaire dans l'element de contact
+ {tabCoLin(i) = (*iE).ConditionLi(casAssemb.n);i++;
+//cout << " i="<Change_fixe(C.Tab_Enum()(1),false);
+ };
+ tempsContact.Arret_du_comptage(); // fin cpu
+ };
+
+// indique si les surfaces des maillages maîtres ont des déplacements fixés
+// c-a-d sont de type solide imposé
+// retourne true si les déplacements des maîtres sont imposés
+bool LesContacts::Maitres_avec_deplacement_imposer() const
+ { bool retour = true; // init par défaut
+// int nb_maitre = t_listFront.Taille(); // le nombre de maîtres
+ int dim = ParaGlob::Dimension();
+ int nb_zone = MaX(1,nom_ref_zone_contact.size());
+ // seule sont disponibles les zones de contact (restreintes éventuellement)
+ // on passe en revue tous les noeuds des frontières
+ for (int i=1; i<= nbmailMaitre;i++)
+ for (int j=1;j<= nb_zone;j++)
+ {LaLIST_io ::const_iterator il,ilfin = t_listFront(i)(j).end();
+ for (il = t_listFront(i)(j).begin(); il != ilfin; il++)
+ {const Tableau & tn = (*il).Eleme_const()->TabNoeud_const();
+ int nb_noe = tn.Taille();
+ for (int n = 1;n<= nb_noe;n++)
+ { const Noeud& noe = *tn(n); // pour simplifier
+ switch(dim)
+ {case 3: if (!(noe.Ddl_fixe(X3))) {retour=false; break;};
+ case 2: if (!(noe.Ddl_fixe(X2))) {retour=false; break;};
+ case 1: if (!(noe.Ddl_fixe(X1))) {retour=false; break;};
+ };
+ if (!retour) break;
+ };
+ if (!retour) break;
+ };
+ if (!retour) break;
+ };
+ // retour
+ return retour;
+ };
+
+
+// def de la largeur de bande des elements contacts
+// casAssemb : donne le cas d'assemblage a prendre en compte
+// les condi linéaires ne donnent pas des largeurs de bande sup et inf égales !!!
+// demi = la demi largeur de bande maxi ,
+// total = le maxi = la largeur sup + la largeur inf +1
+// cumule = la somme des maxis, ce qui donnera la largeur finale, due à des multiples multiplications: une par conditions linéaires
+// ceci dans le cas de la prise en compte par rotation (et uniquement dans ce cas)
+// = true : si la largeur de bande en noeud est supérieure à 1 (cas d'un contact avec une surface déformable)
+// = false : si non, ce qui signifie dans ce cas qu'il n'y a pas d'augmentation de la largeur
+// en noeud (cas d'un contact avec une surface rigide)
+bool LesContacts::Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb,int& cumule)
+ {
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ // dans le cas d'un contact avec surface déformable, le contact modifie la largeur de bande
+ demi = 0;
+ total = 0; // c'est le plus important, car la bande sup réelle est en général différente
+ // de la bande inf, mais ce qui sera utilisé pour le dimensionnement de la bande de la matrice
+ // c'est le total: inf + sup + 1 (le 1 est pour la diagonale, il ne sert à rien)
+ cumule = 0;
+ bool retour = false; // par défaut on se met dans le cas le plus simple : contact avec surface rigide
+ LaLIST ::iterator iE,iEfin=listContact.end();
+ int nb_Assemb = casAssemb.n; // récup du numéro d'assemblage
+//------ debug
+// cout << "\n LesContacts::Largeur_Bande ";
+// ------ fin debug
+ // on boucle sur les elements de contact
+ for ( iE = listContact.begin(); iE !=iEfin; iE++)
+ {
+//------ debug
+// (*iE).Affiche();
+// ------ fin debug
+
+ // on n'intervient que si le contact est actif et que ce n'est pas un contact solide déformable
+ if (((*iE).Actif()) && ((*iE).Cas_solide() == 0))
+ { //on boucle sur les noeuds de l'element de contact
+ const Tableau & tabnoeud = (*iE).TabNoeud();
+ int maxiPourLeContact=0; // stocke le maxi pour chaque condition linéaire
+ retour = true; // ici la largeur de bande en noeud est augmenté, car le noeud en contact
+ // est en relation avec des noeuds d'une surface déformable
+
+ for (int noe=1; noe<= tabnoeud.Taille();noe++)
+ for ( int no=noe+1; no<=tabnoeud.Taille();no++)
+ { Noeud & nne = *tabnoeud(noe);
+ Noeud & nno = *tabnoeud(no);
+ int di;
+ if (nne.PosiAssemb(nb_Assemb) >= nno.PosiAssemb(nb_Assemb))
+ di = nne.PosiAssemb(nb_Assemb) - nno.PosiAssemb(nb_Assemb)
+ + nne.NB_ddl_actif_casAssemb(nb_Assemb);
+ else
+ di = nno.PosiAssemb(nb_Assemb) - nne.PosiAssemb(nb_Assemb)
+ + nno.NB_ddl_actif_casAssemb(nb_Assemb);
+ if ( di > demi) demi = di;
+ if ( di > maxiPourLeContact) maxiPourLeContact = di;
+ if ( 2*di > total) total = 2*di;
+ };
+ cumule += maxiPourLeContact;
+ };
+ };
+ total += 1;
+ demi += 1;
+
+ tempsContact.Arret_du_comptage(); // fin cpu
+ // retour de l'indicateur
+ return retour;
+ };
+
+// actualisation du contact, on examine que les elements de contact, dont on
+// actualise la projection du noeud esclave en fonction de la position de l'element
+// maitre frontiere (mais la position finale du noeud n'est pas forcément changée, cela dépend du
+// modèle de contact (cinématique, pénalisation etc.)
+// ramène true si quelque chose à changé, false sinon
+// --- la suite est fausse, en particulier, on n'examine "que" les éléments actifs
+/* // dans le cas où la réaction est négative, en fonction de l'algorithme l'élément de contact est
+// inactivé, cependant tous les éléments de contact sont passés en revue (actif ou pas)
+*/
+bool LesContacts::Actualisation()
+ {
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ bool retour = false; // init par défaut
+ // on boucle sur les elements de contact
+ nb_contact_actif = 0; // init
+ int i;
+ LaLIST ::iterator iE,iEfin=listContact.end();
+
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact >= 7)
+ cout << "\n -- LesContacts::Actualisation: ";
+
+ for (i=1, iE = listContact.begin(); iE !=iEfin; iE++,i++)//,iden++)
+ // appel de la fonction d'actualisation de chaque element de contact
+ if ((*iE).Actif()) // on intervient si le contact est déclaré actif
+ // on intervient également si c'est collant, car il faut quand même actualiser
+ // le contact,
+ { bool test=false; // init
+/* --- suppression de tout le bloc qui suit car on ne passe plus par là donc c'est inutile de surcharger
+ bool decol=false;
+ // comme on étudie tous les éléments de contact, actif ou non, il faut distinguer le cas d'un noeud actif
+ // pour lequel la réaction a été calculée précédemment, du cas inactif, pour lequel il n'y a pas eu de calcul
+ // de réaction, donc on peut pas savoir
+// if ((*iE).Actif())
+// decol = (*iE).Decol(); // le décolement est testé sur la réaction, qui a été calculée
+ // au pas précédent. Donc, si cette réaction est positive, donc qu'il y a décolement on ne doit
+ // plus tenir compte du contact et donc on n'actualise pas la position
+ if (decol)
+ // cas ou il n'y a plus de contact due à un décollement
+ { LaLIST ::iterator iiE = iE;
+ int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
+ int num_noeud = (*iiE).Esclave()->Num_noeud();
+ if (niveau_commentaire_contact >= 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n force de collage => inactivation du contact entre noeud " << num_noeud
+ << " du maillage " << num_mail_esclave
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+ };
+ (*iiE).Met_Inactif(); // inactive l'élément
+ retour = true; // on signale le changement
+ }
+ else// cas ou on avait une force de contact compressive ou que l'élément est inactif
+ // mise à jour.
+
+*/
+ {
+/* ////debug
+//{Noeud* no = (*iE).Esclave();
+// if (no->Num_noeud()==394)
+// {cout << "\n debug LesContacts::Actualisation( , arrivee au noeud 394 ";
+// cout << " coord2= " << (*iE).Esclave()->Coord2();
+// (*iE).Point_intersection().Affiche();
+// };
+//};
+////// fin debug */
+ // Si le retour est négatif et que l'élément est actif, cela signifie que l'on sort d'une surface de contact,
+ test = (*iE).Actualisation();
+/* //debug
+//test = (*iE).Actualisation();
+//if (!test)
+//{cout << "\n debug LesContacts::Actualisation( ";
+// test = (*iE).Actualisation(); // on rappelle la fonction
+//};
+// fin debug */
+ if ((!test)
+ && !((*iE).Collant()) // si c'est collant, on maintient le contact arbitrairement
+ )
+ // cas ou il n'y a plus de contact, on inactive l'element de contact
+ { LaLIST ::iterator iiE = iE;
+ int num_mail_esclave = (*iiE).Esclave()->Num_Mail();
+ int num_noeud = (*iiE).Esclave()->Num_noeud();
+ if (niveau_commentaire_contact >= 3)
+ { Element & elem = *(*iiE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\ninactivation contact (les_contacts) pour cause de perte de contact"
+ << "\n entre noeud " << num_noeud
+ << " du maillage " << num_mail_esclave
+ << " et frontiere " << (*iiE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem << endl;
+ };
+ (*iiE).Met_Inactif(); // inactive l'élément
+ retour = true; // on signale le changement
+ }
+ else
+ { nb_contact_actif++;
+ if (niveau_commentaire_contact >= 7)
+ { Element & elem = *(*iE).Elfront()->PtEI();
+ int num_mail_elem = (elem.Tab_noeud())(1)->Num_Mail();
+ cout << "\n contact entre noeud "
+ << (*iE).Esclave()->Num_noeud()
+ << " du maillage " << (*iE).Esclave()->Num_Mail()
+ << " et frontiere " << (*iE).Elfront()->Num_frontiere()
+ << " de l'element " << elem.Num_elt() << " du maillage "
+ << num_mail_elem
+ << "\n nb_contact_actif= " << nb_contact_actif
+ << endl;
+ };
+ };
+ };
+ }
+ else
+ {nb_contact_actif++; }; // on sauvegarde l'activité
+ // retour
+ return retour;
+ tempsContact.Arret_du_comptage(); // fin cpu
+ };
+
+// ramène une liste de noeuds dont la position a été perturbé par le contact
+// (dépend du type de contact : ex cas contact = 4)
+// la liste passée en paramètre est supprimée et remplacée par la liste résultat
+void LesContacts::Liste_noeuds_position_changer(list & li_noe)
+ { tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ // récup du type de contact
+ int contact_type = ElContact::Recup_et_mise_a_jour_type_contact();
+ li_noe.clear(); // on vide la liste
+
+ if (contact_type== 4) // pour l'instant c'est le seul type de contact qui est concerné
+ { // on boucle sur les elements de contact
+ int i;
+ LaLIST ::iterator iE,iEfin=listContact.end();
+
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact >= 7)
+ cout << "\n -- LesContacts::Liste_noeuds_position_changer: ";
+
+ for (i=1, iE = listContact.begin(); iE !=iEfin; iE++,i++)//,iden++)
+ if ((*iE).Actif()) // on intervient si le contact est déclaré actif
+ {// récup du noeud esclave
+ Noeud* noe = (*iE).Esclave();
+ li_noe.push_back(noe);
+ };
+ };
+ tempsContact.Arret_du_comptage(); // fin cpu
+ };
+
+// calcul des reactions de contact et stockage des valeurs
+// solution : le vecteur residu
+// test d'un decollement eventuelle, pour un noeud en contact
+void LesContacts::CalculReaction(Vecteur& residu,bool& decol,const Nb_assemb& casAssemb
+ ,bool affiche)
+ {
+ tempsContact.Mise_en_route_du_comptage(); // def deb compt
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (niveau_commentaire_contact >= 7)
+ cout << "\n -- LesContacts::CalculReaction: ";
+ int nb_Assemb = casAssemb.n; // récup du numéro d'assemblage
+ // récup du type de contact
+ int contact_type = ElContact::Recup_et_mise_a_jour_type_contact();
+
+ // mise a dimension du tableau de stockage
+// tabReacCont.Change_taille((int)listContact.size());
+ // on recalcule le nombre de contact actif car c'est mal géré, je ne sais pas pourquoi et ou
+ Recalcul_Nb_contact_actif();
+ tabReacCont.Change_taille(nb_contact_actif);
+ int itab ; // indice du tableau
+ decol = false;
+ bool axi = false; // cas particulier de l'axi
+ if (ParaGlob::AxiSymetrie())
+ axi = true;
+
+ LaLIST ::iterator iE,iEfin = listContact.end();
+
+
+ // on boucle sur les elements de contact
+ for ( itab=1,iE = listContact.begin(); iE != iEfin; iE++)
+ {if ((*iE).Actif())
+ { Noeud* noe = (*iE).Esclave(); // le noeud esclave
+ int posi = noe->Pointeur_assemblage(X1,nb_Assemb); // position du ddl X1
+ #ifdef MISE_AU_POINT
+ if ( posi == -1 )
+ { cout << "\nErreur : ddl X1 "
+ << " inexistant pour le cas de charge " << nb_Assemb << '\n'
+ << " LesContacts::CalculReaction( (1)\n";
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ #endif
+ int dim = noe->Dimension(); // dimension
+ // dans le cas où on est en axi-symétrie, le vecteur réaction est en 2D car le calcul au niveau de l'équilibre
+ // global n'est fait qu'en x et y
+ // donc on ne peut récupérer que du x et du y
+ int nb_ddl_en_var = dim; // init
+ if (axi)
+ nb_ddl_en_var -= 1;
+ Coordonnee force(dim); // on dimensionne à dim au cas où
+ for (int i=1;i<=nb_ddl_en_var;i++)
+ // je crois qu'il faut un - pour la force (??) 20 avril 2018
+ force(i) = -residu(posi+i-1); // si le type de contact est de type 1 -> c'est la réaction
+ if ((contact_type==1)||(contact_type==3))
+ (*iE).Change_force(force); // mise à jour de la force dans l'élément de contact
+
+ if (niveau_commentaire_contact > 4)
+ {if ((contact_type==1)||(contact_type==3))
+ {cout << "\n LesContacts::CalculReaction >> Details: residu totale = contact + CL + F_int (noeud:" << noe->Num_noeud()
+ << " maillage:"<< noe->Num_Mail() << ")\nR=" << force << " gapTDT= " << (*iE).Gaptdt()
+ << "\n dont F_contact= "<< (*iE).Force_contact() ;
+ cout << "\n noeud: coor_tdt: "<Coord2() <<"\n delta: "<<(noe->Coord2()-noe->Coord1());
+ }
+ else if ((contact_type == 2) || (contact_type == 4)|| (contact_type == 41)|| (contact_type == 42))
+ {cout << "\n LesContacts::CalculReaction >> Details: F_contact (noeud:" << noe->Num_noeud()
+// 19 juin 2018 << " maillage:"<< noe->Num_Mail() << ")\nF=" << force << " gapTDT= " << (*iE).Gaptdt() ;
+ << " maillage:"<< noe->Num_Mail() << ")\nForce= " << (*iE).Force_contact()
+ << " gapTDT= " << (*iE).Gaptdt() ;
+ cout << "\n noeud: coor_tdt: "<Coord2() <<"\n delta: "<<(noe->Coord2()-noe->Coord1());
+ if (niveau_commentaire_contact > 7)
+ (*iE).Affiche();
+
+ }
+ else {cout << "\n *** erreur, cas de type de contact= " << contact_type << " pas encore pris en compte " ;
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ };
+ // on regarde si le noeud decolle
+ if ((*iE).Decol()) decol = true;
+ // puis les noeuds de l'element maitre
+//!!!!! il faudra prevoir un cas ou on ne sauvegarde pas les maitres
+
+ Tableau & tabNoeud = (*iE).Elfront()->Eleme()->TabNoeud(); // le tableau
+ // on cree un tableau de sauvegarde des forces
+ int tail = tabNoeud.Taille();
+ // Dans le cas du type 1 de contact, c'est le retour du résidu qui permet de construire des
+ // réaction, alors que dans le cas du type 2 c'est au contraire dans l'élément de contact
+ // que les grandeurs ont déjà été calculées
+ if ((contact_type==1)||(contact_type==3))
+ {Coordonnee ex(dim); // une position à la bonne dimmension
+ Tableau tabForce(tail,ex); // dimmensionnement du tableau avec alocation
+ for (int it=1;it<= tail;it++)
+ { posi = tabNoeud(it)->Pointeur_assemblage(X1,nb_Assemb) ; // position du ddl X1
+ #ifdef MISE_AU_POINT
+ if ( posi == -1 )
+ { cout << "\nErreur : ddl X1 "
+ << " inexistant pour le cas de charge " << nb_Assemb << '\n'
+ << " LesContacts::CalculReaction( (2)\n";
+ tempsContact.Arret_du_comptage(); // fin cpu
+ Sortie(1);
+ };
+ #endif
+ for (int i=1;i<=nb_ddl_en_var;i++)
+ tabForce(it)(i) = residu(posi+i-1); // la reaction
+ };
+ tabReacCont(itab) = ReactCont(noe,force,tabNoeud,tabForce);
+ }
+ else
+ {tabReacCont(itab) = ReactCont(noe,(*iE).Force_contact(),tabNoeud,(*iE).TabForce_cont());
+ };
+ itab++;
+ };
+ };
+ // affichage éventuelle de la force maxi de contact
+ Forces_contact_maxi(affiche);
+ // idem pour les gap N et T
+ Gap_contact_maxi(affiche);
+
+ tempsContact.Arret_du_comptage(); // fin cpu
+ };
+
+// affichage des reactions de contact sur la sortie
+void LesContacts::Affiche(ofstream& sort) const
+ { // on balaie le tableau de reaction
+ for (int i= 1; i<= tabReacCont.Taille();i++)
+ { ReactCont & R = tabReacCont(i);
+ sort << "\n================= noeud esclave ==================";
+ sort << "\nmaillage " << (R.noe)->Num_Mail()
+ <<", noeud " << (R.noe)->Num_noeud()
+ << ", force = " << R.force ;
+ sort << "\n---------------- noeuds de la frontiere maitre -------------";
+ int tail = R.tabNoeud.Taille();
+ for (int it=1;it<= tail;it++)
+ { Noeud & no = *(R.tabNoeud(it));
+ Coordonnee& coor = R.tabForce(it);
+ sort << "\nmaillage " << no.Num_Mail()
+ <<", noeud " << no.Num_noeud()
+ << ", force = " << coor << ", de norme =" << coor.Vect().Norme() ;
+ };
+ };
+ };
+
+// affichage à l'écran des informations liées au contact
+void LesContacts::Affiche() const
+ { cout << "\n ---- affichage des informations liees au contact --------";
+ cout << "\n 1) liste des elements en contact";
+ LaLIST ::const_iterator il,ilfin=listContact.end();
+ for (il=listContact.begin();il != ilfin; il++)
+ (*il).Affiche();
+ cout << "\n 2) reactions aux contact";
+ // on balaie le tableau de reaction
+ for (int i= 1; i<= tabReacCont.Taille();i++)
+ { ReactCont & R = tabReacCont(i);
+ cout << "\n================= noeud esclave ==================";
+ cout << "\nmaillage " << (R.noe)->Num_Mail()
+ <<", noeud " << (R.noe)->Num_noeud()
+ << ", force = " << R.force ;
+ cout << "\n---------------- noeuds de la frontiere maitre -------------";
+ int tail = R.tabNoeud.Taille();
+ for (int it=1;it<= tail;it++)
+ { Noeud & no = *(R.tabNoeud(it));
+ Coordonnee& coor = R.tabForce(i);
+ cout << "\nmaillage " << no.Num_Mail()
+ <<", noeud " << no.Num_noeud()
+ << ", force = " << coor << ", de norme =" << coor.Vect().Norme() ;
+ };
+ };
+ cout << "\n 3) liste des references de zones succeptibles d'entrer en contact";
+
+ list ::const_iterator ill,illfin=nom_ref_zone_contact.end();
+ cout << "\n";
+ for (ill=nom_ref_zone_contact.begin();ill != illfin; ill++)
+ { if ((*ill).nom1.length()) cout << " mail= " << (*ill).nom1 << " ";
+ cout << "ref de noeud esclave: " << (*ill).nom2;
+ if ((*ill).n ==1)
+ cout << " (contact collant) ";
+ cout << ", ";
+ if ((*ill).nom3.length()) cout << " mail= " << (*ill).nom3 << " ";
+ cout << "ref des frontieres maitres : " << (*ill).nom4;
+ };
+ };
+
+// affichage et definition interactive des commandes
+void LesContacts::Info_commande_LesContacts(UtilLecture & entreePrinc)
+{ ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
+ //On va proposer un menu
+ string rep=" ";
+ sort << "\n# --- les contact ------- ";
+ while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
+ {
+ try
+ {
+ cout << "\n -- definition de : --- "
+ << "\n (0 ou f) (fin) "
+ << "\n (1) auto_contact "
+ << "\n (2) zone particuliere de contact "
+ << "\n (3) contact solide-deformable "
+ << "\n (4) contact collant "
+ << "\n (5) contact collant avec suppression du gap"
+ << "\n (6 ou ? ) informations "
+ << "\n ";
+
+ // procédure de lecture avec prise en charge d'un retour chariot
+ rep = lect_return_defaut(false,"f");
+ if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
+ break;
+ int num = ChangeEntier(rep);
+ if (Minuscules(rep) == "?")
+ num = 6;
+ bool choix_valide=false;
+ if ((num >= 0)&&(num<=6))
+ { choix_valide=true; }
+ else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
+ << "\n redonnez une bonne valeur"
+ << "\n ou taper f ou 0 pour arreter le programme";
+ choix_valide=false;
+ }
+ string grandeur=" "; // init
+
+ switch (num)
+ { case 0: // sortie
+ { break;} // normalement cela a déjà été filtré avant
+ case 1: // auto_contact
+ { sort << "\n auto_contact \n";
+ sort << "\n#--------------------------------------------------------------------------------";
+ sort << "\n# definition du nombre de domaine esclave en auto-contat |";
+ sort << "\n#--------------------------------------------------------------------------------";
+ cout << "\n nombre de maillage en autocontact (un entier) ? ";
+ string nb_str;
+ //int nb =0;
+ nb_str = (int) lect_double();
+ if ((Minuscules(nb_str) == "f") || (Minuscules(nb_str) == "0"))// sortie directe
+ break;
+ int nb = ChangeEntier(nb_str);
+ cout << " nom lu = "<< nb_str << " c-a-d le nombre "<ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ while ( (strstr(entreePrinc.tablcar,"auto_contact")!=NULL)
+ || (strstr(entreePrinc.tablcar,"zone_contact")!=NULL)
+ || (strstr(entreePrinc.tablcar,"contact_solide_deformable")!=NULL)
+ || (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
+ || (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
+ )
+ {
+
+ // --- on examine le cas où il y a un marquage d'auto-contact
+ if (strstr(entreePrinc.tablcar,"auto_contact")!=NULL)
+ // cas ou l'on a des domaines esclaves en auto-contact, lecture du nombre
+ { entreePrinc.NouvelleDonnee();
+ if (niveau_commentaire_contact >= 4)
+ cout << " lecture du nombre de domaines esclaves en auto-contact " << endl;
+ *(entreePrinc.entree) >> nbmailautocontact; // lecture du nombre
+ if (niveau_commentaire_contact >= 5) cout << nbmailautocontact << endl;
+ if (niveau_commentaire_contact >= 4)
+ cout << " fin de la lecture du nombre de domaines esclaves en auto-contact " << endl;
+ entreePrinc.NouvelleDonnee(); // positionnement sur une nouvelle info
+ };
+ // --- cas des zones particulières de contact
+ if ( (strstr(entreePrinc.tablcar,"zone_contact")!=NULL)
+ || (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
+ || (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
+ )
+ {
+ int indic_glue = 0; // init de non glue a priori
+ if (strstr(entreePrinc.tablcar,"glue_contact_init_gap_zero")!=NULL)
+ {indic_glue = 2; }// cas particulier d'un contact collant avec suppression du gap
+ else if (strstr(entreePrinc.tablcar,"glue_contact")!=NULL)
+ {indic_glue = 1; }// cas particulier d'un contact collant
+
+ // lecture tant qu'il n'y a pas de nouveau mot clé
+ entreePrinc.NouvelleDonnee();
+ if (niveau_commentaire_contact >= 4) cout << " debut de la lecture des zones de contact possibles " << endl;
+ while (!motCle.SimotCle(entreePrinc.tablcar))
+ { // on lit 2 par deux: une ref de noeud + une ref de frontière
+ quatre_string_un_entier quatre_inter; // une grandeur de travail
+ quatre_inter.n = indic_glue; // on stocke la glue éventuelle
+ for (int nr=1;nr<=2;nr++)
+ {// on commence par regarder si le nom du maillage est définit pour la référence
+ string nom_ref; // variables de travail
+ string* nom_mail=NULL; string nom("");
+ if (strstr(entreePrinc.tablcar,"nom_mail=")!=NULL)
+ { *(entreePrinc.entree) >> nom >> nom; nom_mail = & nom;}
+ // lecture du nom d'une référence
+ *(entreePrinc.entree) >> nom_ref;
+ #ifdef ENLINUX
+ if ((entreePrinc.entree)->rdstate() == 0)
+ #else
+ if (((entreePrinc.entree)->rdstate() == 0)||((entreePrinc.entree)->eof()))
+ #endif
+ // pour mémoire ici on a
+ /* enum io_state
+ { badbit = 1<<0, // -> 1 dans rdstate()
+ eofbit = 1<<1, // -> 2
+ failbit = 1<<2, // -> 4
+ goodbit = 0 // -> O
+ };*/
+ // lecture normale, vérification que la référence existe bien
+ { if (!(lesRef.Existe(nom_ref,nom_mail)))
+ { cout << "\n erreur le nom de reference de zone de contact : " << nom_ref
+ << " , n'existe pas !!"
+ << "\n LesContacts::Lecture_zone_contact(..";
+ throw (UtilLecture::ErrNouvelleDonnee(-1));
+ Sortie (1);
+ }
+ else // enregistrement du nom de référence
+ { if (nr==1)
+ // premier passage on stocke
+ {quatre_inter.nom1=nom;quatre_inter.nom2=nom_ref;}
+ else // cas du deuxième passage on enregistre
+ {quatre_inter.nom3=nom;quatre_inter.nom4=nom_ref;
+ nom_ref_zone_contact.push_back(quatre_inter);
+ };
+// obsolète if (nom_mail != NULL) nom_mail = new string(nom);
+// nom_mail_ref_zone_contact.push_back(nom_mail);
+ }
+ #ifndef ENLINUX
+ if ((entreePrinc.entree)->eof()) // on arrive à la fin de la ligne
+ entreePrinc.NouvelleDonnee(); // lecture d'un nouvelle enregistrement
+ #endif
+ }
+ //sinon il y a un pb ou, l'on est à la fin de la ligne et on passe à l'enregistrement suivant
+ #ifdef ENLINUX
+ else if ((entreePrinc.entree)->fail())
+ // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
+ { entreePrinc.NouvelleDonnee(); } // lecture d'un nouvelle enregistrement
+ #endif
+ else // cas d'une erreur de lecture
+ { cout << "\n erreur de lecture inconnue au niveau des references de zone de contact";
+ entreePrinc.MessageBuffer("** LesContacts::Lecture_zone_contact(.. **");
+ Affiche();
+ throw (UtilLecture::ErrNouvelleDonnee(-1));
+ Sortie (1);
+ };
+ }; // -- fin for (int nr=1;nr<=2;nr++)
+ }; //-- fin du while (!motCle.SimotCle(entreePrinc.tablcar))
+ if (niveau_commentaire_contact >= 4) cout << " fin de la lecture des zones de contact " << endl;
+ };
+ // --- cas des contacts solide-deformable
+ if (strstr(entreePrinc.tablcar,"contact_solide_deformable")!=NULL)
+ { if (niveau_commentaire_contact >= 4) cout << " debut de la lecture des contacts solide-deformable " << endl;
+ string toto; // variables de travail
+ while (strstr(entreePrinc.tablcar,"fin_liste_des_couples_de_noms_solide_deformable")==NULL)
+// && (!motCle.SimotCle(entreePrinc.tablcar)))
+ { Deux_String ie; // une variable de travail
+ *(entreePrinc.entree) >> toto >> ie.nom1 >> toto >> ie.nom2;
+ cont_solide_defor.push_back(ie);
+ entreePrinc.NouvelleDonnee();
+ };
+ // on passe le mot clé de fin
+ entreePrinc.NouvelleDonnee();
+ if (niveau_commentaire_contact >= 4) cout << " fin de la lecture des contacts solide-deformable " << endl;
+ };
+ };
+};
+
+
+
diff --git a/contact/LesContacts.h b/contact/LesContacts.h
new file mode 100644
index 0000000..a24f5de
--- /dev/null
+++ b/contact/LesContacts.h
@@ -0,0 +1,456 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * 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
+#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"
+
+
+/// @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 la liste des éléments de contact
+ LaLIST & 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 > *> 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
+ //
+ const Tableau & ConditionLin(const Nb_assemb& casAssemb);
+
+ // 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 & 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)
+ 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.)
+ // dans le cas où la réaction est négative, en fonction de l'algorithme l'élément de contact est
+ // inactivé, cependant tous les éléments de contact sont passés en revue (actif ou pas)
+ // ramène true si quelque chose à changé, false sinon
+ bool Actualisation();
+
+ // 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 & 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) const;
+
+ // 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 Gap_contact_maxi(bool affiche) const;
+
+ // 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()const;
+
+ // 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(ofstream& 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
+ 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();
+
+ //------- temps cpu -----
+ // retourne temps cumulé pour imposer les CL imposées
+ const Temps_CPU_HZpp& Temps_cpu_Contact() const {return tempsContact;};
+
+ //----- lecture écriture de restart -----
+ // cas donne le niveau de sauvegarde
+ void Ecri_base_info_LesContacts(ofstream& 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
+ void Lec_base_info_LesContacts(ifstream& 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);
+
+ // 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& ,Loi_comp_abstraite::SaveResul * ,list& 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 ListeGrandeurs_particulieres(bool absolue) const;
+
+ // concernant les grandeurs gérées par le contact:
+ // ramène une liste d'iterator correspondant aux List_io passé en paramètre
+ // idem pour une List_io < Ddl _enum_etendu >
+ void List_reduite_aux_contact(const List_io& 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& li1);
+
+// ne sert plus (à virer car problématique !! )
+ // mise à jour du stockage inter, pour prendre en
+ // compte une nouvelle numérotation des noeuds
+// void Prise_en_compte_nouvelle_numerotation_noeud();
+
+ // 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 Init_list_grandeur_contact_a_sortir(const Tableau >& 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 tabNoeud; // les noeuds de la frontiere maitre
+ Tableau 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 tN,const Tableau & 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
+
+ LaLIST listContact; // la liste des elements en contact
+ LaLIST ::iterator> listContact_nouveau_tatdt; // la liste des nouveaux contacts qui sont apparus sur l'incrément
+ LaLIST listContact_efface_tatdt; // la liste des contacts effacés sur l'incrément
+ int nb_contact_actif; // nombre de contact actif courant
+// list 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 tabReacCont; // les reactions
+ Tableau tabCoLin; // 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 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 > *> indice;
+
+//--------- les tableaux de gestions pour la recherche de contact ----------------
+ list 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)
+
+
+ // 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 > > 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)
+
+ // 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::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::iterator > > > tesN_encontact;
+ // tesN_encontact(numMail_esclave)[*pt_noeud] -> la liste des iterators d'élément en 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 liQ_en_sortie; // liste de grandeurs quelconque qu'il faut sortir
+
+ // -------- une variable de travail pour la méthode LesContacts::ConnectionCLL()---
+ Tableau t_connectionCLL;
+
+ //------- temps cpu -----
+ // retourne temps cumulé pour imposer les CL imposées
+ Temps_CPU_HZpp tempsContact;
+
+ // 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
+ // normalement devrait toujours être correct mais ?? il y a quelque chose d'incorrecte quelque part
+ int Recalcul_Nb_contact_actif();
+
+ // création du conteneur Fct_nD_contact
+ void Creation_Fct_nD_contact();
+
+ };
+ /// @} // 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
diff --git a/contact/LesContacts_2.cc b/contact/LesContacts_2.cc
new file mode 100755
index 0000000..81d6f45
--- /dev/null
+++ b/contact/LesContacts_2.cc
@@ -0,0 +1,176 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+#ifndef LesContacts_2_deja_inclus
+ #include "LesContacts.h"
+#endif
+
+#ifndef LesContacts_2_deja_inclus
+
+#include
+#include "ReferenceNE.h"
+#include "ReferenceAF.h"
+
+
+//----- lecture écriture base info -----
+// lecture base info
+// 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
+void LesContacts::Lec_base_info_LesContacts(ifstream& 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)
+ {
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ // tout d'abord on lit le type
+ string type_contact,no_taille; int taille=0; // taille par défaut
+ ent >> type_contact >> no_taille >> taille;
+ #ifdef MISE_AU_POINT
+ if (type_contact != "LesContacts:")
+ { cout << "\n erreur dans la lecture des contacts, on attendait la chaine: LesContacts:"
+ << " alors que l'on a lue : " << type_contact
+ << "\n LesContacts::Lec_base_info_LesContacts(i...";
+ Sortie(1);
+ };
+ if (no_taille != "taille")
+ { cout << "\n erreur dans la lecture des contacts, on attendait la chaine: taille"
+ << " alors que l'on a lue : " << no_taille
+ << "\n LesContacts::Lec_base_info_LesContacts(i...";
+ Sortie(1);
+ };
+ #endif
+ // on supprime tous les éléments de contact sauf... les collants qui restent collant
+ {
+ LaLIST ::iterator iE ;
+ // on met .end(), car cette borne peut changer au gré des suppression
+ for (iE = listContact.begin(); iE != listContact.end(); iE++)
+ if (!((*iE).Collant()) // et si ce n'est pas collant: si collant, on ne change rien
+ )
+ { // sinon on supprime
+ LaLIST ::iterator iiE = iE;
+ iE--; // pointe sur le precedent element
+ LaLIST < LaLIST::iterator > & list_tesN
+ = tesN_encontact((*iiE).Esclave()->Num_Mail())[(*iiE).Esclave()];
+ list_tesN.remove(iiE);
+ listContact.erase(iiE); // efface l'element
+ };
+ Recalcul_Nb_contact_actif();
+ };
+// nb_contact_actif = 0 ; // init
+ Tableau compteur_inesc(nb_mail_Esclave,1); // compteur de compteur de noeuds esclaves
+
+ // on initialise la liste des éléments en contact
+// listContact.clear(); // comme on redémarre, on efface la situation actuelle
+ // non, il faut garder les éléments collants
+
+
+ // --- on s'occupe du deuxième niveau de tesN_encontact
+ // une map vide par défaut
+ std::map::iterator > > map_vide;
+ tesN_encontact.Change_taille(nb_mail_Esclave,map_vide);
+
+
+ for (int i=1;i<= taille;i++)
+ {// on commence par créer un élément de contact de base en fonction des infos sauvegardées
+ // --- le noeud esclave
+ string toto; int numMail_esclave, numNoeud_esclave;
+ string type;
+ int numMail_element, num_element, num_front_element;
+ Enum_type_geom enu ; string nom_enu; //N_es 1 72 El 2 2 SURFACE 1
+ ent >> toto >> numMail_esclave >> numNoeud_esclave // le noeud esclave
+ >> type >> numMail_element >> num_element // partie relative à l'élément
+ >> enu >> num_front_element; // et la frontière
+ // on ne continue que si le noeud fait partie des maillages esclave ou en auto-contact
+ // le nombre de maillages esclave et en auto-contact, peut-être redéfinit lors d'un restart
+ // donc n'est pas sauvegardé
+ if (numMail_esclave <= nb_mail_Esclave)
+ { Noeud& no = (instance.*RecupNoeud)(numMail_esclave, numNoeud_esclave); // ""
+ // --- création de la frontière
+ Element& elem = (instance.*RecupElement_LesMaille)(numMail_element,num_element);
+ ElFrontiere* elfr;
+ switch (enu)
+ { case POINT_G : elfr = elem.Frontiere_points(num_front_element,true) ; break;
+ case LIGNE : elfr = elem.Frontiere_lineique(num_front_element,true) ; break;
+ case SURFACE : elfr = elem.Frontiere_surfacique(num_front_element,true) ; break;
+ default :
+ cout << "\nErreur : valeur incorrecte du type de frontiere " << Nom_type_geom(enu) << " !\n";
+ cout << "LesContacts::Lec_base_info_LesContacts(... \n";
+ Sortie(1);
+ };
+ // création d'un Front
+ Front froont(*elfr,&elem,num_front_element);
+ // création de l'élément de contact
+ ElContact courant(&froont,&no,fct_nD_contact);
+ // lecture des données particulières
+ courant.Lec_base_info_ElContact(ent);
+ // on regarde si c'était un contact actif ou pas, si oui on incrémente le nombre
+ if (courant.Actif())
+ nb_contact_actif++;
+ // sauvegarde
+ listContact.push_front(courant);
+ LaLIST::iterator ipp = listContact.begin();
+ // on met à jour le tableau tesN_encontact
+ //*** la liste peut très bien ne pas exister !
+// #ifdef MISE_AU_POINT
+// if (tesN_encontact(numMail_esclave).find((*ipp).Esclave())
+// == tesN_encontact(numMail_esclave).end() )
+// { cout << "\n*** Erreur : on ne trouve pas la liste d'element en contact avec le noeud esclave "
+// << (*ipp).Esclave()->Num_noeud() << " du maillage " << numMail_esclave
+// << " la suite n'est pas possible "
+// << " LesContacts::Lec_base_info_LesContacts(.. \n";
+// Sortie(1);
+// };
+// #endif
+
+ // ajout dans la liste associé au noeud esclave
+ tesN_encontact(numMail_esclave)[(*ipp).Esclave()].push_front(listContact.begin());
+ } // fin de l'ajout d'un élément de contact
+ else
+ {if (ParaGlob::NiveauImpression() > 0)
+ cout << "\n *** attention, le maillage "< 2) && (nb_contact_actif != 0))
+ || (niveau_commentaire_contact > 0 )
+ )
+ cout << "\n >> restart: lecture elements contact : "<< nb_contact_actif << " elements lus " << endl ;
+ string mot;
+ ent >> mot >> tempsContact;
+ };
+
+
+ #endif // fin du test d'inclusion : ifndef LesContacts_2_deja_inclus
+
+
+
diff --git a/contact/LesContacts_3.cc b/contact/LesContacts_3.cc
new file mode 100755
index 0000000..a946357
--- /dev/null
+++ b/contact/LesContacts_3.cc
@@ -0,0 +1,1247 @@
+
+// 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) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 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 .
+//
+// For more information, please consult: .
+
+
+#include "LesContacts.h"
+#include
+#include "ReferenceNE.h"
+#include "ReferenceAF.h"
+#include "CharUtil.h"
+
+#include "Enum_TypeQuelconque.h"
+#include "TypeQuelconqueParticulier.h"
+
+
+
+// récupération des ddl ou des grandeurs actives de tdt vers t
+void LesContacts::TdtversT()
+ { LaLIST ::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 ::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::iterator > & list_tesN
+ = tesN_encontact(num_mail_noe_esclave)[no];
+ list_tesN.remove(*al);
+// tesN_encontact(num_mail_noe_esclave)(n_noee).remove(*al);
+ if (elc.Actif()) //a priori les nouveaux contacts étaient actif
+ nb_contact_actif--; // mais on ne sait jamais
+ listContact.erase(*al);
+// cout << "\n debug toto ";
+ };
+ };
+ // b) on rajoute les contacts supprimés
+ {LaLIST ::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();
+ 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());
+ if ((*al).Actif()) // si l'élément supprimé était actif on remet à jour
+ nb_contact_actif++;
+ };
+ };
+ // 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 ::iterator il,ilfin=listContact.end();
+ for (il=listContact.begin();il != ilfin; il++)
+ (*il).TversTdt();
+ };
+ };
+
+
+// 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 ::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 ::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 d'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: "< 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::iterator ili_deb= listContact.begin();
+ LaLIST::iterator ilifin= listContact.end();
+ LaLIST::iterator ili;
+
+ // on passe en revue la liste de quelconque
+ {List_io::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 & 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 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 LesContacts::ListeGrandeurs_particulieres(bool absolue) const
+ {
+ // def de la liste de retour
+ List_io 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 du glissement des noeuds projectiles actifs
+ {TypeQuelconque typQ1(NORMALE_CONTACT,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 passé en paramètre
+ // idem pour une List_io < Ddl _enum_etendu >
+void LesContacts::List_reduite_aux_contact(const List_io& liTQ
+ ,List_io < TypeQuelconque >& li_restreinte_TQ
+ )
+ {
+ // initialisation des listes de retour
+ li_restreinte_TQ.clear();
+ // on passe en revue la liste
+ List_io::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:
+ {// ----- 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& liTQ)
+ {liQ_en_sortie = liTQ; // on récupère la liste --> sans doute que cela ne sert à rien
+
+ LaLIST::iterator ili_deb= listContact.begin();
+ LaLIST::iterator ilifin= listContact.end();
+ LaLIST::iterator ili;
+
+ // on passe en revue la liste
+ List_io::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 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 ::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_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ // 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 nom_ref_zone_contact; // liste des noms de références des zones de contact
+ list ::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_contact > 2)
+ cout << "\n >>>> Suppression_gap_pour_noeud_collant : ";
+ // on va iterer sur les noeuds esclaves collants dont on veut supprimer le gap
+ LaLIST_io ::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_contact >2 )
+ cout << "\n boucle : "<& tesc= tesctotal(intot)(j); // pour simplifier la notation:
+ const Tableau 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 list_P; // la liste des projetés
+ list ::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 > > t_listFront;
+ LaLIST_io & 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 ::iterator il,ilfin=list_P.end();
+ if (niveau_commentaire_contact >5 )
+ {cout << "\n " << list_P.size() << " proj trouvees "
+ << " Noe: "<Num_noeud()
+ << " mail: " << noee->Num_Mail() << " (zone"<::iterator>::iterator iface = li_pt_front_P.begin();
+ LaLIST_io ::iterator>::iterator iface_maxi ;
+ for (il=list_P.begin(); il!= ilfin;il++,iface++)
+ { double Ndis = (M-(*il)).Norme();
+ if (niveau_commentaire_contact >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_contact >3 )
+ cout << "\n suppression gap=("<Num_noeud()
+ << " du maillage " << noee->Num_Mail() << " (zone "<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_contact >3 )
+ cout << "\n pas de projection trouvee donc de suppression gap du noeud "<Num_noeud()
+ << " du maillage" << noee->Num_Mail() << " (zone "<2 )
+ {if (compteur_noeuds_projecte)
+ cout << "\n zone: " << j <<", " << compteur_noeuds_projecte << " suppression(s) de gap, maxi_distance= "
+ << le_maxi_des_distances_trouve << "( passage"<& 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 & list_fronta = t_listFront(i)(j); // pour simplifier
+ LaLIST_io ::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 & 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 & 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 t_enu(1); t_enu(1)=X1 ;
+ LaLIST ::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::Recalcul_Nb_contact_actif()
+ { LaLIST ::iterator il,ilfin = listContact.end();
+ int ancien_nb_contact_actif = nb_contact_actif;
+ nb_contact_actif = 0; // init
+ for (il = listContact.begin();il != ilfin; il++)
+ if ((*il).Actif())
+ nb_contact_actif++;
+
+ int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact();
+ if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();};
+ if (nb_contact_actif != ancien_nb_contact_actif)
+ if (niveau_commentaire_contact > 4)
+ cout << "\n mise a jour anormale du nombre de contact actif : "
+ << " ancien_nb_contact_actif= " << ancien_nb_contact_actif
+ << " nouveau_nombre= " << nb_contact_actif << endl;
+ 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;};
+ };
+
+ };
+
+/*// 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 > > ta_inverse_old(ta_inverse);
+
+ // on recherche les maxi des numéros de noeuds esclave, pour dimensionner ta_inverse !!
+ Tableau < Tableau > 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 & 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 & 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 > nouveau_Noe(nb_mail_Esclave);
+ // on cherche la taille maxi
+ Tableau