Herezh_dev/contact/ElContact.cc
Gérard Rio 4fb2021022 Signed-off-by: Gérard Rio <gerardrio56@free.fr>
ajout de fichiers manquants, fin de l'intro d'éléments d'angle morts en 2D 2D axi, mise à jour pour restart avec contact 3D
2023-05-27 10:50:10 +02:00

2473 lines
119 KiB
C++

// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.
#include "ElContact.h"
#include "Droite.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "ElemMeca.h"
#include "Util.h"
#include <cmath>
#include "TypeConsTens.h"
#include "Enum_TypeQuelconque.h"
#include "TypeQuelconqueParticulier.h"
using namespace std;
//---------- variables statiques --------------
list <DdlElement> ElContact::list_Ddl_global; // liste de tous les DdlElements des éléments de contact
list <Vecteur> ElContact::list_SM; // list de second membre local: sert pour tous les éléments de contact
list <Mat_pleine> 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
// stockage transitoire pour les quelconques vraiment quelconque
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationPenetration;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_penalisationPenetration;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationPenetration;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_borne_regularisation;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_penetration_borne_regularisation;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_borne_regularisation;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_force_contact_noeud_maxi;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_force_contact_noeud_maxi;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_contact_noeud_maxi;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationTangentielle;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_penalisationTangentielle;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationTangentielle;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_contact_maxi;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_contact_maxi;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_contact_maxi;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_borne_regularisation;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_borne_regularisation;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_borne_regularisation;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_force_tangentielle_noeud_maxi;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_force_tangentielle_noeud_maxi;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_tangentielle_noeud_maxi;
Tableau <const TypeQuelconque * > ElContact::Fct_nD_contact::tqi_const_fct_nD_niveau_commentaire;
Tableau < TypeQuelconque * > ElContact::Fct_nD_contact::tqi_fct_nD_niveau_commentaire;
Tableau <int> ElContact::Fct_nD_contact::t_num_ordre_fct_nD_niveau_commentaire;
//----------- 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)
,fct_niveau_commentaire(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)
,fct_niveau_commentaire(a.fct_niveau_commentaire)
{};
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;
fct_niveau_commentaire = a.fct_niveau_commentaire;
return *this;
};
// initialisation des conteneurs statique des fonction nD
void ElContact::Fct_nD_contact::Init_conteneur_statique()
{// on initialise chaque fct nD
if (fct_nD_penalisationPenetration != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_penalisationPenetration
,tqi_fct_nD_penalisationPenetration,tqi_const_fct_nD_penalisationPenetration
,t_num_ordre_fct_nD_penalisationPenetration);
if (fct_nD_penetration_contact_maxi != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_penetration_contact_maxi
,tqi_fct_nD_penetration_contact_maxi,tqi_const_fct_nD_penetration_contact_maxi
,t_num_ordre_fct_nD_penetration_contact_maxi);
if (fct_nD_penetration_borne_regularisation != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_penetration_borne_regularisation
,tqi_fct_nD_penetration_borne_regularisation,tqi_const_fct_nD_penetration_borne_regularisation
,t_num_ordre_fct_nD_penetration_borne_regularisation);
if (fct_nD_force_contact_noeud_maxi != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_force_contact_noeud_maxi
,tqi_fct_nD_force_contact_noeud_maxi,tqi_const_fct_nD_force_contact_noeud_maxi
,t_num_ordre_fct_nD_force_contact_noeud_maxi);
if (fct_nD_penalisationTangentielle != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_penalisationTangentielle
,tqi_fct_nD_penalisationTangentielle,tqi_const_fct_nD_penalisationTangentielle
,t_num_ordre_fct_nD_penalisationTangentielle);
if (fct_nD_tangentielle_contact_maxi != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_tangentielle_contact_maxi
,tqi_fct_nD_tangentielle_contact_maxi,tqi_const_fct_nD_tangentielle_contact_maxi
,t_num_ordre_fct_nD_tangentielle_contact_maxi);
if (fct_nD_tangentielle_borne_regularisation != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_tangentielle_borne_regularisation
,tqi_fct_nD_tangentielle_borne_regularisation,tqi_const_fct_nD_tangentielle_borne_regularisation
,t_num_ordre_fct_nD_tangentielle_borne_regularisation);
if (fct_nD_force_tangentielle_noeud_maxi != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_nD_force_tangentielle_noeud_maxi
,tqi_fct_nD_force_tangentielle_noeud_maxi,tqi_const_fct_nD_force_tangentielle_noeud_maxi
,t_num_ordre_fct_nD_force_tangentielle_noeud_maxi);
if (fct_niveau_commentaire != NULL)
Definition_conteneurs_static_TypeQuelconque
(fct_niveau_commentaire
,tqi_fct_nD_niveau_commentaire,tqi_const_fct_nD_niveau_commentaire
,t_num_ordre_fct_nD_niveau_commentaire);
};
// définition des conteneurs static des TypeQuelconque
void ElContact::Fct_nD_contact::Definition_conteneurs_static_TypeQuelconque
(Fonction_nD * pt_fonct,Tableau < TypeQuelconque * >& tqi,Tableau < const TypeQuelconque * >& tqii
,Tableau <int>& t_num_ordre )
{// on commence par récupérer le conteneurs des grandeurs à fournir
const Tableau <EnumTypeQuelconque>& tab_queconque = pt_fonct->Tab_enu_quelconque();
// on dimensionne
int tail_tab_queconque = tab_queconque.Taille();
tqi.Change_taille(tail_tab_queconque);
t_num_ordre.Change_taille(tail_tab_queconque);
Grandeur_scalaire_entier grand_courant_entier(0); // par défaut pour la création des conteneurs quelconques
Grandeur_scalaire_double grand_courant_double(0.); // par défaut pour la création des conteneurs quelconques
// grandeurs de travail
int dim = ParaGlob::Dimension();
Coordonnee inter(dim);
Grandeur_coordonnee grand_coor_courant(inter);
// on va balayer les grandeurs quelconques
for (int i=1;i<= tail_tab_queconque;i++)
{ bool trouver = false;
EnumTypeQuelconque enu = tab_queconque(i);
tqi(i) = NULL; // init
t_num_ordre(i) = 1; //***** pour l'instant uniquement la première coordonnée s'il s'agit d'un Coordonnee
// *** à abonder par la suite !!!!!!!!!!
// on regarde tout d'abord les grandeurs spécifiques à l'élément contact
switch (enu)
{ // 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:
{ tqi(i) = new TypeQuelconque(CONTACT_NB_DECOL,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_PENALISATION_N:
{ tqi(i) = new TypeQuelconque(CONTACT_PENALISATION_N,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_PENALISATION_T:
{ tqi(i) = new TypeQuelconque(CONTACT_PENALISATION_T,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_NB_PENET:
{ tqi(i) = new TypeQuelconque(CONTACT_NB_PENET,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_CAS_SOLIDE:
{ tqi(i) = new TypeQuelconque(CONTACT_CAS_SOLIDE,X1,grand_courant_entier);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_ELAS:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_ELAS,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_PLAS:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_PLAS,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_VISQ:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_GLISSE_VISQ,X1,grand_courant_double);
trouver = true;
break;
}
case CONTACT_ENERG_PENAL:
{ tqi(i) = new TypeQuelconque(CONTACT_ENERG_PENAL,X1,grand_courant_double);
trouver = true;
break;
}
case NOEUD_PROJECTILE_EN_CONTACT:
{ tqi(i) = new TypeQuelconque(NOEUD_PROJECTILE_EN_CONTACT,X1,grand_courant_double);
trouver = true;
break;
}
case NOEUD_FACETTE_EN_CONTACT:
{ tqi(i) = new TypeQuelconque(NOEUD_FACETTE_EN_CONTACT,X1,grand_courant_double);
Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
trouver = true;
break;
}
case NUM_NOEUD:
{ tqi(i) = new TypeQuelconque(NUM_NOEUD,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_MAIL_NOEUD:
{ tqi(i) = new TypeQuelconque(NUM_MAIL_NOEUD,X1,grand_courant_entier);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE,X1,grand_coor_courant);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE_t,X1,grand_coor_courant);
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t0:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE_t0,X1,grand_coor_courant);
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:
{tqi(i) = new TypeQuelconque(PENETRATION_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case PENETRATION_CONTACT_T:
{tqi(i) = new TypeQuelconque(PENETRATION_CONTACT_T,X1,grand_coor_courant);
trouver = true;
break;
}
case GLISSEMENT_CONTACT:
{tqi(i) = new TypeQuelconque(GLISSEMENT_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case GLISSEMENT_CONTACT_T:
{tqi(i) = new TypeQuelconque(GLISSEMENT_CONTACT_T,X1,grand_coor_courant);
trouver = true;
break;
}
case NORMALE_CONTACT:
{tqi(i) = new TypeQuelconque(NORMALE_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case FORCE_CONTACT:
{tqi(i) = new TypeQuelconque(FORCE_CONTACT,X1,grand_coor_courant);
trouver = true;
break;
}
case FORCE_CONTACT_T:
{tqi(i) = new TypeQuelconque(POSITION_GEOMETRIQUE,X1,grand_coor_courant);
trouver = true;
break;
}
case CONTACT_COLLANT:
{ tqi(i) = new TypeQuelconque(CONTACT_COLLANT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_ZONE_CONTACT:
{ tqi(i) = new TypeQuelconque(NUM_ZONE_CONTACT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_ELEMENT:
{ tqi(i) = new TypeQuelconque(NUM_ELEMENT,X1,grand_courant_entier);
trouver = true;
break;
}
case NUM_MAIL_ELEM:
{ tqi(i) = new TypeQuelconque(NUM_MAIL_ELEM,X1,grand_courant_entier);
trouver = true;
break;
}
//*** fin
default:
trouver = false;
break;
};
// si on n'a rien trouvé
if (!trouver)
{cout << "\n erreur***: la grandeur " << NomTypeQuelconque(enu)
<< " n'existe pas les elements de contact "
<< " la fonction nD " << pt_fonct->NomFonction()
<< " ne peut pas etre renseignee "
<< "\n ElContact::Fct_nD_contact::Definition_conteneurs_static_TypeQuelconque(.." << flush;
pt_fonct->Affiche();
Sortie(1);
};
};
// tableau de const intermédiaire pour l'appel de la fonction
tqii.Change_taille(tail_tab_queconque);
for (int i=1;i<= tail_tab_queconque;i++)
tqii(i) = tqi(i);
};
///------- fin particularité class Fct_nD_contact ------------------
// CONSTRUCTEURS :
// par defaut
ElContact::ElContact () :
tabNoeud(),tabNoeud_t()
,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),elfront_t(NULL),noeud(NULL),noeud_t(NULL)
,num_zone_contact(0),normale_lisser(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),nb_change_frontiere(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(),tabNoeud_t()
,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),elfront_t(NULL),noeud(NULL),noeud_t(NULL)
,num_zone_contact(0),normale_lisser(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),nb_change_frontiere(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(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
noeud_t = noeud;
elfront = new Front(*elf);
elfront_t=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
tabForce_cont.Change_taille(tabNoeud.Taille()-1);
tabForce_cont_t.Change_taille(tabNoeud.Taille()-1);
};
// de copie
ElContact::ElContact ( const ElContact & a):
tabNoeud(),tabNoeud_t()
,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),elfront_t(NULL),noeud(NULL),noeud_t(NULL)
,num_zone_contact(a.num_zone_contact),normale_lisser(a.normale_lisser)
,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),nb_change_frontiere(a.nb_change_frontiere)
,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;
noeud_t = noeud;
elfront = new Front(*(a.Elfront()));
elfront_t=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
// cas = 0 : affichage en fonction du niveau de commentaire voulu
// cas = 1 : affichage minimal nécessaire pour repérer l'élément
// cas = 2 : affichage minimal en fonction du niveau de commentaire pour les éléments de contact
void ElContact::Affiche(int cas) const
{
if (cas == 1)
{cout << "el contact: noe "
<< noeud->Num_noeud() <<" mail. " << noeud->Num_Mail()
<< " avec front:";
if (elfront->Angle_mort())
cout << "(angle mort)";
if (normale_lisser)
cout << " (lissage N) ";
if (!actif) cout << " (inactif) ";
cout << elfront->Num_frontiere()
<< " de l'EF " << elfront->PtEI()->Num_elt() << " du mail. "
<< elfront->PtEI()->Num_maillage() << flush;;
if (Permet_affichage() > 6)
{const Tableau <Front*>* tabmit = elfront->TabMitoyen();
if (tabmit != NULL)
{int taille = tabmit->Taille();
for (int i=1;i<= taille;i++)
cout << " ele_mitoy: "<< (*tabmit)(i)->PtEI()->Num_elt()
<< " du mail. "
<< (*tabmit)(i)->PtEI()->Num_maillage() << flush;
};
};
}
else if (cas == 2)
{if (Permet_affichage() > 5)
{cout << "\n el contact: noe "
<< noeud->Num_noeud() <<" mail. " << noeud->Num_Mail()
<< " avec front:";
if (elfront->Angle_mort())
cout << "(angle mort)";
if (normale_lisser)
cout << " (lissage N) ";
if (!actif) cout << " (inactif) ";
cout << elfront->Num_frontiere()
<< " de l'EF " << elfront->PtEI()->Num_elt() << " du mail. "
<< elfront->PtEI()->Num_maillage() << flush;
if (Permet_affichage() > 6)
{const Tableau <Front*>* tabmit = elfront->TabMitoyen();
if (tabmit != NULL)
{int taille = tabmit->Taille();
for (int i=1;i<= taille;i++)
cout << " ele_mitoy: "<< (*tabmit)(i)->PtEI()->Num_elt()
<< " du mail. "
<< (*tabmit)(i)->PtEI()->Num_maillage() << flush;
};
};
};
// sinon pas d'affichage
}
else
{ cout << "\n element de contact ";
if (!actif) cout << " Inactif ! ";
if (normale_lisser) cout << " (lissage N) ";
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 (Permet_affichage() > 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 "; };
cout << "\n fct_niveau_commentaire: ";
if (fct_nD_contact.fct_niveau_commentaire != NULL )
{cout << fct_nD_contact.fct_niveau_commentaire->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
////debug
// cout << "\n ElContact::Contact: "; this->Affiche(1);
//// fin debug
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;
};
// **** il y a des choses à faire au niveau de la droite tangente et du point d'impact
// lorsque l'on a une ligne d'angle mort, contrairement au cas du point, le point d'intersection
// doit-être calculé, et c'est important car il va servir pour RecupInfo et ensuite pour
// le calcul de la raideur et du second membre...
// bref il faut revoir la chose: c'est un peu moins simple que dans le cas d'un point_G
// 1) === le cas des angles morts est particulier, on commence par le traiter
if (elfront->Angle_mort())
{ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
int dim = noeud->Dimension();
Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
N = Calcul_Normale(dim,pl,dr,indic);
// la seule chose que l'on peut faire pour valider le fait qu'il y a contact ou pas
// c'est de tester si le noeud est à l'intérieur de l'élément d'angle mort ou pas
// c'est plus long qu'un test de surface mais il n'y a pas vraiment d'autre solution
int cas = elfront->PtEI()->Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt ? cas= " << cas <<", ";
this->Affiche(1);
};
return cas; // si != 0 le point est interne
};
// 2) === suite pour le cas différent des angles morts
// 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
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_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
{ int cas = elem.Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt (particulier 1 surface) ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas > 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
{ int cas = elem.Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt (particulier 2 surface) ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas > 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
{ int cas = elem.Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt (particulier 3 surface) ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas > 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
{ int cas = elem.Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt (particulier 4 surface) ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas > 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
{ int cas = elem.Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Contact: ";
cout << " Interne_tdt (particulier 5 surface) ? cas= " << cas <<", ";
this->Affiche(1);
};
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
// //debug
// cout << "\n debug ElContact::Trajectoire: "; this->Affiche(1);
// cout << "\n Vinitial= "<< V
// << "\n type de frontiere: " << (elfront->Eleme())->TypeFrontiere();
// if (actif)
// cout << "\n actif " << actif;
// // fin debug
// ------- 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
// ----- on traite les cas particuliers des éléments d'angle mort
// ---- on regarde si on veut une normale lissée
// ou s'il s'agit d'angle mort
if ((normale_lisser) || (elfront->Angle_mort()))
{// dans le cas d'une normale lissée on va utiliser une interpolation des normales aux noeuds
ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
// recup et actualisation du dernier plan tangent, coordonnées locale etc.
// dimensionnement des variables de tangence
Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
// //debug
// cout << "\n debug ElContact::Trajectoire: ";
// cout << "\n elfro.DernierTangent " << flush;
// // fin debug
elfro.DernierTangent(dr,pl,indic,false);
// récup des fonctions phi
const Vecteur& phii = elfro.Phi();
// on parcours les noeuds de la frontière
// retourne le tableau de noeud en lecture lecture/écriture
Tableau <Noeud *>& tNfront = elfro.TabNoeud();
int nbNfront = tNfront.Taille();
Coordonnee Nnoe(dim); // variable inter
for (int inoe = 1;inoe <= nbNfront;inoe++)
{ const TypeQuelconque& tiq = tNfront(inoe)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
Nnoe = gr.ConteneurCoordonnee_const();
N += phii(inoe)*Nnoe;
};
double norme = N.Norme();
// //debug
// cout << "\n debug ElContact::Trajectoire: ";
// cout << "\n norme= "<< norme;
// cout << " elfro.TypeFrontiere()= "<< elfro.TypeFrontiere() << flush;
// // fin debug
// dans le cas improbable, mais qui arrive, que norme = 0:
// cas par exemple d'un élément dont la somme des normales aux == 0
// on se rabat sur le calcul classique
if (Dabs(norme) < ConstMath::petit)
{// 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);
}
else // sinon c'est ok
{N /= norme;
V=N;
};
test = type_trajectoire_tdt = 5;
}
// --- on continue avec les éléments qui ne sont pas d'angle mort et sans lissage
else
{
// //debug
// cout << "\n debug ElContact::Trajectoire: ";
// cout << " elfro.TypeFrontiere()= "<< elfro.TypeFrontiere() << flush;
// // fin debug
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;
};
}
else
{ // ------- 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 <Noeud *>& 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();
bool rien_ne_bouge = true;
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; V=V11;rien_ne_bouge=false;};
// 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; V = V11;rien_ne_bouge=false;};
// -<<>>-- là vraiment il n'y a rien qui bouge sur la frontière
// --on prendra comme direction la normale a l'element
if (rien_ne_bouge)
// recherche de la normale ,traitement suivant les different cas
{ // dimensionnement des variables de tangence (plan ou droite)
int dim = noeud->Dimension(); // dimension des points
// on traite les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ if (elfro.TypeFrontiere() == "FrontPointF")
{// s'il s'agit d'un point il n'y a pas d'existance de normale
// // on remplace la notion de normale par le vecteur qui joint le noeud à la position
// // du point frontière
// V = elfro.Ref()- noeud->Coord2();
// on utilise la normale au noeud
const TypeQuelconque& tiq = tabNoeud(2)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
V = gr.ConteneurCoordonnee_const();
}
else
{ cout << "\n *** cas element Angle_mort actuellement non implante: , "
<< elfro.TypeFrontiere()
<< "\n ElContact::Trajectoire(int & test)";
Sortie(1);
};
}
else
{ 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;
};
}
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;};
};
// //debug
// cout << "\n debug ElContact::Trajectoire: V= " << V << flush;
// // fin debug
// retour
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
// on traite tout d'abord les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ if (elfro.TypeFrontiere() == "FrontPointF")
{// s'il s'agit d'un point il n'y a pas d'existance de normale
const TypeQuelconque& tiq = tabNoeud(2)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
N = gr.ConteneurCoordonnee_const();
// l'intersection est considérée toujours valide et est égale aux coordonnées
// du point frontière
return elfro.Ref();
}
else
{ cout << "\n *** cas element Angle_mort actuellement non implante: , "
<< elfro.TypeFrontiere()
<< "\n ElContact::Intersection(...";
Sortie(1);
};
}
else
{ // cas des éléments de contact autres que ceux qui décrivent les angles morts
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() == 29)
// {cout << "\n debug : ElContact::Intersection(.. ";
// // on vérifie la perpendicularité
// double perpen = dr.VecDroite() * V;
// cout << "\n diff normale : "<< perpen ;
// cout << " N= ";
// cout <<endl;
// };
// //---- fin debug
// --- def de la droite de trajectoire
// dans le cas où le précédent point est libre (pas de projection systématique) on retient le point à t
// dans le cas où il y a une projection systématique on retient le point à tdt, car il s'agit de la simple
// projection du point final sur la facette
Coordonnee pointDeBase = noeud->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() == 29)
// {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() == 29)
// {cout << "\n debug : ElContact::Intersection(.. ";
// // on vérifie la perpendicularité
// double perpen = dr.VecDroite() * droite.VecDroite();
// cout << " diff normale2 : "<< perpen ;
// cout <<endl;
// };
// //---- fin debug
// cas général : algorithme de recherche d'intersection
// - initialisation
int intp = 0; // indicateur de recherche de pt d'inter
Coordonnee M(dim); // le point cherché d'intersection avec la surface
Coordonnee M1; // le point courant de la surface
int compteur = 0; double nm = 0.; // grandeurs de contrôle
double max_compteur = ParaGlob::param->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 > 0 ) { 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();
//// debug
//{ double d = newtra.Norme();
// // if (d <= ConstMath::trespetit)
// if (d <= ConstMath::petit) // *****pour test
// { cout << "\n*** (1) debug ElContact::Intersection : la norme du vecteur est trop petite !";
// cout <<"\nnorme = " << d << " newtra= " << newtra ;
// }
//}
//// fin debug
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 > 0) { 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 > 0) { 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);
// // debug
// { double d = newtra.Norme();
// // if (d <= ConstMath::trespetit)
// if (d <= ConstMath::petit) // *****pour test
// { cout << "\n*** (2) debug ElContact::Intersection : la norme du vecteur est trop petite !";
// cout <<"\nnorme = " << d << " newtra= " << newtra ;
// }
// }
// // fin debug
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 > 0) { 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 (Permet_affichage() >= 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 (Permet_affichage() >= 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 <Noeud *>& 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<int> 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 <Enum_ddl> 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 <Noeud *> 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
// retourne:
// 0 : dans le cas ou on ne trouve pas d'intersection, cas d'une intersection qui n'est pas calculable
// 1 : contact ok, sur l'élément
// -1 : contact ok, mais hors de l'élément (là, on a parcouru tous les mitoyens et aucun ne convient
// du coup on utilise l'élément initial pour la projection
// 2 : changement de frontière, et contact ok sur la nouvelle frontière
// NB: sauf pour le cas 0, dans tous les autres cas, les grandeurs locales sont correctement calculées
// c-a-d : la projection, la normale
// en fonction de la méthode de contact, le noeud est ramené éventuellement sur la frontière
int 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
int nb_change_frontiere_max = 4; // **** à mettre ensuite en paramètre
#ifdef MISE_AU_POINT
if (!actif)
{cout << "\n ElContact::Actualisation(., actif= "<< actif
<< " l'element n'est pas actif, ce n'est pas normal, Actualisation ne s'applique "
<< " qu'a un element actif ! ";
};
#endif
int intersec = 0; // init: pour l'instant pas d'intersection
int passage_par_angle_mort=0; // pour le passage d'angle mort à normal
Coordonnee M1;
Coordonnee N_sauve = N; // pour un retour si l'intersection ne peut-être calculé
// cependant le cas des angles morts est particulier, on commence par le traiter
if (elfront->Angle_mort())
{ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
if (elfro.TypeFrontiere() == "FrontPointF")
{// s'il s'agit d'un point il n'y a pas d'existance de normale
// // on remplace la notion de normale par le vecteur qui joint le noeud à la position
// // du point frontière
// Coordonnee V = elfro.Ref()- noeud->Coord2();
const TypeQuelconque& tiq = tabNoeud(2)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
N = gr.ConteneurCoordonnee_const();
// l'intersection avec la frontière est systématiquement le point frontière
// même si on change de frontière (c'est pour simplifier le calcul de M1
// qui sera mieux calculé au prochain appel)
M1 = elfro.Ref();
intersec=-1; // init à minima
// la seule chose que l'on peut faire pour valider le fait qu'il y a contact ou pas
// c'est de tester si le noeud est à l'intérieur de l'élément d'angle mort ou pas
// c'est plus long qu'un test de surface mais il n'y a pas vraiment d'autre solution
int cas = elfront->PtEI()->Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Actualisation: ";
cout << " Interne_tdt ? cas= " << cas <<", ";
this->Affiche(1);
};
// pour éviter les flip flop, si on a eu trop de changement de frontière
// on valide de manière arbitraire le choix actuel
if (nb_change_frontiere > nb_change_frontiere_max)
{cas = 1;
if (Permet_affichage() > 5)
{cout << "\n -- nb_change_frontiere: " << nb_change_frontiere
<< " on impose cas = 1 " ;
};
};
if (!cas)
// le point n'est pas dans l'élément on essaie les éléments voisins
// on itere sur les elements voisins
{const Tableau <Front*>* ta = elfront->TabMitoyen();
if (ta != NULL) // cas où il y a des éléments voisins !
{ int ta_taille_et1 = 1+ta->Taille();
for (int i=1; i < ta_taille_et1; i++)
{ cas = (*ta)(i)->PtEI()->Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Actualisation: ";
cout << " Interne_tdt sur mitoyen d'angel mort ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas)
// on a trouvé un élément mitoyen qui contient le point
{// --- changement d'element frontiere
if (Permet_affichage() > 2)
{cout << "\n change front. du noeud "<< noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
<< " ==> ";
elfront->Affiche(1);
if (Permet_affichage() > 4)
cout << " ( mitoyen: " << i << " )" ;
};
// on commence par sauvegarder (*ta)(i) en créant une copie
Front* newelfront = new Front(*((*ta)(i)));
// Libere(); // on supprime le elfront actuel, donc le tableau ta
// on ne peut pas supprimer le elfront, car il est également pointé par elfront_t
// du coup ce sera fait dans la méthode ElContact::TdtversT()
elfront = newelfront; // on récupére le nouvelle élément créé
if (Permet_affichage() > 2)
{cout << " --> nevez ";
elfront->Affiche(1);
};
Construction_TabNoeud(); // on reconstruit le tableau de noeud global
nb_change_frontiere++; // on incrémente
intersec = 2;
passage_par_angle_mort=2;
};
if (intersec)
break;
};
};
}
else // l'intersection est ok
{intersec = 1; };
}
else
{ cout << "\n *** cas element Angle_mort actuellement non implante: , "
<< elfro.TypeFrontiere()
<< "\n ElContact::Actualisation()";
Sortie(1);
};
}
// ---- la suite concerne des éléments autres que ceux d'angle mort
else
{// 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;
// calcul de l'intersection de la pseudo-trajectoire avec la frontiere
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)
{intersec = 0;}
else // sinon on peut continuer
{intersec=-1; // init à minima
// maintenant on regarde si l'intersection est acceptable
// - 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();
int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
if ((elfro.InSurf(extra_in_surface))
|| (nb_change_frontiere > nb_change_frontiere_max) // pour limiter les flip-flop
)
// 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
{ intersec = 1;
}
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 <Front*>* ta = elfront->TabMitoyen();
if (ta != NULL) // cas où il y a des éléments voisins !
{for (int i=1; i<= ta->Taille(); i++)
{ bool mitoyen_valider = false;
// le cas des angles morts est particulier, on commence par le traiter
if ((*ta)(i)->Angle_mort())
{ ElFrontiere & elfroto = *((*ta)(i)->Eleme()); // pour commodite
if (elfroto.TypeFrontiere() == "FrontPointF")
{// s'il s'agit d'un point il n'y a pas d'existance de normale
const TypeQuelconque& tiq = tabNoeud(2)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
V = gr.ConteneurCoordonnee_const();
// la seule chose que l'on peut faire pour valider le fait qu'il y a contact ou pas
// c'est de tester si le noeud est à l'intérieur de l'élément d'angle mort ou pas
// c'est plus long qu'un test de surface mais il n'y a pas vraiment d'autre solution
int cas = (*ta)(i)->PtEI()->Interne_tdt(noeud->Coord2());
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::Actualisation: ";
cout << " Interne_tdt sur mitoyen ? cas= " << cas <<", ";
this->Affiche(1);
};
if (cas) // si true, le point est interne
{M1 = elfroto.Ref();
N = V;
mitoyen_valider = true;
};
}
else
{ cout << "\n *** cas element Angle_mort actuellement non implante: , "
<< elfroto.TypeFrontiere()
<< "\n ElContact::Actualisation()";
Sortie(1);
};
}
else // ---- la suite concerne des éléments autres que ceux d'angle mort
{ElContact elct((*ta)(i),noeud,fct_nD_contact); // on cree un element contact pour utiliser ses methodes
Coordonnee M1_new;
M1_new = 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_new.Dimension() != 0)
{ if ((elct.Elfront()->Eleme()->InSurf(extra_in_surface))
|| (nb_change_frontiere > nb_change_frontiere_max) // pour éviter les flip-flop
)
// on a trouve une bonne intersection
{ mitoyen_valider = true;M1 = M1_new;};
};
};
// si le mitoyen est validé on change de Front pour l'élément de contact
if (mitoyen_valider)
{ // --- changement d'element frontiere
if (Permet_affichage() > 2)
{cout << "\n change front. du noeud "<< noeud->Num_noeud() <<" mail= " << noeud->Num_Mail()
<< " == ";
elfront->Affiche(1);
if (Permet_affichage() > 4)
cout << " ( mitoyen: " << i << " )" ;
};
// on commence par sauvegarder (*ta)(i)
Front* newelfront = new Front(*((*ta)(i)));
// Libere(); // on supprime le elfront actuel, donc le tableau ta
// on ne peut pas supprimer le elfront, car il est également pointé par elfront_t
// du coup ce sera fait dans la méthode ElContact::TdtversT()
elfront = newelfront; // on récupére le nouvelle élément créé
if (Permet_affichage() > 2)
{cout << " --> nevez ";
elfront->Affiche(1);
};
Construction_TabNoeud(); // on reconstruit le tableau de noeud global
nb_change_frontiere++;
intersec = 2;
// si le nouvel élément de frontière est un angle mort, alors la normale
// a été calculée dans Intersection, donc pas la peine de la recalculer
break;
};
};
};
};
};
}; // fin du test sur les front d'angle mort
if (intersec != 0)
{Mtdt = M1; // sauvegarde du point d'intersection
int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
// 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;
};
if (Permet_affichage() > 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();
};
};
}
else // cas où l'intersection n'est pas calculable
// on remet les choses à l'état initiale
{Mtdt = Mt;
N = N_sauve;
}
#ifdef MISE_AU_POINT
if (Permet_affichage() > 2)
{cout << "\n ElContact::Actualisation(., intersec= "<< intersec;
};
#endif
// retour du type d'intersection
return intersec;
};
// 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
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
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_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 (Permet_affichage() > 4)
{cout << "\n cas d'une reaction negative:"<<-r<<", nb decollement ("
<< nb_decol_tdt << "): >= le nombre de decollement ("
<< ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise()
<< ") tolere ";
Affiche(1);
};
if (Permet_affichage() >= 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 (Permet_affichage() > 4)
{cout << "\n cas d'une reaction negative:"<<-r<<", et "
<< "d'un gap > Dabs(borne_regularisation) ("
<< Dabs(borne_regularisation) << " * typededecolement ("
<< typededecolement << "), nb decollement ("
<< nb_decol_tdt << "): >= le nombre de decollement ("
<< ParaGlob::param->ParaAlgoControleActifs().NbDecolAutorise()
<< ") tolere ";
Affiche(1);
};
if (Permet_affichage() >= 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
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_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;
// on regarde si on a changé de elfront
if (elfront != elfront_t)
// cas où on a changé de frontière
{ delete elfront_t; // suppression de la frontière ancienne
elfront_t = elfront; // mise à jour
};
noeud_t = noeud;
tabNoeud_t = tabNoeud;
nb_change_frontiere = 0; // initialisé à chaque fois
};
// 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;
// on regarde si on a changé de elfront
if (elfront != elfront_t)
// cas où on a changé de frontière
{ delete elfront; // suppression de la nouvelle frontière
elfront = elfront_t; // retour sur l'ancienne frontière
};
noeud = noeud_t;
tabNoeud = tabNoeud_t;
nb_change_frontiere = 0; // initialisé à chaque fois
};
//----- 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);
elfront_t=elfront;
noeud_t = noeud;
tabNoeud_t = tabNoeud;
};
// é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 = elfront_t = NULL;
};
// construction du tableau de tous les noeuds, le premier est celui esclave
// et mise à jour de ddlElement et de list_Ddl_global éventuellement
// et mise à jour des grandeurs liées à elfront: concerne le dimensionnement
// si on change d'elfront -> peut changer le nombre de noeud maître d'où
// il faut redimensionner: tabForce_cont,tabForce_cont_t;
void ElContact::Construction_TabNoeud()
{ // def du tableau de l'element frontiere
Tableau <Noeud *>& 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<Ddl> 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);
};
// mise à jour des grandeurs liées à elfront: concerne le dimensionnement
// si on change d'elfront -> peut changer le nombre de noeud maître d'où
// il faut redimensionner: tabForce_cont,tabForce_cont_t;
tabForce_cont.Change_taille(taile-1);
tabForce_cont_t.Change_taille(taile-1);
// on init à 0
for (int i=1; i< taile; i++)
{tabForce_cont(i).Zero();
tabForce_cont_t(i).Zero();
};
// --- 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 <DdlElement>::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 "<<endl;
Sortie(1);
};
// sinon c'est ok
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
Grandeur_scalaire_entier& gr = *((Grandeur_scalaire_entier*) gr_quelc->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 <double> & 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;
};