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 maxi_maxi_num_noe_esclave(nb_mail_Esclave); // les maxis pour chaque maillage + for (int i=1;i<=nb_mail_Esclave;i++) + {int& max_max_esclave = maxi_maxi_num_noe_esclave(i) = 0; // init + for (int j=1;j<=nb_zone;j++) + {int& max_num_esclave = maxi_num_noe_esclave(i)(j); // pour simplifier + if (max_num_esclave > max_max_esclave) + max_max_esclave = max_num_esclave; + }; + }; + // on balaie les anciens noeuds + for (int i=1;i<=nb_mail_Esclave;i++) + {nouveau_Noe(i).Change_taille(maxi_maxi_num_noe_esclave(i)); + Tableau & nouveau_Noe_i = nouveau_Noe(i); + for (int j=1;j<=nb_zone;j++) + { Tableau & ta_inverse_old_ij = ta_inverse_old(i)(j); + Tableau & ta_inverse_ij = ta_inverse(i)(j); + int nbN = ta_inverse_old_ij.Taille(); + for (int k=1;k<= nbN;k++) // k c'est le numéro de l'ancien noeud + {if (ta_inverse_old_ij(k) != 0) + {for (int k2=1;k2<= nbN;k2++) + { if (ta_inverse_old_ij(k) == ta_inverse_ij(k2)) + {nouveau_Noe_i(k)=k2;break;}; + }; + }; + }; + }; + }; + +// // maintenant on met à jour le tableau tesN_encontact +// // Tableau < Tableau < LaLIST < LaLIST::iterator > > > tesN_encontact; +// // on sauvegarde l'ancien +// Tableau < Tableau < LaLIST < LaLIST::iterator > > > tesN_encontact_old(tesN_encontact); +// // et on fait la passation +// for (int i=1;i<=nb_mail_Esclave;i++) +// {Tableau & nouveau_Noe_i = nouveau_Noe(i); +// int nbn = tesN_encontact(i).Taille(); +// for (int j=1;j<=nbn;j++) +// { tesN_encontact(i)(nouveau_Noe_i(j)) = tesN_encontact_old(i)(j); +// }; +// }; + + // on continue avec le tableau: liste pour chaque noeud, des éléments qui contient ce noeud + // indice(i)(j) : = la liste des éléments qui contiennent le noeud j, pour le maillage i + Tableau < const Tableau > *> indice_old(indice); + int nb_mail = indice_old.Taille(); + for (int i=1;i<=nb_mail;i++) + {if (indice_old(i) != NULL) + { int nbn = indice_old(i)->Taille(); +// const Tableau > & indice_i = indice(i); +// for (int j=1;j<=nbn;j++) +//indice + + } + + } +cout << "\n LesContacts::Prise_en_compte_nouvelle_numerotation_noeud() pas terminé !!" + << " il faut changer lesMaillages pour récupérer directement la nouvelle numérotation !!"; +Sortie(1); + + }; +*/ + + +// récupération via les éléments de contact des forces maxis +// et affichage éventuel +// un : le maxi en effort normal, deux: le maxi en effort tangentiel +DeuxDoubles LesContacts::Forces_contact_maxi(bool affiche) const + {DeuxDoubles retour; + LaLIST ::const_iterator il,ilfin = listContact.end(); + for (il = listContact.begin();il != ilfin; il++) + { const ElContact& icont = (*il); // pour simplifier + double fNmax = icont.F_N_MAX(); + double fTmax = icont.F_T_MAX(); + if (Dabs(fNmax) > Dabs(retour.un) ) + retour.un = fNmax; + if (Dabs(fTmax) > Dabs(retour.deux) ) + retour.deux = fTmax; + }; + int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact(); + if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();}; + if ((affiche && (ParaGlob::NiveauImpression() > 2)) + || (niveau_commentaire_contact > 5) // spécifiquement pour le contact + ) + cout << "\n contact: reaction ==> F_N max " << retour.un << " F_T max " << retour.deux; + return retour; + }; + +// récupération via les éléments de contact des gaps maxis +// un : le maxi en gap normal, deux: le maxi en gap tangentiel +DeuxDoubles LesContacts::Gap_contact_maxi(bool affiche) const + {DeuxDoubles retour; + LaLIST ::const_iterator il,ilfin = listContact.end(); + for (il = listContact.begin();il != ilfin; il++) + { const ElContact& icont = (*il); // pour simplifier + double fNmax = icont.Gaptdt(); + double fTmax = icont.Dep_T_tdt(); + if (Dabs(fNmax) > Dabs(retour.un) ) + retour.un = fNmax; + if (Dabs(fTmax) > Dabs(retour.deux) ) + retour.deux = fTmax; + }; + int niveau_commentaire_contact = ParaGlob::param->ParaAlgoControleActifs().Niveau_commentaire_contact(); + if (niveau_commentaire_contact == 0) {niveau_commentaire_contact = ParaGlob::NiveauImpression();}; + if ((affiche && (ParaGlob::NiveauImpression() > 2)) + || (niveau_commentaire_contact > 5) // spécifiquement pour le contact + ) + cout << ", maxi gap_N : " << retour.un << " gap_T : " << retour.deux; + return retour; + }; + + + + + + + diff --git a/contact/Plan.cc b/contact/Plan.cc new file mode 100644 index 0000000..4d4be6b --- /dev/null +++ b/contact/Plan.cc @@ -0,0 +1,211 @@ +//#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 "Plan.h" +#include "ConstMath.h" +#include "MathUtil.h" +#include "Util.h" + + // CONSTRUCTEURS : +// par defaut +Plan::Plan () : + A(), N() + {}; +// avec les datas +Plan::Plan ( const Coordonnee& B, const Coordonnee& vec) : + A(B), N(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->N = P.N; + return *this; + }; + + // METHODES PUBLIQUES : + +// change le point de ref du plan +void Plan::Change_ptref( const Coordonnee& B) + { + #ifdef MISE_AU_POINT + if (B.Dimension() != N.Dimension()) + { cout << "\nErreur : les dimensions du point et du vecteur ne sont pas identique !"; + cout <<"\ndim point = " <> (istream & entree, Plan & pl)\n"; + Sortie(1); + }; + #endif + // puis lecture des différents éléments + entree >> nom >> pl.A >> nom >> pl.N; + return entree; + }; + +// surcharge de l'operateur d'ecriture +ostream & operator << ( ostream & sort,const Plan & pl) + { // tout d'abord un indicateur donnant le type + sort << " _plan_ " ; + // puis les différents éléments + sort << "\n A= " << pl.A << " U= " << pl.N << " "; + return sort; + }; + diff --git a/contact/Plan.h b/contact/Plan.h new file mode 100644 index 0000000..1bebd3a --- /dev/null +++ b/contact/Plan.h @@ -0,0 +1,124 @@ + +// 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'un plan: un point et une normale. * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * * + * VERIFICATION: * + * * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * ! ! ! ! * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * + * MODIFICATIONS: * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * $ * + ************************************************************************/ +#ifndef PLAN_H +#define PLAN_H + +#include "Droite.h" +#include "Coordonnee.h" + +/// @addtogroup Groupe_sur_les_contacts +/// @{ +/// + + +class Plan +{ // surcharge de l'operator de lecture + friend istream & operator >> (istream &, Plan &); + // surcharge de l'operator d'ecriture + friend ostream & operator << (ostream &, const Plan &); + + public : + // CONSTRUCTEURS : + // par defaut + Plan (); + // avec les datas + Plan ( const Coordonnee& B, const Coordonnee& vec); + // avec la dimension + Plan (int dim); + // de copie + Plan ( const Plan& a); + // DESTRUCTEUR : + ~Plan (); + // surcharge des operator + Plan& operator = ( const Plan & P); + + // METHODES PUBLIQUES : + // retourne le point de ref du plan + inline const Coordonnee& PointPlan() const { return A;}; + // retourne la normale au plan + inline const Coordonnee& Vecplan() const { return N;}; + + // change la dimension de la droite + void Change_dim(int dima) {A.Change_dim(dima);N.Change_dim(dima);}; + // change le point de ref du plan + void Change_ptref( const Coordonnee& B); + // change le vecteur normal du plan + void Change_normal( const Coordonnee& vec); + // change toutes les donnees + void change_donnees( const Coordonnee& B, const Coordonnee& vec); + + // calcul l'intercection M d'une droite avec le plan, 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 un point d'intercection + int Intersection( const Droite & D,Coordonnee& M)const; + + // calcul la distance d'un point à la droite + double Distance_au_plan(const Coordonnee& M) const; + + // calcul du projeté d'un point sur le plan + Coordonnee Projete(const Coordonnee& M) const + {return (M - ((M-A)*N)*N);}; + + // ramène true si les deux points sont du même coté du plan, false sinon + bool DuMemeCote(const Coordonnee& M1, const Coordonnee& M2) const; + + protected : + // VARIABLES PROTEGEES : + Coordonnee A; // un point du plan + Coordonnee N; // normale au plan + // METHODES PROTEGEES : + + }; + /// @} // end of group + +#endif diff --git a/contact/Sphere.cc b/contact/Sphere.cc new file mode 100644 index 0000000..c47f207 --- /dev/null +++ b/contact/Sphere.cc @@ -0,0 +1,202 @@ + +// 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 "Sphere.h" +#include "MathUtil.h" +#include "ParaGlob.h" + + // CONSTRUCTEURS : +// par defaut +Sphere::Sphere () : + centre(3),rayon(0.) + { if (ParaGlob::Dimension()!= 3) + { cout << "\nErreur : la dimension n'est pas 3 et on veut utiliser une sphere ??? "; + cout << "\nSphere::Sphere ()" << endl; + Sortie(1); + }; + }; +// avec les datas +Sphere::Sphere ( const Coordonnee& B, const double& r): + centre(B),rayon(r) + { if (ParaGlob::Dimension()!= 3) + { cout << "\nErreur : la dimension n'est pas 3 et on veut utiliser une sphere ??? "; + cout << "\nSphere::Sphere (.." << endl; + Sortie(1); + }; + if (rayon < 0.) + { cout << "\n erreur dans la construction d'une sphere, le rayon " << rayon + << " est negatif !! "; + Sortie(1); + }; + }; +// avec la dimension +Sphere::Sphere (int dim): + centre(dim),rayon(0.) + { if (ParaGlob::Dimension()!= 3) + { cout << "\nErreur : la dimension n'est pas 3 et on veut utiliser une sphere ??? "; + cout << "\nSphere::Sphere (.." << endl; + Sortie(1); + }; + if (dim != 3) + { cout << "\nErreur : la dimension demandee n'est pas 3 et on veut utiliser une sphere ??? "; + cout << "\nSphere::Sphere (.." << endl; + Sortie(1); + }; + }; + // de copie +Sphere::Sphere ( const Sphere& a): + centre(a.centre),rayon(a.rayon) + {}; + + // DESTRUCTEUR : +Sphere::~Sphere () {}; + +// surcharge des operator +Sphere& Sphere::operator = ( const Sphere & sph) + { centre = sph.centre; rayon = sph.rayon; return *this; }; + +// METHODES PUBLIQUES : + +// change le centre de la sphere +void Sphere::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 = " < 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; + }; + +// calcul la distance d'un point à la sphere +double Sphere::Distance_a_sphere(const Coordonnee& M) const + { return Dabs((centre - M).Norme()-rayon); + }; + +// projection d'un point M sur la parois de la sphère +// dans le cas où M = le centre de la sphère, la projection n'est pas +// possible, dans ce cas projection_ok = false en retour, sinon true +Coordonnee Sphere::Projete(const Coordonnee& M,bool& projection_ok) const +{ // on commence par calculer la projection du point sur l'axe + Coordonnee CM = M-centre; + double dist_centre = CM.Norme(); + if (dist_centre < ConstMath::pasmalpetit) + {projection_ok = false;// on signale que la projection n'est pas possible + Coordonnee toto; // on fait l'opération en deux temps pour linux + return (toto);// on ramène un point par défaut + } + else + {projection_ok = true; + Coordonnee P = centre + CM * (rayon / dist_centre ); + return P; + }; + }; + +// surcharge de l'operateur de lecture +istream & operator >> (istream & entree, Sphere & sph) + { // vérification du type + string nom; + entree >> nom; + #ifdef MISE_AU_POINT + if (nom != "_sphere_") + { cout << "\nErreur, en lecture d'une instance sphere " + << " on attendait _sphere_ et on a lue: " << nom ; + cout << "istream & operator >> (istream & entree, Sphere & sph)\n"; + Sortie(1); + }; + #endif + // puis lecture des différents éléments + entree >> nom >> sph.centre >> nom >> sph.rayon; + return entree; + }; + +// surcharge de l'operateur d'ecriture +ostream & operator << ( ostream & sort,const Sphere & sph) + { // tout d'abord un indicateur donnant le type + sort << " _sphere_ " ; + // puis les différents éléments + sort << "\n C= " << sph.centre << " r= " << sph.rayon << " "; + return sort; + }; diff --git a/contact/Sphere.h b/contact/Sphere.h new file mode 100644 index 0000000..04371f6 --- /dev/null +++ b/contact/Sphere.h @@ -0,0 +1,126 @@ + +// 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'une sphere: un centre et un rayon * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * * + * VERIFICATION: * + * * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * ! ! ! ! * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * + * MODIFICATIONS: * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * $ * + ************************************************************************/ +#ifndef SPHEREE_H +#define SPHEREE_H + +#include "Droite.h" +#include "Coordonnee.h" + +/// @addtogroup Groupe_sur_les_contacts +/// @{ +/// + + +class Sphere +{ // surcharge de l'operator de lecture + friend istream & operator >> (istream &, Sphere &); + // surcharge de l'operator d'ecriture + friend ostream & operator << (ostream &, const Sphere &); + + public : + // CONSTRUCTEURS : + // par defaut + Sphere (); + // avec les datas + Sphere ( const Coordonnee& B, const double& r); + // avec la dimension + Sphere (int dim); + // de copie + Sphere ( const Sphere& a); + // DESTRUCTEUR : + ~Sphere (); + // surcharge des operator + Sphere& operator = ( const Sphere & P); + + // METHODES PUBLIQUES : + // retourne le centre de la Sphere + inline const Coordonnee& CentreSphere() const { return centre;}; + // retourne le rayon de la sphere + inline double RayonSphere() const { return rayon;}; + + // change le centre de la sphere + void Change_centre( const Coordonnee& B); + // change le rayon de la sphere + void Change_rayon( const double & r); + // change toutes les donnees + void change_donnees( const Coordonnee& B, const double& r); + + // calcul les deux intercections M1 et M2 d'une droite avec la sphere, + // 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 à la sphere + double Distance_a_sphere(const Coordonnee& M) const; + + // ramène true si le point est à l'intérieur de la sphère, false sinon + bool Dedans(const Coordonnee& M)const + { return ((centre - M).Norme() < rayon);}; + + // projection d'un point M sur la parois de la sphère + // dans le cas où M = le centre de la sphère, 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 : + Coordonnee centre; // centre de la sphere + double rayon; // rayon de la sphère + // METHODES PROTEGEES : + + }; + /// @} // end of group + +#endif