Herezh_dev/contact/ElContact_2.cc

3276 lines
171 KiB
C++
Raw Normal View History

// 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.
//
2023-05-03 17:23:49 +02:00
// 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 "TypeQuelconqueParticulier.h"
// --- calcul des puissances virtuelles développées par les efforts de contact ----------
// et eventuellement calcul de la raideur associé
// -> explicite à tdt
Vecteur* ElContact::SM_charge_contact()
{
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
{cout << "\n -- ElContact::SM_charge_contact: ";this->Affiche(1);}
int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
//cout << "\n -- debug ElContact::SM_charge_contact: contactType= " << contactType;
// def de quelques dimensions pour simplifier
int dima = ParaGlob::Dimension();
int tab_taille = tabNoeud.Taille();
int nbddl = ddlElement_assemblage->NbDdl();
energie_penalisation = 0.;
energie_frottement.Inita(0.);
// récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
RecupPlaceResidu(nbddl);
Vecteur& SM_res = *residu; // pour simplifier
Mise_a_jour_ddlelement_cas_solide_assemblage(); // mise à jour de ddl element et de cas_solide
// la suite de la méthode ne fonctionne que pour les type 2 et 4 de contact,
// dans le cas contraire on revient directement
if (!((contactType == 2) || (contactType == 4) || (contactType == 41)|| (contactType == 42)))
return residu;
// ---- sinon .... cas du contact par pénalisation -----
// dans le cas 2: on calcul un facteur de pénalisation
// dans le cas 4: on déduit le facteur de pénalisation à partir des forces internes
// et de la condition cinématique de contact
// on considère ici que le point de contact est déterminé et on s'occupe de déterminer les
// efforts éventuels dus au contact ainsi que les énergies échangées sur le pas de temps
// a priori on suppose que le contact est collant --> calcul des efforts de contact
Coordonnee Noe_atdt = noeud->Coord2(); // récup de la position actuelle du noeud projectile
// recup des dernières différentes informations calculées au niveau de la cinématique de contact
Coordonnee M_impact; // le point d'impact, la normale
Vecteur phii;
RecupInfo(N,M_impact,phii,false);
// en fait due aux différents algos de recherche de contact, normalement la position de contact est sauvegardée
// dans l'élément, donc on utilise cette info, par contre on utilise RecupInfo pour calculer les autres infos : normale et phi
// changement éventuel par une moyenne glissante des positions successive du noeud esclave
// Noe_atdt est modifié éventuellement
ChangeEnMoyGlissante(Noe_atdt);
// calcul de la pénétration normale: deltaX=de la surface au point pénétré
Coordonnee deltaX(dima);
switch (contactType)
{ case 2: // cas d'une pénalisation classique
case 41: case 42:// idem après le basculement du cas 4
{ deltaX = Noe_atdt - M_impact;
break;
}
case 4: // cas ou le noeud à été projeté sur la surface
// normalement Noe_atdt est identique à M_impact
{ deltaX = M_noeud_tdt_avant_projection - Noe_atdt;
break;
}
default: cout << "\n erreur, le cas contactType = " << contactType
<< " ne devrait pas exister ici !! "<< endl;
Sortie(1);
break;
};
// le N sort de la surface maître, donc rentre dans la surface esclave
double gap= N * deltaX; // gap est négatif quand il y a pénétration
2023-05-03 17:23:49 +02:00
if ((Permet_affichage() > 7) && (contactType==4))
{double a = (deltaX - gap*N).Norme(); // on calcule pour vérifier
cout << " diff_projX= "<< a; // l'erreur de projection normale
};
// récupération du facteur de pénalisation adaptée au cas de calcul et à la géométrie
double d_beta_gap=0.; // init de la dérivée du facteur de pénalisation / au gap
// calcul du facteur de pénalisation si le contact est de type 2
if (contactType == 2)
{ penalisation = CalFactPenal(gap,d_beta_gap,contactType);}
// sinon dans le cas 41 on utilise la valeur qui est en cours pondéré dans une moyenne glissante
// avec le type 4
else if (contactType == 41) // après basculement du 4 on utilise la pénalisation
{ double essai_penalisation = CalFactPenal(gap,d_beta_gap,contactType);
// maintenant on va calculer la moyenne glissante, de manière à lisser les variations
ElContact::Moyenne_glissante_penalisation(penalisation, essai_penalisation);
};
// si on est en 42, on conserve le facteur précédemment calculé
gap_tdt = gap; // sauvegarde
/* // debug
//cout << "\n noeud: " << noeud->Num_noeud() <<" mailage:"<<noeud->Num_Mail()<< " : gap= " << gap <<" \n Noe_atdt ";Noe_atdt.Affiche(); cout << " Noe_a0:"; noeud->Coord0().Affiche();
//cout << " Noe_at:"; noeud->Coord1().Affiche();
//cout << "\n M_impact:"; M_impact.Affiche(); cout << "\n deltaX:"; deltaX.Affiche();
//cout << "\n N:"; N.Affiche(); cout << " debug ElContact::SM_charge_contact()"<<endl;
//// fin debug
// limitation éventuelle au niveau de la pénétration maxi
// double max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi(); */
int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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();}
// pour l'instant je supprime le cas de la limitation du déplacement, car je pense qu'il faudrait y adjoindre les forces
// de réaction associées sinon l'équilibre est faux !! donc on commente pour l'instant
// méthode de limitation de la pénétration: opérationnelle si max_pene > 0
// si max_pene < 0 on intervient sur l'incrément de temps !!
/* if (max_pene > 0)
{if ((gap < (- max_pene)) && (Dabs(gap) > ConstMath::trespetit))
// on modifie la position du noeud pour tenir compte de la pénalisation
// { Coordonnee nevez_posi(M_impact - 2 * max_pene * N);
{ Coordonnee nevez_posi(M_impact + (max_pene / deltaX.Norme()) * deltaX);
noeud->Change_coord2(nevez_posi);
gap = - max_pene;
};
};*/
// --- calcul de la force normale
// avec limitation éventuelle de l'intensité de la force de contact
double intens_force = 0. ; // init
bool force_limiter=false;
Coordonnee F_N(dima); // init
switch (contactType)
{ case 2: // cas d'une pénalisation classique
case 41: case 42: // idem après basculement du cas 4
{ intens_force = gap * penalisation; // négatif quand on a pénétration
double max_force_noeud;
if (fct_nD_contact.fct_nD_force_contact_noeud_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_force_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_contact_noeud_maxi);
}
else {max_force_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_contact_noeud_maxi();}
if (Dabs(intens_force) > max_force_noeud)
{intens_force = max_force_noeud * Signe(intens_force);
force_limiter = true;
}
2023-05-03 17:23:49 +02:00
// on recalcul la pénalisation associée
if ((Dabs(gap) > ConstMath::trespetit) && force_limiter)
{penalisation = intens_force / gap;
if (Permet_affichage() > 5)
{cout << " ** limitation penalisation= " << penalisation
<< " intensite force = " << intens_force << flush;};
};
// F_N c'est la force qui appuie sur le noeud esclave d'où le - car intens_force est négatif
F_N = - N * intens_force; //(-gap * penalisation);
break;
}
case 4: // cas ou le noeud à été projeté sur la surface
// on récupère la force de contact via la puissance interne des éléments contenants
// le noeud exclave (le calcul des forces internes doit déjà avoir été effectué)
{ TypeQuelconque_enum_etendu enu(FORCE_GENE_INT);
// récupération du conteneur pour lecture uniquement
const TypeQuelconque& typquel = noeud->Grandeur_quelconque(enu);
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
// signe - car le contact doit s'opposer exactement à l'effort interne
F_N = - cofo.ConteneurCoordonnee_const(); // récup de - la réaction
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6) cout << " F_N(force_interne)= " << F_N << " ";
// en fait on ne va garder que la partie normale à la facette, ce qui laissera le glissement possible
intens_force = - F_N * N; // 1) projection de la réaction
F_N = - N * intens_force; // 2) recalcul uniquement de la partie normale
// on va également tenter un calcul d'une pénalisation équivalente
// penalisation = Dabs(intens_force / (Dabs(gap)));// + ConstMath::unpeupetit)) ;
double max_pene;
if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_pene = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi));
}
else {max_pene = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi());}
// double essai_penalisation; // variable intermédiaire
// if (Dabs(gap) > max_pene)
// {essai_penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
// {essai_penalisation = Dabs(intens_force) / max_pene;
2023-05-03 17:23:49 +02:00
// if (Permet_affichage() > 5) cout << "\n (penalisation limite) ";
// };
// // on tient compte d'un facteur multiplicatif éventuelle
// a priori c'est cette méthode qui est la plus performante (idem implicite)
double essai_penalisation = Dabs(intens_force) / max_pene;
// maintenant on va calculer la moyenne glissante
ElContact::Moyenne_glissante_penalisation(penalisation, essai_penalisation);
// if (Dabs(gap) > max_pene)
// {penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
// {penalisation = Dabs(intens_force) / max_pene;
2023-05-03 17:23:49 +02:00
// if (Permet_affichage() > 5) cout << "\n (penalisation limite) ";
// };
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6) cout << " F_N(pur)= " << F_N << " ";
break;
}
default: break; // déjà vu au dessus
};
F_N_max = Dabs(intens_force); // sauvegarde
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
{cout << " noeud: " << noeud->Num_noeud();
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<<"\n gap= " << gap << " N= " << N << " penalisation= " << penalisation
<< " intensite force = " << intens_force << flush;
};
//cout << "\n SM_charge_contact: penalisation= "<< penalisation;
// -- ici on a un traitement différent suivant typ_cal ---
// Dans le cas du contact 4 on ne s'occupe pas du type de calcul de pénalisation
if (contactType != 4)
{ switch (typ_cal)
{case 1: case 2: case 3: // cas le plus simple : pas de calcul particulier
if (gap > 0) // non ce n'est pas bizarre c'est le cas où le noeud décolle
// c'est aussi le cas où on a un type de calcul de la pénalisation = 4 (il y aura une très légère force de collage pour
// gap > 0 mais < borne_regularisation
// par contre on annulle effectivement le résidu
{ //cout << "\n *** bizarre la penetration devrait etre negative ?? , on annule les forces de contact "
// << "\n ElContact::SM_charge_contact(...";
force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
// au cas où on met à 0 les forces de réaction sur la facette
int nb_n_facette = tabForce_cont.Taille();
for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
{ cout << "\n noeud: " << noeud->Num_noeud() << ": force collage non prise en compte " << force_contact
<< " gap(positif)= " << gap << ", Normale= " << N;
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<< " penalisation= " << penalisation
<< " intensite force = " << intens_force ;
};
// on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
return residu; // les résidu + raideur sont nul à ce niveau de la méthode
};
break;
case 4: case 5:case 6:
if (gap > Dabs(borne_regularisation))
// on est sortie de la zone d'accostage donc on neutralise le contact
{ force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
// au cas où on met à 0 les forces de réaction sur la facette
int nb_n_facette = tabForce_cont.Taille();
for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 6)
{ cout << "\n noeud: " << noeud->Num_noeud()
<< ": force collage non prise en compte " << force_contact
<< " gap(positif et > borne regularisation)= " << gap << ", Normale= " << N;
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<< " penalisation= " << penalisation
<< " intensite force = " << intens_force ;
};
// on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
return residu; // les résidu + raideur sont nul à ce niveau de la méthode
};
break;
case 7: case 8:
// par rapport aux autres cas, on neutralise rien
break;
default :
cout << "\n *** cas pas pris en compte !! \n SM_charge_contact() " << endl;
Sortie(1);
};
};
// -- fin du traitement différent suivant typ_cal ---
/*
////////debug
// if (ParaGlob::NiveauImpression() >= 6)
//// if (noeud->Num_noeud()==113)
// {
//// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113";
// cout << "\n noeud: " << noeud->Num_noeud();
// cout << "\n deltaX " << deltaX
// <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
// <<"\n gap= " << gap << " N= " << N << " penalisation= " << penalisation << endl
// ;
// };
////// fin debug
//////debug
// if (noeud->Num_noeud()==113)
// {
// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113"
// << "\n force " << F_N << " force_limiter "<<force_limiter <<endl
// ;
// };
//// fin debug
// -- debug
//cout << ", F_N= " << (F_N * N) << " (ElContact::SM_charge_contact())" << endl;
// -- fin debug */
// énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
energie_penalisation = 0.5 * intens_force * gap; // la partie déplacement normal
// on initialise la partie frottement avec au moins la partie pénalisation, ensuite
// ce sera éventuellement abondé par le glissement ? ou la force de collage .... en devenir
energie_frottement.ChangeEnergieElastique(energie_penalisation);
// -- maintenant on regarde s'il faut s'occuper du frottement
Coordonnee F_T(dima);
Element * elemf = elfront->PtEI(); // récup de l'élément fini
CompFrotAbstraite* loiFrot = ((ElemMeca*) elemf)->LoiDeFrottement();
penalisation_tangentielle = 0.; // init
bool force_T_limiter = false; // init
if (loiFrot != NULL)
{ // --- cas de l'existance d'une loi de frottement
// calcul du déplacement tangentiel
Coordonnee M_tatdt;
if (Mt.Dimension() != 0)
{M_tatdt = (Mtdt-Mt);} // déplacement total
// sinon Mt n'est pas encore définit donc on ne peut pas calculer le déplacement
// il est donc laissé à 0.
dep_tangentiel = M_tatdt- N * (M_tatdt*N); // on retire le deplacement normal éventuel
// calcul de la force tangentielle en supposant tout d'abord un contact collant
double penalisation_tangentielle;
if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
2023-05-03 17:23:49 +02:00
{penalisation_tangentielle = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationTangentielle);
}
else {penalisation_tangentielle = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
// F_T =dep_tangentiel*(-ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact());
F_T =dep_tangentiel*(-penalisation_tangentielle);
// -- vérification en appelant le comportement en frottement ----
// tout d'abord on récupère le delta t pour le calcul de la vitesse
double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
double unSurDeltat=0;
if (Abs(deltat) >= ConstMath::trespetit)
{unSurDeltat = 1./deltat;}
else
// si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
{ // non un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
if (unSurDeltat < 0)
{ cout << "\n le pas de temps est négatif !! "
<< "\n ElContact::SM_charge_contact(...";
};
unSurDeltat = ConstMath::tresgrand;
};
// calcul des vitesses
Coordonnee vit_T = dep_tangentiel * unSurDeltat;
// appel de la loi de comportement: calcul de la force de frottement et des énergies échangées
Coordonnee nevez_force_frot;EnergieMeca energie;
bool glisse = loiFrot->Cal_explicit_contact_tdt(vit_T,N,F_N,F_T,energie,deltat,nevez_force_frot);
// if (vit_T * nevez_force_frot > 0)
// cout << "\n bizarre puissance de frottement positive !";
if (glisse) // on remplace la force de frottement si ça glisse sinon on conserve F_T
F_T = nevez_force_frot;
// --- calcul des énergies échangées
energie_frottement += energie;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
{ cout << "\n deltaX_T: " << dep_tangentiel
<<"\n vit_T= " << vit_T << " glisse= " << glisse
<< " penalisation_tangentielle= " << penalisation_tangentielle;
};
}
else if ( cas_collant)
{ // --- cas d'un contact collant sans loi de frottement explicite
// calcul du déplacement tangentiel par rapport au premier point de contact
ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
const Coordonnee & M_C0 = elfro.Metrique()->PointM_tdt // ( stockage a tdt)
(elfro.TabNoeud(),phi_theta_0);
Coordonnee M_0atdt = (Noe_atdt-M_C0); // déplacement total à partir du point d'impact initial
// transportée via l'interpolation: c-a-d les phi_theta_0 qui restent constant
dep_tangentiel = M_0atdt- N * (M_0atdt*N); // on retire le deplacement normal éventuel
double dep_T = dep_tangentiel.Norme();
// calcul de la pénalisation
double d_beta_dep_T=0.; // init de la dérivée du facteur de pénalisation / au déplacement
// pour l'instant ne sert pas
penalisation_tangentielle = CalFactPenalTangentiel(dep_T,d_beta_dep_T);
dep_T_tdt = dep_T; // sauvegarde
// calcul de la force tangentielle en supposant un contact collant
F_T = -dep_tangentiel * penalisation_tangentielle;
// limitation éventuelle de la force
double max_force_T_noeud;
if (fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_force_T_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_tangentielle_noeud_maxi);
}
else {max_force_T_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_tangentielle_noeud_maxi();}
double n_F_T = Dabs(penalisation_tangentielle * dep_T);
if (n_F_T > max_force_T_noeud)
{F_T *= max_force_T_noeud/n_F_T;
force_T_limiter = true;
};
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
{ cout << "\n deltaX_T: " << dep_tangentiel
<< " penalisation_tangentielle= " << penalisation_tangentielle;
};
// --- calcul des énergies échangées
// ici il s'agit d'une énergie élastique, que l'on ajoute à la pénalisation normale
// énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
energie_penalisation += Dabs(0.5 * F_T * dep_tangentiel); // pour que le résultat soit > 0
energie_frottement.ChangeEnergieElastique(energie_penalisation);
}; // --- calcul des puissances virtuelles
2023-05-03 17:23:49 +02:00
F_T_max = F_T.Norme(); // sauvegarde
force_contact = F_T + F_N;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 5)
{ cout << "\n noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
2023-05-03 17:23:49 +02:00
cout << " ||F_N||= "<< F_N.Norme() << " ||F_T||= "<< F_T_max;
if (force_limiter) cout << " force normale en limite " ;
if (force_T_limiter) cout << " force tangentielle en limite " ;
};
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
cout << "\n ==> force contact imposee au residu (noeud:" << noeud->Num_noeud()
<< " maillage:"<< noeud->Num_Mail() << ") " << force_contact;
/* ////debug
// if (noeud->Num_noeud()==207)
// {
// cout << "\n debug : ElContact::SM_charge_contact(): noeud 113";
// cout << "\n noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
// if (force_limiter) cout << " force en limite " ;
// };
//// fin debug
// -- debug
//double inten = force_contact.Norme();
//if (inten > 0)
// cout << "\n force_contact = " << force_contact << " (ElContact::SM_charge_contact())" << endl;
// -- fin debug */
int posi = Id_nom_ddl("R_X1") -1; // préparation pour les réactions
Ddl_enum_etendu& ddl_reaction_normale=Ddl_enum_etendu::Tab_FN_FT()(1);
Ddl_enum_etendu& ddl_reaction_tangentielle=Ddl_enum_etendu::Tab_FN_FT()(2);
// une petite manip pour le cas axisymétrique: dans ce cas les ddl à considérer pour le résidu et la raideur
// doivent être uniquement x et y donc 2 ddl au lieu de 3. (rien ne dépend de z)
int nb_ddl_en_var = dima; // init
bool axi = false;
if (ParaGlob::AxiSymetrie())
{ nb_ddl_en_var -= 1; axi = true;};
// a- cas du noeud projectile
int ism=1;
if ((cas_solide == 0 ) || (cas_solide == 1))
// cas où le noeud est libre
{for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++) // pour le noeud projectile la vitesse virtuelle associé est
{ SM_res(ism)= force_contact(ix); // directement la vitesse du noeud
// on abonde au niveau de la réaction au noeud
noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
};
}
else
// on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
{for (int ix=1;ix<=dima;ix++) // pour le noeud projectile la vitesse virtuelle associé est
// on abonde au niveau de la réaction au noeud
noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
};
// dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// if (axi) ism++; // qui n'est pas pris en compte // on abonde au niveau de la réaction normale et tangentielle pour le noeud esclave
noeud->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force;
double intensite_tangentielle = F_T.Norme();
noeud->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle;
// b- cas de la surface cible
if ((cas_solide == 0 ) || (cas_solide == 2))
// cas où la facette est libre
{for (int ir=1;ir<=tab_taille-1;ir++)
{ Noeud* noe = tabNoeud(ir+1); // pour simplifier
tabForce_cont(ir) = -force_contact*phii(ir);
for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++)
{ double force_imp = -force_contact(ix)*phii(ir);
SM_res(ism)= force_imp;
// on abonde au niveau de la réaction au noeud
noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
};
// dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// if (axi) ism++; // qui n'est pas pris en compte
// on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
};
}
else
// on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
{for (int ir=1;ir<=tab_taille-1;ir++)
{ Noeud* noe = tabNoeud(ir+1); // pour simplifier
tabForce_cont(ir) = -force_contact*phii(ir);
for (int ix=1;ix<=dima;ix++)
{ double force_imp = -force_contact(ix)*phii(ir);
// on abonde au niveau de la réaction au noeud
noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
};
// on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
};
};
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 7)
{ cout << "\n =-=-=- bilan sur le calcul de l'element de contact: =-=-=- ";
this->Affiche();
};
/* // retour
////debug
// cout << "\n debug : ElContact::SM_charge_contact()";
//noeud->Affiche();
//for (int ir=1;ir<=tab_taille-1;ir++)
// tabNoeud(ir+1)->Affiche();
//
// cout << "\n residu " << *residu <<endl;
// fin debug */
return residu;
};
// -> implicite,
Element::ResRaid ElContact::SM_K_charge_contact()
2023-05-03 17:23:49 +02:00
{ if (Permet_affichage() > 5)
{cout << "\n -- SM_K_charge_contact: ";this->Affiche(1);};
// le contact 4 passe en 41 ou 42 quand on dépasse un nombre donné d'itérations par exemple
int contactType = ElContact::Recup_et_mise_a_jour_type_contact();
// préparation du retour
Element::ResRaid el;el.res=NULL;el.raid=NULL;
energie_penalisation = 0.;
energie_frottement.Inita(0.);
Mise_a_jour_ddlelement_cas_solide_assemblage(); // mise à jour de ddl element et de cas_solide
// dans le cas du modèle de contact cinématique, on n'a pas de contribution (pour l'instant) au second membre et à la raideur
// cela pourrait changer si l'on considérait le frottement, mais pour l'instant ce n'est pas le cas
// on retourne un pointeur null
if (contactType == 1)
return el;
// def de quelques dimensions pour simplifier
int dima = ParaGlob::Dimension();
int tab_taille = tabNoeud.Taille();
int nbddl = ddlElement_assemblage->NbDdl();
// récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
RecupPlaceResidu(nbddl);
Vecteur& SM_res = *residu; // pour simplifier
// idem pour la raideur
RecupPlaceRaideur(nbddl);
// ---- initialisation de SM et de la raideur
SM_res.Zero();raideur->Initialise(0.0);
el.res = residu;
el.raid = raideur;
// la suite de la méthode ne fonctionne que pour les type 2 et 4 de contact,
// dans le cas contraire on revient directement
if (!((contactType == 2) || (contactType == 4) || (contactType == 41) || (contactType == 42)))
return el;
// ---- sinon .... cas du contact par pénalisation -----
// dans le cas 2: on calcul un facteur de pénalisation
// dans le cas 4: on déduit le facteur de pénalisation à partir des forces internes
// et de la condition cinématique de contact
// on considère ici que le point de contact est déterminé et on s'occupe de déterminer les
// efforts éventuels dus au contact ainsi que les énergies échangées sur le pas de temps
// a priori on suppose que le contact est collant --> calcul des efforts de contact
Coordonnee Noe_atdt = noeud->Coord2(); // récup de la position actuelle du noeud projectile
// recup du dernier des différentes informations
Coordonnee M_impact; // le point d'impact, la normale
Vecteur phii;
////debug
2023-05-03 17:23:49 +02:00
// if (noeud->Num_noeud()== 2)
// {
2023-05-03 17:23:49 +02:00
// cout << "\n debug : ElContact::SM_K_charge_contact():"
// << " noeud: " << noeud->Num_noeud() <<" mailage:"<<noeud->Num_Mail()
// << endl;
// };
//// fin debug
2023-05-03 17:23:49 +02:00
// //debug
// if (Permet_affichage() > 4)
// {cout << "\n debug ElContact::SM_K_charge_contact avant RecupInfo " ;
// };
// //fin debug
// d_T_pt: représente la variation du vecteur normale
Tableau <Coordonnee >* d_T_pt = (RecupInfo(N,M_impact,phii,true));
// en fait due aux différents algos de recherche de contact, normalement la position de contact est sauvegardée
// dans l'élément, donc on utilise cette info, par contre on utilise RecupInfo pour calculer les autres infos : normale et phi
// M_impact et Mtdt sont différents uniquement dans le cas d'un restart
// Mtdt est mis à jour pendant la recherche du contact
M_impact = Mtdt;
// changement éventuel par une moyenne glissante des positions successive du noeud esclave
// Noe_atdt est modifié éventuellement
ChangeEnMoyGlissante(Noe_atdt);
// calcul de la pénétration normale
Coordonnee deltaX(dima);
switch (contactType)
{ case 2: // cas d'une pénalisation classique
case 41 : case 42: // idem après basculement du 4
{ deltaX = Noe_atdt - M_impact;
break;
}
case 4: // cas ou le noeud à été projeté sur la surface
// normalement Noe_atdt est identique à M_impact
{ deltaX = M_noeud_tdt_avant_projection - Noe_atdt;
break;
}
default: cout << "\n *** erreur, le cas contactType = " << contactType
<< " ne devrait pas exister ici !! "<< endl;
Sortie(1);
break;
};
double gap= N * deltaX; // ce qui constitue la fonction g(ddl) à annuler voir à minimiser
2023-05-03 17:23:49 +02:00
if ((Permet_affichage() > 7) && (contactType==4))
{double a = (deltaX - gap*N).Norme(); // on calcule pour vérifier
cout << " diff_projX= "<< a; // l'erreur de projection normale
};
////debug
// if (noeud->Num_noeud()==56)
// {
// cout << "\n debug : ElContact::SM_K_charge_contact(): noeud 409"
// << "\n deltaX " << deltaX
// <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
// <<"\n gap= " << gap << " N= " << N << endl
// ;
// };
//// fin debug
// récupération du facteur de pénalisation adaptée au cas de calcul et à la géométrie
double d_beta_gap=0.; // init de la dérivée du facteur de pénalisation / au gap
// calcul du facteur de pénalisation si le contact est de type 2
if (contactType == 2)
{penalisation = CalFactPenal(gap,d_beta_gap,contactType);}
// sinon dans le cas 41 ou 42 on utilise la valeur qui est en cours
// il n'y a pas de différence entre 41 et 42 en implicite
gap_tdt = gap; // sauvegarde
// limitation au niveau du gap à 2 fois la pénétration maxi
// double max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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 typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
//debug
// if (noeud->Num_noeud()==7)
// {double max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();
// if ((gap_t > max_pene) && (gap_tdt > max_pene))
// {cout << "\n debug : ElContact::SM_K_charge_contact(): noeud 7"
// << "\n gap_t " << gap_t << " max_pene= " << max_pene
// <<"\n gap_tdt= " << gap_tdt << " M_impact= " << M_impact
// <<"\n gap= " << gap << " N= " << N << endl;
// };
// };
// fin debug
// pour l'instant je supprime le cas de la limitation du déplacement, car je pense qu'il faudrait y adjoindre les forces
// de réaction associées sinon l'équilibre est faux !! donc on commente pour l'instant
/* // méthode de limitation de la pénétration: opérationnelle si max_pene > 0
// si max_pene < 0 on intervient sur l'incrément de temps !!
if (max_pene > 0)
{if ((typ_cal == 5) && (gap < (- 2 * max_pene)))
// on modifie la position du noeud pour tenir compte de la pénalisation
// { Coordonnee nevez_posi(M_impact - 2 * max_pene * N);
{ Coordonnee nevez_posi(M_impact + (2. * max_pene / deltaX.Norme()) * deltaX);
noeud->Change_coord2(nevez_posi);
};
};*/
// --- calcul de la force normale
// limitation éventuelle de l'intensité de la force de contact
double intens_force = 0. ; // init
bool force_limiter=false;
Coordonnee F_N(dima); // init
double max_force_noeud;
if (fct_nD_contact.fct_nD_force_contact_noeud_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_force_noeud = Valeur_fct_nD(fct_nD_contact.fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_force_contact_noeud_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_contact_noeud_maxi);
}
else {max_force_noeud = ParaGlob::param->ParaAlgoControleActifs().Force_contact_noeud_maxi();}
switch (contactType)
{ case 2: // cas d'une pénalisation classique
case 41: case 42: // idem après basculement du cas 4
{ intens_force = gap * penalisation; // négatif quand on a pénétration
if (Dabs(intens_force) > max_force_noeud)
{intens_force = max_force_noeud * Signe(intens_force);
force_limiter = true;
};
// on recalcul la pénalisation associée
if ((Dabs(gap) > ConstMath::trespetit) && force_limiter)
{penalisation = intens_force / gap;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
{cout << " ** limitation penalisation= " << penalisation
<< " intensite force = " << intens_force << flush;};
};
// F_N c'est la force qui appuie sur le noeud esclave d'où le - car intens_force est négatif
F_N = - N * intens_force; //(-gap * penalisation);
break;
}
case 4: // cas ou le noeud à été projeté sur la surface
// on récupère la force de contact via la puissance interne des éléments contenants
// le noeud exclave (le calcul des forces internes doit déjà avoir été effectué)
{ TypeQuelconque_enum_etendu enu(FORCE_GENE_INT);
// récupération du conteneur pour lecture uniquement
const TypeQuelconque& typquel = noeud->Grandeur_quelconque(enu);
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
// signe - car le contact doit s'opposer exactement à l'effort interne
F_N = - cofo.ConteneurCoordonnee_const(); // récup de - la réaction
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6) cout << " F_N(force_interne)= " << F_N << " ";
// en fait on ne va garder que la partie normale à la facette, ce qui laissera le glissement possible
intens_force = - F_N * N; // 1) projection de la réaction
F_N = - N * intens_force; // 2) recalcul uniquement de la partie normale
// on va également tenter un calcul d'une pénalisation équivalente
double max_pene;
if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_pene = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi));
}
else {max_pene = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi());}
// l'idée est de viser la pénétration max_pene, car en pénalisation, le fait
// de conserver la pénétration et la force constatées, ne va pas diminuer la pénétration
// or on aimerait une pénétration petite !! a priori celle = max_pene
// // si cette grandeur est plus petite que gap
// // si par contre max_pene est grand, (ou bien plus grand que gap) on utilise gap
// penalisation = Dabs(intens_force) / (MiN(max_pene, Dabs(gap)));
// if (Dabs(gap) > max_pene)
// {penalisation = Dabs(intens_force) / max_pene; }
// else
// {penalisation = Dabs(intens_force) / Dabs(gap);}
// a priori c'est cette méthode qui est la plus performante
penalisation = Dabs(intens_force) / max_pene;
// if (Dabs(gap) > max_pene)
// {penalisation = Dabs(intens_force) / Dabs(gap);} //(Dabs(gap) + ConstMath::unpeupetit)) ;}
// else // sinon la pénétration est vraiment petite, on va cibler la valeur de max_pene
// {penalisation = Dabs(intens_force) / max_pene;
2023-05-03 17:23:49 +02:00
// if (Permet_affichage() > 5) cout << "\n (penalisation limite) ";
// };
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6) cout << " F_N(pur)= " << F_N << " ";
break;
}
default: break; // déjà vu au dessus
};
F_N_max = Dabs(intens_force); // sauvegarde
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
{cout << " noeud: " << noeud->Num_noeud();
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<<"\n gap= " << gap << " N= " << N << " penalisation= " << penalisation
<< " intensite force = " << intens_force << flush;
};
//cout << "\n SM_K_charge_contact: penalisation= "<< penalisation << " gap= " << gap << " FN= " << F_N ;
2023-05-03 17:23:49 +02:00
//debug
// if ((F_N_max > 5000000) || (noeud->Num_noeud()==2))
// if (penalisation == 0.)
// if (noeud->Num_noeud()==2)
// {
// cout << "\n debug : ElContact::SM_K_charge_contact(): noeud " << noeud->Num_noeud()
// << " zone: " << num_zone_contact
// << "\n force " << F_N << " force_limiter "<<force_limiter <<endl
// <<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
// <<"\n gap= " << gap << " N= " << N
// << " penalisation= " << penalisation << endl
// ;
2023-05-03 17:23:49 +02:00
//// CalFactPenal(gap,d_beta_gap,contactType);
// };
// fin debug
// ici on a un traitement différent suivant les types de contact
// Dans le cas du contact 4 on ne s'occupe pas du type de calcul de pénalisation
if (contactType != 4)
{switch (typ_cal)
{case 1: case 2: case 3: // cas le plus simple : pas de calcul particulier
if (gap > 0) // non ce n'est pas bizarre c'est le cas où le noeud décolle
// c'est aussi le cas où on a un type de calcul de la pénalisation = 4 (il y aura une très légère force de collage pour
// gap > 0 mais < borne_regularisation
// par contre on annulle effectivement le résidu
{ //cout << "\n *** bizarre la penetration devrait etre negative ?? , on annule les forces de contact "
// << "\n ElContact::SM_charge_contact(...";
force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
2023-05-03 17:23:49 +02:00
// au cas où on met à 0 les forces de réaction sur la facette
int nb_n_facette = tabForce_cont.Taille();
for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
if (Permet_affichage() > 6)
{ cout << " noeud: " << noeud->Num_noeud()
<< ": force collage non prise en compte " << force_contact
<< " gap(positif)= " << gap << ", Normale= " << N;
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<< " penalisation= " << penalisation
<< " intensite force = " << intens_force ;
};
// on ne contribue pas aux réactions aux niveaux des noeuds car la valeur que l'on devrait ajoutée est nulle
return el; // les résidu + raideur sont nul à ce niveau de la méthode
};
break;
case 4: case 5: case 6:
if (gap > Dabs(borne_regularisation))
// on est sortie de la zone d'accostage donc on neutralise le contact
{ force_contact=F_N; // on sauvegarde pour le traitement du décollement éventuel
2023-05-03 17:23:49 +02:00
// au cas où on met à 0 les forces de réaction sur la facette
int nb_n_facette = tabForce_cont.Taille();
for (int i=1; i<= nb_n_facette; i++) tabForce_cont(i).Zero();
if (Permet_affichage() >= 6)
{ cout << " noeud: " << noeud->Num_noeud()
<< ": force collage non prise en compte " << force_contact
<< " gap(positif et > borne regularisation)= " << gap << ", Normale= " << N;
cout << "\n deltaX " << deltaX
<<"\n Noe_atdt= " << Noe_atdt << " M_impact= " << M_impact
<< " penalisation= " << penalisation
<< " intensite force = " << intens_force ;
};
// on ne contribue pas aux réactions aux niveaux des noeuds
// car la valeur que l'on devrait ajoutée est nulle
return el; // les résidu + raideur sont nul à ce niveau de la méthode
};
break;
case 7: case 8:
// par rapport aux autres cas, on neutralise rien
break;
default :
cout << "\n *** cas pas pris en compte !! \n SM_K_charge_contact() " << endl;
Sortie(1);
};
};
// énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
energie_penalisation = 0.5 * F_N_max * gap; // la partie déplacement normal
// on initialise la partie frottement avec au moins la partie pénalisation, ensuite
// ce sera éventuellement abondé par le glissement ? ou la force de collage .... en devenir
energie_frottement.ChangeEnergieElastique(energie_penalisation);
// -- maintenant on regarde s'il faut s'occuper du frottement
Coordonnee F_T(dima);
Element * elemf = elfront->PtEI(); // récup de l'élément fini
CompFrotAbstraite* loiFrot = ((ElemMeca*) elemf)->LoiDeFrottement();
penalisation_tangentielle = 0.; // init
bool force_T_limiter = false; // init
if (loiFrot != NULL)
{ // --- cas de l'existance d'une loi de frottement
2023-05-03 17:23:49 +02:00
// calcul du déplacement tangentiel par rapport au premier point de contact
// mis à jour en fonction du glissement éventuelle
ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
const Coordonnee & M_C0 = elfro.Metrique()->PointM_tdt // ( stockage a tdt)
(elfro.TabNoeud(),phi_theta_0);
////---- debug ----
//{const Coordonnee & M_a0 = elfro.Metrique()->PointM_0 // ( stockage a tdt)
// (elfro.TabNoeud(),phi_theta_0);
// cout << "\n debug smK contact: M_a0: ";M_a0.Affiche_1(cout);
// cout << " a tdt: ";M_C0.Affiche_1(cout);
//}
////---- fin debug ---
Coordonnee M_0atdt = (Noe_atdt-M_C0); // déplacement total à partir du point d'impact mis à jour
// transportée via l'interpolation: c-a-d les phi_theta_0 qui restent constant
// ici du au frottement, le point d'impact est mis à jour en fonction du glissement éventuel
dep_tangentiel = M_0atdt- N * (M_0atdt*N); // on retire le deplacement normal éventuel
////---- debug ----
//{ cout << "\n dep_tangentiel: ";dep_tangentiel.Affiche_1(cout);
// cout << "\n Noe_atdt: "; Noe_atdt.Affiche_1(cout);
//}
////---- fin debug ---
double dep_T = dep_tangentiel.Norme();
dep_T_tdt = dep_T; // sauvegarde
// // calcul du déplacement tangentiel: là il s'agit du déplacement relatif entre l'ancien point projeté et le nouveau
//
// Coordonnee M_tatdt(dima);
// if (Mt.Dimension() != 0)
// {M_tatdt = (Mtdt-Mt);} // déplacement total
// ; // sinon Mt n'est pas encore définit donc on ne peut pas calculer le déplacement
// // il est donc laissé à 0.
// dep_tangentiel = M_tatdt- N * (M_tatdt*N); // on retire le deplacement normal éventuel
// calcul de la force tangentielle en supposant tout d'abord un contact collant
double penalisation_tangentielle;
if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
2023-05-03 17:23:49 +02:00
{penalisation_tangentielle = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationTangentielle);
}
else {penalisation_tangentielle = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
// F_T =dep_tangentiel*(-ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact());
F_T =dep_tangentiel*(-penalisation_tangentielle);
// -- verification en appelant le comportement en frottement ----
// tout d'abord on récupère le delta t pour le calcul de la vitesse
double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
double unSurDeltat=0;
if (Abs(deltat) >= ConstMath::trespetit)
{unSurDeltat = 1./deltat;}
else
// si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand
{ // non un pas de temps doit être positif !! or certaine fois il peut y avoir des pb
if (unSurDeltat < 0)
{ cout << "\n le pas de temps est négatif !! "
<< "\n ElContact::SM_charge_contact(...";
};
unSurDeltat = ConstMath::tresgrand;
};
// calcul des vitesses
Coordonnee vit_T = dep_tangentiel * unSurDeltat;
// appel de la loi de comportement: calcul de la force de frottement et des énergies échangées
Coordonnee nevez_force_frot;EnergieMeca energie;
bool glisse = loiFrot->Cal_explicit_contact_tdt(vit_T,N,F_N,F_T,energie,deltat,nevez_force_frot);
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
{ cout << "\n deltaX_T: " << dep_tangentiel
<<"\n vit_T= " << vit_T << " glisse= " << glisse
<< " penalisation_tangentielle= " << penalisation_tangentielle;
};
// *** à faire
// mise à jour du point d'impact en fct du glissement , ou d'un point de référence qui tient compte
// du glissement
// if (vit_T * nevez_force_frot > 0)
// cout << "\n bizarre puissance de frottement positive !";
if (glisse) // on remplace la force de frottement si ça glisse sinon on conserve F_T
F_T = nevez_force_frot;
2023-05-03 17:23:49 +02:00
// --- calcul des énergies échangées
energie_frottement += energie;
}
else if ( cas_collant)
{ // --- cas d'un contact collant sans loi de frottement explicite
// calcul du déplacement tangentiel par rapport au premier point de contact
ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
const Coordonnee & M_C0 = elfro.Metrique()->PointM_tdt // ( stockage a tdt)
(elfro.TabNoeud(),phi_theta_0);
////---- debug ----
//{const Coordonnee & M_a0 = elfro.Metrique()->PointM_0 // ( stockage a tdt)
// (elfro.TabNoeud(),phi_theta_0);
// cout << "\n debug smK contact: M_a0: ";M_a0.Affiche_1(cout);
// cout << " a tdt: ";M_C0.Affiche_1(cout);
//}
////---- debug ---
Coordonnee M_0atdt = (Noe_atdt-M_C0); // déplacement total à partir du point d'impact initial
// transportée via l'interpolation: c-a-d les phi_theta_0 qui restent constant
dep_tangentiel = M_0atdt- N * (M_0atdt*N); // on retire le deplacement normal éventuel
////---- debug ----
//{ cout << "\n dep_tangentiel: ";dep_tangentiel.Affiche_1(cout);
// cout << "\n Noe_atdt: "; Noe_atdt.Affiche_1(cout);
//}
////---- debug ---
double dep_T = dep_tangentiel.Norme();
// calcul de la pénalisation
double d_beta_dep_T=0.; // init de la dérivée du facteur de pénalisation / au déplacement
// pour l'instant ne sert pas
penalisation_tangentielle = CalFactPenalTangentiel(dep_T,d_beta_dep_T);
dep_T_tdt = dep_T; // sauvegarde
// calcul de la force tangentielle en supposant un contact collant
F_T = -dep_tangentiel * penalisation_tangentielle;
// limitation éventuelle de la force
double max_force_T_noeud;
if (fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_force_T_noeud = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_force_tangentielle_noeud_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_force_tangentielle_noeud_maxi));
}
else {max_force_T_noeud = Dabs(ParaGlob::param->ParaAlgoControleActifs().Force_tangentielle_noeud_maxi());}
double n_F_T = Dabs(penalisation_tangentielle * dep_T);
////---- debug ----
//{ cout << "\n n_F_T= " << n_F_T ;
// cout << " F_T: ";F_T.Affiche_1(cout);
//}
////---- debug ---
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
{ cout << "\n deltaX_T: " << dep_tangentiel
<< " penalisation_tangentielle= " << penalisation_tangentielle;
};
if ((n_F_T > max_force_T_noeud) && (max_force_T_noeud > ConstMath::petit))
{F_T *= max_force_T_noeud/n_F_T;
force_T_limiter = true;
// on recalcul la pénalisation associée
if (Dabs(dep_T) > ConstMath::trespetit)
{penalisation_tangentielle = max_force_T_noeud / dep_T;}
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 6)
{cout << " ** limitation penalisation tangentielle= " << penalisation_tangentielle
<< " intensite force = " << max_force_T_noeud << flush;};
};
////---- debug ----
//{ cout << "\n F_T_max= " << n_F_T ;
// cout << " F_T: ";F_T.Affiche_1(cout);
//}
////---- debug ---
// --- calcul des énergies échangées
// ici il s'agit d'une énergie élastique, que l'on ajoute à la pénalisation normale
// énergie élastique de pénalisation: énergie élastique = 1/2 k x^2 = 1/2 F x
energie_penalisation -= 0.5 * F_T * dep_tangentiel; // - pour que le résultat soit > 0
energie_frottement.ChangeEnergieElastique(energie_penalisation);
};
2023-05-03 17:23:49 +02:00
F_T_max = F_T.Norme(); // sauvegarde
// --- calcul des puissances virtuelles
force_contact = F_T + F_N;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
{ cout << " noeud: " << noeud->Num_noeud() << ": force contact " << force_contact ;
2023-05-03 17:23:49 +02:00
cout << " ||F_N||= "<< F_N.Norme() << " ||F_T||= "<< F_T_max;
if (force_limiter) cout << " force normale en limite " ;
if (force_T_limiter) cout << " force tangentielle en limite " ;
};
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
cout << "\n ==> force contact imposee au residu (noeud:" << noeud->Num_noeud()
<< " maillage:"<< noeud->Num_Mail() << ") " << force_contact;
int posi = Id_nom_ddl("R_X1") -1; // préparation pour les réactions
Ddl_enum_etendu& ddl_reaction_normale=Ddl_enum_etendu::Tab_FN_FT()(1);
Ddl_enum_etendu& ddl_reaction_tangentielle=Ddl_enum_etendu::Tab_FN_FT()(2);
// une petite manip pour le cas axisymétrique: dans ce cas les ddl à considérer pour le résidu et la raideur
// doivent être uniquement x et y donc 2 ddl au lieu de 3. (rien ne dépend de z)
int nb_ddl_en_var = dima; // init
bool axi = false;
if (ParaGlob::AxiSymetrie())
{ nb_ddl_en_var -= 1; axi = true;};
// récup du kronecker qui va bien
TenseurHB& IdHB = *Id_dim_HB(ParaGlob::Dimension());
// a- cas du noeud projectile
int ism=1; // init cas normale
if ((cas_solide == 0 ) || (cas_solide == 1))
// cas où le noeud est libre
{for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++) // pour le noeud projectile la vitesse virtuelle associé est
{SM_res(ism) += force_contact(ix); // directement la vitesse du noeud
// F_N = force_contact
// = - N * intens_force = - N * (gap * penalisation)
// = - N * ( (N * deltaX) * penalisation );
// donc force_contact(ix) = - N(ix) * ( (N * deltaX) * penalisation )
// et d_force_contact(ix) / d ddl_iy = - N(ix) * ( (N * d_deltaX_d_ddl_iy ) * penalisation )
// + d(- N(ix))_d_ddl_iy * ( (N * deltaX) * penalisation )
// + - N(ix) * ( (d_N_d_ddl_iy * deltaX) * penalisation )
// + - N(ix) * ( (N * deltaX) * d_penalisation_d_ddl_iy )
// avec d_penalisation_d_ddl_iy = d_penalisation_d_gap * d_gap_d_ddl_iy
// et sachant que d_gap_d_ddl_iy = N(iy) pour le noeud central
// on abonde au niveau de la réaction au noeud
noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
// tout d'abord les termes strictement relatifs au noeud esclave
int jsm=1;
if ( cas_collant)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
{ (*raideur)(ism,jsm) += penalisation * N(ix)*N(iy) // partie classique
//+ N(ix) * ( gap * d_beta_gap * N(iy) ) // partie intégrant la variation de la pénalisation
+ penalisation_tangentielle *(IdHB(ix,iy) - N(ix)*N(iy)) // partie collant
;
};
}
else // sans frottement
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
{ (*raideur)(ism,jsm) += penalisation * N(ix)*N(iy) // partie classique
//+ N(ix) * ( gap * d_beta_gap * N(iy) )
; // partie intégrant la variation de la pénalisation
};
};
//--- fin raideur : noeud esclave - noeud esclave
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// --- ensuite les termes de couplage noeud esclave - noeuds de la facette
if (cas_solide == 0) // cas du bi_déformable, sinon pas de terme de couplage
{int iddl_facette = 1;
if (d_T_pt != NULL) // car même si on l'a demandé, il peut être null s'il n'existe pas (ex cas 1D )
2023-05-03 17:23:49 +02:00
{Tableau <Coordonnee >& d_T = *d_T_pt; // variation du vecteur normale: pour simplifier
if ( cas_collant)
{if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ gap * d_T(iddl_facette)(ix)
+ N(ix) * (d_T(iddl_facette) * deltaX)
)
+ penalisation_tangentielle * phi_theta_0(jr)
*(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
;
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
}
else // sinon deltax est normal à la facette et d_N * deltaX = 0
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ gap * d_T(iddl_facette)(ix)
)
+ penalisation_tangentielle * phi_theta_0(jr)
*(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
;
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
};
}
else // sinon pas collant avec (d_T_pt != NULL)
{if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ gap * d_T(iddl_facette)(ix)
+ N(ix) * (d_T(iddl_facette) * deltaX)
);
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
}
else // sinon deltax est normal à la facette et d_N * deltaX = 0
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy)
+ gap * d_T(iddl_facette)(ix)
);
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
};
};
}
else // sinon cas d_T_pt == NULL et (cas_solide == 0)
{if ( cas_collant)
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy))
+ penalisation_tangentielle * phi_theta_0(jr)
*(-IdHB(ix,iy)+N(ix)*N(iy)); // partie collant
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
};
}
else // sinon cas non collant
{for (int jr=1;jr<=tab_taille-1;jr++) // boucle sur les noeuds de la facette
{ for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++) // boucle sur les ddl
(*raideur)(ism,jsm) += penalisation * ( - phii(jr) * N(ix)*N(iy));
// dans le cas de l'axi il faut décaler jsm, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
};
}; // fin du if (cas_collant)
}; // fin cas d_T_pt == NULL et (cas_solide == 0)
}; // fin du if (cas_solide == 0)
}; // fin de la boucle ix sur le noeud esclave
} // fin de la première partie de: if ((cas_solide == 0 ) || (cas_solide == 1))
2023-05-03 17:23:49 +02:00
else // sinon c-a-d: cas_solide différent de 0 et 1 c-a-d le noeud est bloqué
// on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
{for (int ix=1;ix<=dima;ix++) // pour le noeud projectile la vitesse virtuelle associé est
// on abonde au niveau de la réaction au noeud
noeud->Ajout_val_tdt(Enum_ddl(ix+posi),force_contact(ix));
};
// dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
// if (axi) ism++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// on abonde au niveau de la réaction normale et tangentielle pour le noeud esclave
noeud->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force;
double intensite_tangentielle = F_T.Norme();
noeud->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle;
// b- cas de la surface cible
if ((cas_solide == 0 ) || (cas_solide == 2))
// cas où la facette est libre
// pour les noeud de la facette maître, sachant que l'on a pour la force sur le noeud esclave
// F_N = - N * intens_force = - N * (gap * penalisation) = - N * ( (N * deltaX) * penalisation )
// = force_contact
// donc sur les noeuds "s" de la facette on a :
// F_N^s = phi_s * N * ( (N * deltaX) * penalisation )
// d'autre part on a gap = N * (X(t+dt)-M_impact) = N * (X(t+dt)- phi_r * X(tdt)^r)
// avec X(tdt)^r les coordonnées du noeud r de la facette
// d'où la forme finale pour le noeud "s" de la facette :
// F_N^s = phi_s * N * ( (N * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
// = - phi_s * force_contact
//
// maintenant au niveau des raideurs:
// les raideurs relativements au noeud esclave -> dF_N^s/dX(t+dt)(iy)
// dF_N^s/dX(t+dt)(iy) = phi_s * N * (N(iy)) * penalisation
//
// les raideurs relativements entre noeuds de la facette
// dF_N^s/dX(t+dt)(iy) = phi_s * N * ( (N(iy) * (- phi_r ) * penalisation )
// + phi_s * d_N/dX(t+dt)(iy) * ( (N * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
// + phi_s * N * (d_N/dX(t+dt)(iy) * (X(t+dt)- phi_r * X(tdt)^r)) * penalisation )
// donc force_contact(ix) = - N(ix) * ( (N * deltaX) * penalisation )
// et d_force_contact(ix) / d ddl_iy = - N(ix) * ( (N * d_deltaX_d_ddl_iy ) * penalisation )
// + d(- N(ix))_d_ddl_iy * ( (N * deltaX) * penalisation )
// + - N(ix) * ( (d_N_d_ddl_iy * deltaX) * penalisation )
// + - N(ix) * ( (N * deltaX) * d_penalisation_d_ddl_iy )
// avec d_penalisation_d_ddl_iy = d_penalisation_d_gap * d_gap_d_ddl_iy
// et sachant que d_gap_d_ddl_iy = N(iy) pour le noeud central
{for (int is=1;is<=tab_taille-1;is++)
{ Noeud* noe = tabNoeud(is+1); // pour simplifier
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 7)
cout << "\n reaction facette imposee au residu (noeud:" << noe->Num_noeud()
<< " maillage:"<< noe->Num_Mail() << ") " ;
tabForce_cont(is) = -force_contact*phii(is);
for (int ix=1;ix<=nb_ddl_en_var;ix++,ism++)
{ double force_imp = -force_contact(ix)*phii(is);
SM_res(ism) += force_imp;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 6)
cout << force_imp << " ";
// on abonde au niveau de la réaction au noeud
noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
int jsm = 1;
// tout d'abord le terme de couplage
if (cas_solide == 0) // on intervient que si c'est déformable-déformable
{ if ( cas_collant)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
{ (*raideur)(ism,jsm)
+= - phii(is)
* (penalisation * (N(ix)*N(iy))
+ penalisation_tangentielle * (IdHB(ix,iy) - N(ix)*N(iy))
// partie collant
);
}
}
else // cas non collant
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++)
{ (*raideur)(ism,jsm) += - phii(is) * penalisation * N(ix)*N(iy);}
}
};
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// puis les termes facette - facette
int iddl_facette = 1;
if (d_T_pt != NULL) // car même si on l'a demandé, il peut être null s'il n'existe pas (ex cas 1D )
{Tableau <Coordonnee >& d_T = *d_T_pt; // pour simplifier
if (cas_collant)
{if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm)
+= - phii(is) * ( penalisation
*(N(ix) * ( - phii(js) * N(iy))
+ d_T(iddl_facette)(ix) * gap
+ N(ix) * (d_T(iddl_facette) * deltaX)
)
+ penalisation_tangentielle * phi_theta_0(js)
*(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
} //fin cas actif == 1
else // sinon: actif diff de 1, deltax est normal à la facette et d_N * deltaX = 0
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm)
+= - phii(is) * ( penalisation
* (N(ix) * ( - phii(js) * N(iy))
+ d_T(iddl_facette)(ix) * gap
)
+ penalisation_tangentielle * phi_theta_0(js)
*(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
}; // fin cas actif != 1
}
else // sinon cas non collant
{if (actif==1) // on doit prendre en compte que deltax n'est pas normal à la facette
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm) += - phii(is) * penalisation * (
N(ix) * ( - phii(js) * N(iy))
+ d_T(iddl_facette)(ix) * gap
+ N(ix) * (d_T(iddl_facette) * deltaX)
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
} //fin cas actif == 1
else // sinon: actif diff de 1, deltax est normal à la facette et d_N * deltaX = 0
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm) += - phii(is) * penalisation * (
N(ix) * ( - phii(js) * N(iy))
+ d_T(iddl_facette)(ix) * gap
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
}
}; // fin cas actif != 1
}; // fin du if then else sur : if (cas_collant)
} // fin du cas if (d_T_pt != NULL)
else
{if (cas_collant)
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm)
+= - phii(is) * ( penalisation
* (N(ix) * ( - phii(js) * N(iy)))
+ penalisation_tangentielle * phi_theta_0(js)
*(-IdHB(ix,iy)+N(ix)*N(iy)) // partie collant
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
};
}
else // sinon cas non collant
{for (int js=1;js<=tab_taille-1;js++)
{for (int iy=1;iy<=nb_ddl_en_var;iy++,jsm++,iddl_facette++)
(*raideur)(ism,jsm) += - phii(is) * penalisation * (
N(ix) * ( - phii(js) * N(iy))
);
// dans le cas de l'axi il faut décaler jsm pour la suite, ce qui correspond au z
// if (axi) jsm++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
};
};
}; // fin du cas où d_T_pt == NULL
};
// dans le cas de l'axi il faut décaler ism pour la suite, ce qui correspond au z
// if (axi) ism++; // qui n'est pas pris en compte
// non: 20 mars 2019: maintenant le SM local a juste les ddl de X1 et X2 donc ce qui correspond à nb_ddl_en_var
// du coup on ne décale plus
// on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(is);
noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(is);
};
}
else // *** modif 23 juin 2015 , a virer si c'est ok
// on s'occupe quand même des réactions, ce qui nous permettra de les récupérer même sur un solide
{for (int ir=1;ir<=tab_taille-1;ir++)
{ Noeud* noe = tabNoeud(ir+1); // pour simplifier
tabForce_cont(ir) = -force_contact*phii(ir);
for (int ix=1;ix<=dima;ix++)
{ double force_imp = -force_contact(ix)*phii(ir);
// on abonde au niveau de la réaction au noeud
noe->Ajout_val_tdt(Enum_ddl(ix+posi),force_imp);
};
// on abonde au niveau de la réaction normale et tangentielle pour les noeuds maîtres
noe->ModifDdl_etendu(ddl_reaction_normale).Valeur() += -intens_force*phii(ir);
noe->ModifDdl_etendu(ddl_reaction_tangentielle).Valeur() += intensite_tangentielle*phii(ir);
};
2023-05-03 17:23:49 +02:00
// // --- debug
//{ for (int ir=1;ir<=tab_taille-1;ir++)
// { Noeud* noe = tabNoeud(ir+1); // pour simplifier
// if ((noe->Num_noeud() == 5) && (noe->Num_Mail() == 2))
// {cout << "\n debug : ElContact::SM_K_charge_contact() ";
// cout << " R_X= ";
// for (int ix=1;ix<=dima;ix++)
// cout << noe->Valeur_tdt(Enum_ddl(ix+posi)) << " ";
// }
// }
//}
// // --- fin debug
};
// retour
// return residu; // SM est nul à ce niveau du programme
//// --- debug
//cout << "\n debug : ElContact::SM_K_charge_contact() ";
//SM_res.Affiche();
//raideur->Affiche();
//// --- fin debug
return el;
};
//================================= methodes privées ===========================
// calcul la normale en fonction de differente conditions
Coordonnee ElContact::Calcul_Normale(int dim, Plan & pl, Droite & dr,int indic)
{
Coordonnee N(dim); // le vecteur normal initialisé à 0
2023-05-27 11:33:09 +02:00
ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
2023-05-03 17:23:49 +02:00
// --- le cas des angles morts est particulier, on commence par le traiter
2023-05-27 11:33:09 +02:00
if ((elfront->Angle_mort()) && (elfro.Type_geom_front() == POINT_G))
{ // s'il s'agit d'un point il n'y a pas d'existance de normale
// 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()));
N = gr.ConteneurCoordonnee_const();
2023-05-03 17:23:49 +02:00
}
2023-05-27 11:33:09 +02:00
// ---- maintenant on regarde 1) si on veut une normale lissée
// 2) qui représente aussi le cas d'angle mort avec une ligne normalement qu'en 3D,
// pour laquelle il n'y a pas d'existance d'une normale classique
// on utilise ici la normale interpolée aux noeuds
else if ( (normale_lisser)
|| ((elfront->Angle_mort()) && (elfro.Type_geom_front() == LIGNE))
)
2023-05-03 17:23:49 +02:00
{// 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
// //debug
// cout << "\n debug ElContact::Calcul_Normale: ";
// cout << "\n elfro.DernierTangent " << flush;
// // fin debug
Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
elfro.DernierTangent(dr,pl,indic,false);
// récup des fonctions phi
const Vecteur& phii = elfro.Phi();
// //debug
// cout << "\n debug ElContact::Calcul_Normale: ";
// cout << "\n phii= " << phii;
// // fin debug
// 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();
////debug
// cout << "\n debug ElContact::Calcul_Normale: ";
// cout << "\n Nnoe= " << Nnoe;
//// fin debug
//{TypeQuelconque& tiq_t = tNfront(inoe)->ModifGrandeur_quelconque(N_FRONT_t);
// Grandeur_coordonnee& gr_t= *((Grandeur_coordonnee*) (tiq_t.Grandeur_pointee()));
// Coordonnee& normale_t = *gr.ConteneurCoordonnee();
//
//}
N = phii(inoe)*Nnoe;
// cout << "\n Nnoe= " << Nnoe;
};
N.Normer();
}
// --- on continue avec les éléments qui ne sont pas d'angle mort et sans lissage
else if ( (dim == 3) && (indic == 2))
// cas 3d avec une surface
{ N = pl.Vecplan();
}
2023-05-03 17:23:49 +02:00
else if ( ((dim == 2) && (indic == 1))
|| (ParaGlob::AxiSymetrie() && (dim == 3) && (indic == 1))
)
// cas 2D avec une ligne, (ou 3D bloqué avec une ligne ??)
// ou 3D axisymétrique avec une ligne
// else if((dim == 2) && (indic == 1))
// // cas 2D ou 3D bloqué avec une ligne
{ Coordonnee V = dr.VecDroite(); // le vecteur tangent
// ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
// car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
// donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
N(1) = V(2); N(2) = -V(1);
}
else if ( (dim == 3) && (indic == 1))
// cas 3d avec une ligne, on va considérer que la normale est la normale dans la direction
// du noeud esclave (si celui-ci est suffisemment externe à la ligne
{ Coordonnee V = dr.VecDroite(); // On récupère le vecteur tangent à la ligne
Coordonnee A = noeud->Coord2() - tabNoeud(2)->Coord2(); // on construit un vecteur entre le premier point de ligne -> le noeud esclave
Coordonnee B = Util:: ProdVec_coor(V,A); // produit vectoriel
// on ne continue que si ce produit vectoriel n'est pas nul
if (B.Norme() > ConstMath::petit)
{ N = Util:: ProdVec_coor(V,B);}
else // sinon cela veut dire que le noeud est sur la ligne, dans ce cas particulier, d'une manière arbitraire
// on prend la normale dans un des 3 plans de base, en commençant par le plan xy qui serait celui où par exemple
// on travaille en 3D, mais avec le z bloqué
{ // on commence par voir si c'est possible en xy
if (DabsMaX(V(1),V(2)) > ConstMath::petit)
// là c'est ok la ligne n'est pas // à z
// ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
// car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
// donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
{ N(1) = V(2); N(2) = -V(1);
N(3)=0.; // on pose z=0 d'où une normale dans le plan xy
}
else // sinon cela veut dire que l'on est suivant l'axe de z, on choisit x par défaut
{ N(1)=1; N(2)=N(3)=0.;};
};
}
else if ( (dim == 1) && (indic == 0))
// cas 1D avec un point
{ // la normale sortante de l'élément c'est soit 1 ou -1
// pour le déterminer on commence par trouver le coté de l'élément frontière qui va rentrer en contact
// on est obligé de considérer l'élément
// pour cela on cherche le noeud de l'élément qui correspond au noeud frontière
// qui normalement est le second noeud du global des noeuds de l'élément de contact
Noeud * no_front= tabNoeud(2); int num_no_front = no_front->Num_noeud();
const Tableau < Noeud * > t_N_elem = elfront->PtEI()->Tab_noeud_const();
int nbN_elem = t_N_elem.Taille(); int num_N=0;
for (int i=1;i<= nbN_elem;i++)
if (t_N_elem(i)->Num_noeud() == num_no_front)
{num_N = i;break;};
if (num_N == 0)
{ cout << "\n *** warning on n'a pas trouve de frontiere correct pour le calcul de la normale "
<< "\n cas du contact entre deux points ... le contact sera mal calcule " << endl;
};
// maintenant on prend au autre noeud de l'élément et on regarde le sens
for (int i=1;i<= nbN_elem;i++)
if (i != num_N)
{// il s'agit bien d'un autre noeud
if (t_N_elem(i)->Coord2()(1) > no_front->Coord2()(1) )
{N(1) = -1.;}
else {N(1) = 1.;}
break;
};
}
else
// autres cas non traite pour l'instant
{ cout << "\n erreur, desole mais le cas de contact en dimension = " << dim
<< ", avec ";
if (indic == 1)
cout << " une droite ";
else
cout << " un plan ";
2023-05-27 11:33:09 +02:00
cout << " n\'est pas actuellement traite \n" ;
Affiche(1);
cout << "ElContact::Normal(.." << endl;
Sortie(1);
};
return N;
};
// récupération d'informations des classes internes
// N: le vecteur normal
// M_impact: le point d'impact sur la surface (ou ligne ou point)
// phii : les fonctions d'interpolation au point d'impact
// si avec_var est vrai: il y a retour du tableau de variation de la normale
Tableau <Coordonnee >* ElContact::RecupInfo(Coordonnee& N,Coordonnee& M_impact,Vecteur& phii,bool avec_var)
{ ElFrontiere & elfro = *(elfront->Eleme()); // pour commodite
// recup de la dimension
int dim = noeud->Dimension();
// recup du dernier plan tangent (ou droite)
// dimensionnement des variables de tangence
Plan pl(dim); Droite dr(dim); int indic; // def des variables de tangence
2023-05-03 17:23:49 +02:00
Tableau <Coordonnee >* d_T = NULL; // init par défaut = elfro.DernierTangent(dr,pl,indic,avec_var);
// different cas
N.Change_dim(dim); // le vecteur normal
2023-05-03 17:23:49 +02:00
// on commence par traiter le cas des éléments particuliers qui décrivent les angles morts
2023-05-27 11:33:09 +02:00
if ((elfront->Angle_mort()) && (elfro.Type_geom_front() == POINT_G))
{ // s'il s'agit d'un point il n'y a pas d'existance de normale
// on utilise la normale au noeud
elfro.DernierTangent(dr,pl,indic,false);
// on ne considère pas la variation de la normale
d_T = NULL;
const TypeQuelconque& tiq = tabNoeud(2)->Grandeur_quelconque(N_FRONT_t);
const Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
N = gr.ConteneurCoordonnee_const();
M_impact = elfro.Ref();
2023-05-03 17:23:49 +02:00
}
// ---- maintenant on regarde si on veut une normale lissée
2023-05-27 11:33:09 +02:00
// ---- maintenant on regarde 1) si on veut une normale lissée
// 2) qui représente aussi le cas d'angle mort avec une ligne normalement qu'en 3D,
// pour laquelle il n'y a pas d'existance d'une normale classique
// on utilise ici la normale interpolée aux noeuds
else if ( (normale_lisser)
|| ((elfront->Angle_mort()) && (elfro.Type_geom_front() == LIGNE))
)
2023-05-03 17:23:49 +02:00
{// 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
elfro.DernierTangent(dr,pl,indic,false);
// le vecteur normal est fixe ici pendant les itérations
d_T = NULL;
// 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
N.Zero();
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;
};
N.Normer();
2023-05-27 11:33:09 +02:00
////debug
//if (Permet_affichage() > 4)
// {cout << "\n debug ElContact::RecupInfo N= "<<N ;
// };
////fin debug
2023-05-03 17:23:49 +02:00
// récup du point d'impact
switch (indic)
{ case 2: M_impact = pl.PointPlan(); break;
case 1: M_impact = dr.PointDroite(); break;
2023-05-27 11:33:09 +02:00
case 0: M_impact = tabNoeud(2)->Coord2(); break;
2023-05-03 17:23:49 +02:00
default:
{cout << "\n *** erreur indic =" << indic <<" c-a-d diff de 2 ou 1 ou 0 "
<< " on ne peut pas continuer !";
this->Affiche(1);
}
break;
};
}
else
2023-05-03 17:23:49 +02:00
{
// cas d'élément de contact autres que ceux qui représentent les angles morts
// et des normales lissées
Tableau <Coordonnee >* d_T = elfro.DernierTangent(dr,pl,indic,avec_var);
if (ParaGlob::AxiSymetrie() && (dim == 3))
N(3) = 0.; // init pour le cas axi
if ( (dim == 3) && (indic == 2))
// cas 3d avec une surface
{ N = pl.Vecplan();
M_impact = pl.PointPlan();
}
else if ( ((dim == 2) && (indic == 1))
|| (ParaGlob::AxiSymetrie() && (dim == 3) && (indic == 1))
)
// cas 2D avec une ligne
// ou 3D axisymétrique avec une ligne
{ Coordonnee V = dr.VecDroite(); // le vecteur tangent
// N(1) = -V(2); N(2) = V(1); // un vecteur normal
// !!!! pour l'instant il y a une erreur de numérotation: on utilise en fait une numérotation
// exactement inverse de la doc !!!
N(1) = V(2); N(2) = -V(1); // un vecteur normal
// en axi N(3) est déjà initialisé à 0
M_impact = dr.PointDroite();
}
else if ( (dim == 3) && (indic == 1))
// cas 3d avec une ligne, on va considérer que la normale est la normale dans la direction
// **** a revoir car c'est problématique quand le noeud esclave est très proche de la ligne
// du coup on peut avoir une normale qui oscille d'un coté à l'autre de la ligne ce qui fait que l'on va
// avoir ensuite une force de contact ou de collage !!! aléatoire !!! pas bon du tout
// sans doute trouver autre chose : peut-être que c'est ok quand le point est franchement hors de la ligne
// pas pas autrement
// du noeud esclave (si celui-ci est suffisemment externe à la ligne
{ Coordonnee V = dr.VecDroite(); // On récupère le vecteur tangent à la ligne
Coordonnee A = noeud->Coord2() - tabNoeud(2)->Coord2(); // on construit un vecteur entre le premier point de ligne -> le noeud esclave
Coordonnee B = Util:: ProdVec_coor(V,A); // produit vectoriel
// on ne continue que si ce produit vectoriel n'est pas nul
if (B.Norme() > ConstMath::petit)
{ N = Util:: ProdVec_coor(V,B).Normer();}
else // sinon cela veut dire que le noeud est sur la ligne, dans ce cas particulier, d'une manière arbitraire
// on prend la normale dans un des 3 plans de base, en commençant par le plan xy qui serait celui où par exemple
// on travaille en 3D, mais avec le z bloqué
{ // on commence par voir si c'est possible en xy
if (DabsMaX(V(1),V(2)) > ConstMath::petit)
// là c'est ok la ligne n'est pas // à z
// ici il faut faire attention: la normale est prise de manière à être sortante de l'élément
// car normalement, le vecteur unitaire de la droite est déterminée avec deux points suivants la numérotation de l'élément
// donc la normale à ce vecteur, en suivant le sens trigo, se trouve dirigé vers l'intérieur de l'élément
{ N(1) = V(2); N(2) = -V(1);
N(3)=0.; // on pose z=0 d'où une normale dans le plan xy
}
else // sinon cela veut dire que l'on est suivant l'axe de z, on choisit x par défaut
{ N(1)=1; N(2)=N(3)=0.;};
};
M_impact = dr.PointDroite();
}
// else if ( (dim == 2) && (indic == 1))
// // cas 2D avec une ligne
// { Coordonnee V = dr.VecDroite(); // le vecteur tangent
//// N(1) = -V(2); N(2) = V(1); // un vecteur normal
//// !!!! pour l'instant il y a une erreur de numérotation: on utilise en fait une numérotation
//// exactement inverse de la doc !!!
// N(1) = V(2); N(2) = -V(1); // un vecteur normal
// M_impact = dr.PointDroite();
// }
else if ( (dim == 1) && (indic == 0))
// cas 1D avec un point
{ // la normale sortante de l'élément c'est soit 1 ou -1
// pour le déterminer on commence par trouver le coté de l'élément frontière qui va rentrer en contact
// on est obligé de considérer l'élément
// pour cela on cherche le noeud de l'élément qui correspond au noeud frontière
// qui normalement est le second noeud du global des noeuds de l'élément de contact
Noeud * no_front= tabNoeud(2); int num_no_front = no_front->Num_noeud();
const Tableau < Noeud * > t_N_elem = elfront->PtEI()->Tab_noeud_const();
int nbN_elem = t_N_elem.Taille(); int num_N=0;
for (int i=1;i<= nbN_elem;i++)
if (t_N_elem(i)->Num_noeud() == num_no_front)
{num_N = i;break;};
if (num_N == 0)
{ cout << "\n *** warning on n'a pas trouve de frontiere correct pour le calcul de la normale "
<< "\n cas du contact entre deux points ... le contact sera mal calcule " << endl;
};
// maintenant on prend au autre noeud de l'élément et on regarde le sens
for (int i=1;i<= nbN_elem;i++)
if (i != num_N)
{// il s'agit bien d'un autre noeud
if (t_N_elem(i)->Coord2()(1) > no_front->Coord2()(1) )
{N(1) = -1.;}
else {N(1) = 1.;}
break;
};
// non erreur !! M_impact = N; // sera modifié ensuite, la valeur n'a pas d'importance
// a priori le point d'impact c'est le noeud frontière
M_impact = no_front->Coord2();
}
else if ( (dim == 1) && (indic == 1))
// cas 1D avec une droite
{ N(1) = 1.; // le vecteur normal, qui correspond au seul vecteur disponible
M_impact = dr.PointDroite();;
}
else
// autres cas non traite pour l'instant
{ cout << "\n erreur, desole mais le cas de contact en dimension = " << dim
<< ", avec ";
if (indic == 1)
cout << " une droite ";
else
cout << " un plan ";
2023-05-27 11:33:09 +02:00
cout << " n\'est pas actuellement traite \n" ;
Affiche(1);
cout << "ElContact::RecupInfo(.."<< endl;
2023-05-03 17:23:49 +02:00
Sortie(1);
};
};
// récup des fonctions phi
2023-05-03 17:23:49 +02:00
phii = elfro.Phi();
// retour
return d_T;
};
// mise à jour de cas_solide et donc de ddlElement en fonction de l'activité des ddl
void ElContact::Mise_a_jour_ddlelement_cas_solide_assemblage()
{cas_solide = 0; // init par défaut: déformable-déformable
// on regarde l'activité des noeuds
// 1-- cas du noeud esclave
int dim = ParaGlob::Dimension();
bool esclave_solide = true;
switch (dim)
{case 3: esclave_solide = noeud->Ddl_fixe(X3) && esclave_solide ;
case 2: esclave_solide = noeud->Ddl_fixe(X2) && esclave_solide ;
case 1: esclave_solide = noeud->Ddl_fixe(X1) && esclave_solide ;
};
// 2-- la frontière
int tal = tabNoeud.Taille();
bool front_solide = true;
for (int i=2;i<=tal;i++)
{ Noeud* noe = tabNoeud(i);
switch (dim)
{case 3: front_solide = noe->Ddl_fixe(X3) && front_solide ;
case 2: front_solide = noe->Ddl_fixe(X2) && front_solide ;
case 1: front_solide = noe->Ddl_fixe(X1) && front_solide ;
};
};
// maintenant on traite les différents cas
int dim_ddlelement = 0;
if (esclave_solide && front_solide)
{cas_solide = 3;dim_ddlelement=0;}
else if (esclave_solide) {cas_solide = 2;dim_ddlelement=tal-1;}
else if (front_solide) {cas_solide = 1;dim_ddlelement=1;}
else {cas_solide = 0;dim_ddlelement=tal;};
// maintenant on dimensionne ddlElement éventuellement
if (ddlElement_assemblage->NbNoeud() != dim_ddlelement)
// il faut redimensionner
{
// en fait tous les éléments du tableau sont identiques et il suffit qu'ils existent
// on commence par parcourir la liste pour trouver un bon candidat
list <DdlElement>::iterator ili,ilifin=list_Ddl_global.end();
bool trouve = false;
for (ili=list_Ddl_global.begin();ili !=ilifin; ili++)
if ((*ili).NbNoeud() == dim_ddlelement) // on a trouvé un candidat
{ddlElement_assemblage = &(*ili); trouve = true;};
// dans le cas où on n'a pas trouvé, on en cré un
if (!trouve)
{ int dima = ParaGlob::Dimension();
// dans le cas où on est en axisymétrie il faut diminuer de 1
if (ParaGlob::AxiSymetrie())
dima--;
DdlElement tab_ddl(dim_ddlelement,dima);
int posi = Id_nom_ddl("X1") -1;
for (int i =1; i<= dima; i++)
for (int j=1; j<= dim_ddlelement; j++)
tab_ddl.Change_Enum(j,i,Enum_ddl(i+posi));
list_Ddl_global.push_front(tab_ddl);
ddlElement_assemblage = &(*list_Ddl_global.begin());
};
// ensuite il faut s'occuper du tableau d'assemblage tabNoeud_pour_assemblage.Change_taille(0);
switch (cas_solide)
{case 0: tabNoeud_pour_assemblage = tabNoeud; // c'est le cas le plus complet
break;
case 1: tabNoeud_pour_assemblage.Change_taille(1); // seulement le noeud libre
tabNoeud_pour_assemblage(1)=noeud;
break;
case 2: tabNoeud_pour_assemblage.Change_taille(tal-1); // la facette seule est libre
for (int i=2;i<=tal;i++)
tabNoeud_pour_assemblage(i-1) = tabNoeud(i);
break;
case 3: tabNoeud_pour_assemblage.Change_taille(0); // tout est bloqué
break;
};
};
};
// récup d'une place pour le résidu local et mise à jour de list_SM éventuellement
void ElContact::RecupPlaceResidu(int nbddl)
{ // tout d'abord on vérifie que la place actuelle ne convient pas
if (residu != NULL)
{if (residu->Taille() == nbddl)
{residu->Zero(); return; } // cas courant
};
// dans tous les autres cas il faut soit récupérer une place qui convient soit en créé une autre
// on commence par parcourir la liste pour trouver un bon candidat
list <Vecteur>::iterator ilv,ilvfin=list_SM.end();
bool trouve = false;
for (ilv=list_SM.begin();ilv !=ilvfin; ilv++)
if ((*ilv).Taille() == nbddl) // on a trouvé un candidat
{residu = &(*ilv); residu->Zero();trouve = true;};
// dans le cas où on n'a pas trouvé, on en cré un
if (!trouve)
{ Vecteur interv(nbddl,0.); // vecteur mis à 0 par défaut
list_SM.push_front(interv);
residu = &(*list_SM.begin());
};
};
// récup d'une place pour la raideur locale et mise à jour de list_raideur éventuellement
void ElContact::RecupPlaceRaideur(int nbddl)
{ // tout d'abord on vérifie que la place actuelle ne convient pas
if (raideur != NULL)
{if (raideur->Nb_ligne() == nbddl)
{raideur->Initialise(0.); return; } // cas courant
};
// dans tous les autres cas il faut soit récupérer une place qui convient soit en créé une autre
// on commence par parcourir la liste pour trouver un bon candidat
list <Mat_pleine>::iterator ilv,ilvfin=list_raideur.end();
bool trouve = false;
for (ilv=list_raideur.begin();ilv !=ilvfin; ilv++)
if ((*ilv).Nb_ligne() == nbddl) // on a trouvé un candidat
{raideur = &(*ilv); raideur->Initialise(0.);trouve = true;};
// dans le cas où on n'a pas trouvé, on en cré un
if (!trouve)
{ Mat_pleine interv(nbddl,nbddl,0.); // init à 0 par défaut
list_raideur.push_front(interv);
raideur = &(*list_raideur.begin());
};
};
// calcul du facteur de pénalisation en pénétration, en fonction de la géométrie
2023-05-03 17:23:49 +02:00
// du module de compressibilité et des différents cas possibles
// sauvegarde du gap
// éventuellement, calcul de la dérivée: d_beta_gapdu, du facteur par rapport au gap
// la sensibilité dépend du type de calcul du facteur de pénalisation
double ElContact::CalFactPenal(const double& gap,double & d_beta_gap,int contact_type)
{ // récup du facteur donné par l'utilisateur
double fact_penal=0.; // init par défaut
if (fct_nD_contact.fct_nD_penalisationPenetration != NULL)
2023-05-03 17:23:49 +02:00
{fact_penal = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationPenetration
,ElContact::Fct_nD_contact::tqi_fct_nD_penalisationPenetration
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationPenetration
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationPenetration);
}
else {fact_penal = ParaGlob::param->ParaAlgoControleActifs().PenalisationPenetrationContact();}
double facteur=1.; // un facteur
// choix en fonction du type de calcul
int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationPenetration();
// --- premier choix en fonction de typ_cal ---
if (typ_cal != 0)
{if (contact_type != 41)
{switch (typ_cal)
{ case 1: // cas le plus simple : pas de calcul particulier
break; // on ne fait rien
case 2: case 3: case 4: case 5: case 6: case 7: case 8:// calcul du type ls-dyna avec la compressibilité du maître
{ // on choisit en fonction de la géométrie si il existe une compressibilité
ElFrontiere* elfrontiere = elfront->Eleme(); // pour simplifier l'écriture
const Element * elem = elfront->PtEI(); // idem
if (((const ElemMeca*) elem)->CompressibiliteMoyenne() > 0.)
{ switch (elfrontiere->Type_geom_front())
{ case SURFACE:
if (elem->ElementGeometrie(X1).Dimension()==3)
{ // cas d'une surface frontière d'un volume
double surf = elfrontiere->SurfaceApprox();
double volume = elem->Volume();
if (Dabs(volume) <= ConstMath::pasmalpetit)
2023-05-03 17:23:49 +02:00
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenal()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else if (elem->ElementGeometrie(X1).Dimension()==2)
{ // cas d'une surface frontière d'un élément coque ou plaque
double surf = elfrontiere->SurfaceApprox();
double maxdiag = elfrontiere->MaxDiagonale_tdt();
if (maxdiag <= ConstMath::pasmalpetit)
2023-05-03 17:23:49 +02:00
{ if (Permet_affichage() > 1)
cout << "\n *** attention, la surface de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenal()";
facteur = maxdiag;
}
else // sinon c'est bon
{facteur = surf/maxdiag;}
};
break;
// pour mémoire pour la suite POINT_G = 1 , LIGNE , SURFACE, VOLUME, RIEN_TYPE_GEOM
//******** partie en construction
case LIGNE:
2023-05-27 11:33:09 +02:00
// --- on traite les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ // il n'y a pas de notion de surface de contact et l'idée est de récupérer
// une grandeur du type module de compressibilité * une longueur caractéristique de l'élément
// on retient une expression simple
double longueur = elem->LongueurGeometrique_mini(1);
facteur = longueur;
//%%%% essai %%%%
longueur = elem->LongueurGeometrique_mini(1);
double volume = elem->Volume();
facteur = volume / (longueur * longueur);
//%%%% fin essai %%%%
}
2023-05-27 11:33:09 +02:00
else
{// --- cas d'un élément de contact autre que d'angle mort
if (ParaGlob::AxiSymetrie())
// cas où l'on est en axisymétrique,
{ // on regarde la dimension de l'élément associé
if (elem->ElementGeometrie(X1).Dimension()==2)
// élément 2D en axi donc 3D en réalité
{ // récup de la longueur de la frontière
double longueur = elfrontiere->LongueurApprox();
// on calcul la surface associée
// M_impact(1) = x donc = le rayon car on est axi autour de y
//// double surf = longueur * M_impact(1) * ConstMath::Pi * 2.;
// 9 nov 2016: je crois qu'ici il y a une incompréhension. en fait il s'agit de la surface du maître
// donc il ne faut pas tenir compte du point d'impact ?? sinon par exemple si le point est au centre
// M_impact(1) = 0 et on n'a pas de surf !!
// mais plus généralement, le pt d'impact ne doit pas interférer à mon avis
double surf = longueur * ConstMath::Pi * 2.;
// on récupère la surface de l'élément qui a créé la frontière
double volume = elem->Volume();
if (Dabs(volume) <= ConstMath::pasmalpetit)
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenal()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else // sinon ce n'est pas pris en charge
{cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< " contact sur une ligne axisyme trique"
<< " \n ElContact::CalFactPenal() ";
Sortie(1);
};
}
else if (elem->ElementGeometrie(X1).Dimension()==3)
// cas d'une ligne frontière d'un élément coque ou plaque
{
// il faut finir la fonction ElFrontiere::LongueurApprox()
// cf le laïus qui est écrit dans la méthode
2023-05-27 11:33:09 +02:00
double surf = elfrontiere->SurfaceApprox();
double volume = elem->Volume();
// virtual double EpaisseurMoyenne(Enum_dure )
if (Dabs(volume) <= ConstMath::pasmalpetit)
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenal()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else if (elem->ElementGeometrie(X1).Dimension()==2)
// cas d'une ligne frontière d'une plaque
{ double longueur = elfrontiere->LongueurApprox();
double epais = 0.; // init
if (!ParaGlob::AxiSymetrie()) // si on n'est pas en axi
{epais = ((ElemMeca*) elem)->EpaisseurMoyenne(TEMPS_tdt );}
else // si on est en axi
{epais = 1.;};
double surf = elem->Volume() / epais;
facteur = surf/longueur;
};
};
break;
//******** fin partie en construction
case POINT_G:
2023-05-03 17:23:49 +02:00
// --- on traite les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ // il n'y a pas de notion de surface de contact et l'idée est de récupérer
// une grandeur du type module de compressibilité * une longueur caractéristique de l'élément
// on retient une expression simple
double longueur = elem->LongueurGeometrique_mini(1);
facteur = longueur;
//%%%% essai %%%%
longueur = elem->LongueurGeometrique_mini(1);
double volume = elem->Volume();
facteur = volume / (longueur * longueur);
2023-05-03 17:23:49 +02:00
//%%%% fin essai %%%%
}
else
2023-05-03 17:23:49 +02:00
{ // --- cas d'un élément de contact autre que d'angle mort
// on ne considère que le cas d'une dimension 1D non axi, qui est un cas d'école
// pour les autres cas, on considère que l'on ne doit pas prendre en compte des frontières
// de type point, du coup on génèrera une erreur
if (ParaGlob::Dimension() == 1 )
{// on veut calculer Ke * Ae * Ae / vol , comme on est dans le cas d'une barre
// vol = long * section, et Ae = section , du coup:
// Ke * Ae * Ae / vol = Ke * vol / (long * long) avec long = la longueur de l'élément
double longueur = elem->LongueurGeometrique_mini(1);
double volume = elem->Volume();
facteur = volume / (longueur * longueur);
}
else
{cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< "\n contact en dimension " << ParaGlob::Dimension()
<< " \n ElContact::CalFactPenal() ";
Sortie(1);
};
}
break;
default:
cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< " \n ElContact::CalFactPenal() ";
Sortie(1);
};
// on tiens compte maintenant de la compressibilité (moyenne) de l'élément
facteur *= ((const ElemMeca*) elem)->CompressibiliteMoyenne();
}// fin du test d'existance d'une compressibilité
else
// on n'interdit pas car on pourrait avoir plusieurs maîtres, certains bien définit et
// d'autres sans comportement donc sans compressibilité:
2023-05-03 17:23:49 +02:00
{if (Permet_affichage() >5)
cout << "\n contact: *** attention le module de compressibilite n'est (encore?) pas defini "
<< " on n'en tient pas compte (pour l'instant) pour le calcul du facteur de penalite normal ! ";
};
break;
}
default:
cout << "\n **** erreur cas de calcul du facteur de penalisation en penetration non existant "
<< " typ_cal= " << typ_cal
<< "\n ElContact::CalFactPenal()";
Sortie(1);
};
// --- deuxième choix en fonction de typ_cal ---
// on calcul la valeur final du facteur
switch (typ_cal)
{ case 1: case 2:
{ fact_penal *= facteur;d_beta_gap = 0.;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 5)
cout << "\n fact_penal= " << fact_penal ;
break;
}
case 3: // on fait varier le coef de pénalisation en fonction de l'enfoncement
{ if ((gap < gap_t) && (gap < 0.)) // la première fois gap_t = 0. donc on a forcément nb_pene_tdt >= 1 après le test
{ nb_pene_tdt++;}
else if ((gap > gap_t ) && (gap < 0.)) // on diminue que si gap diminue,
{ if (nb_pene_tdt > 1) // on limite à 1 pour le calcul correcte de la puissance
{ nb_pene_tdt--;
// cout << "\n ************* on diminue np_pene_tdt *************** ";
};
};
// l'évolution du facteur prend en compte le nombre de fois où la pénétration augmente
// 2**10 = 10^2, 2**100 = 10^30 !!
const double a = 1.2; const double b=2.;
fact_penal *= pow(a,nb_pene_tdt*b); //PUISSN(2.,nb_pene_tdt); // on modifie en conséquence le facteur
d_beta_gap = 0.; // a priori on n'a pas vraiment de dérivée calculable ...
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 5)
cout << "\n fact_penal= " << fact_penal << " nb_pene_tdt= "
<< nb_pene_tdt << " pow("<<a<<",nb_pene_tdt*"<<b<<") " <<pow(a,nb_pene_tdt*b);
break;
}
case 4: // on fait varier le coef de pénalisation lorsque l'enfoncement est plus petit qu'un maxi
{ // ON récupe la pénétration maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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();}
double max_pene;
if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi);
}
else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
// on calcul un facteur de majoration en fonction de la pénétration du pas précédent
// double mult_pene = MaX(1., -gap_t/max_pene);
double mult_pene = MaX(1., (-gap_t/max_pene)*mult_pene_t); // il faut appliquer au facteur précédent !
mult_pene_tdt = 0.5*(mult_pene_t + mult_pene); // on fait une moyenne glissante de 2
//////debug
//if (mult_pene_tdt == 1)
// {cout << "\n debug ElContact::CalFactPenal() temps " << ParaGlob::Variables_de_temps().TempsCourant();
// };
////fin debug
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
cout << "\n mult_pene_tdt= " << mult_pene_tdt ;
// on calcul un facteur en fonction de la distance: thèse dominique chamoret, page 94 formule (3.3)
if (gap <= (-borne_regularisation))
{ fact_penal *= facteur*mult_pene_tdt;d_beta_gap = 0.;}
else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
// { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
{ fact_penal *= facteur *mult_pene_tdt * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
d_beta_gap = facteur *mult_pene_tdt * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
}
else
{ fact_penal = 0;d_beta_gap = 0.;};
break;
}
case 5:case 7: // on fait varier le coef de pénalisation lorsque l'enfoncement est plus petit qu'un maxi
{ // ON récupe la pénétration maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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: thèse dominique chamoret, page 94 formule (3.3)
if (gap <= (-borne_regularisation))
{fact_penal *= facteur;d_beta_gap = 0.;}
else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
// { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
{ fact_penal *= facteur * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
d_beta_gap = facteur * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
}
else
{ fact_penal = 0;d_beta_gap = 0.;};
break;
}
case 6: // idem cas 5 mais avec une fonction différente
{ // on récupère la pénétration maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{borne_regularisation = Dabs(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 = Dabs(ParaGlob::param->ParaAlgoControleActifs().Penetration_borne_regularisation());}
// on calcul un facteur en fonction de la distance: = (0.5*(tanh(4.*gap/borne)-1.))
// 0.25*exp(-gap/(0.25*borne))
if (gap <= (-borne_regularisation))
{fact_penal *= facteur;d_beta_gap = 0.;}
else if (Dabs(gap) < borne_regularisation)
{ fact_penal *= -facteur * 0.5 * (tanh(gap*4./borne_regularisation)-1.); // formule du même type
d_beta_gap = 4.*(1.-fact_penal*fact_penal)/borne_regularisation; //
}
else
{ fact_penal = 0;d_beta_gap = 0.;};
break;
}
case 8: // idem 4 mais pour un contact collant: quelque soit le sens de gap
// on fait varier le coef de pénalisation lorsque l'enfoncement est plus petit qu'un maxi
{
// //------ essai à virer
// fact_penal *= facteur;d_beta_gap = 0.;
2023-05-03 17:23:49 +02:00
// if (Permet_affichage() >= 5)
// cout << "\n fact_penal= " << fact_penal ;
// break;
// //------ fin essai
// ON récupe la pénétration maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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();}
double max_pene;
if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi);
}
else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
// on calcul un facteur de majoration en fonction de la pénétration du pas précédent
// double mult_pene = MaX(1., -gap_t/max_pene);
double mult_pene = MaX(1., (Dabs(gap_t)/max_pene)*mult_pene_t); // il faut appliquer au facteur précédent !
mult_pene_tdt = 0.5*(mult_pene_t + mult_pene); // on fait une moyenne glissante de 2
//////debug
//if (mult_pene_tdt == 1)
// {cout << "\n debug ElContact::CalFactPenal() temps " << ParaGlob::Variables_de_temps().TempsCourant();
// };
////fin debug
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
cout << "\n mult_pene_tdt= " << mult_pene_tdt ;
// on calcul un facteur en fonction de la distance: thèse dominique chamoret, page 94 formule (3.3)
if (Dabs(gap) > borne_regularisation)
{ fact_penal *= facteur*mult_pene_tdt;d_beta_gap = 0.;}
else // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
// { fact_penal *= facteur * ((gap*0.5/borne_regularisation + 1.)*gap*0.5+borne_regularisation*0.25); // formule fausse de marmoret
{ fact_penal *= facteur *mult_pene_tdt * Sqr((-Dabs(gap)-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
d_beta_gap = facteur *mult_pene_tdt * (-Dabs(gap)-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
}
break;
}
default:
cout << "\n **** erreur 2 cas de calcul du facteur de penalisation en penetration non existant "
<< " typ_cal= " << typ_cal
<< "\n ElContact::CalFactPenal()";
Sortie(1);
};
}
else if (contact_type == 41)// si == 41, on utilise une mise à jour de la pénalisation
{ // la méthode est analogue au cas: typ_cal == 4
// ON récupe la pénétration maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_penetration_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{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();}
double max_pene;
if (fct_nD_contact.fct_nD_penetration_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_pene = Valeur_fct_nD(fct_nD_contact.fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penetration_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penetration_contact_maxi);
}
else {max_pene = ParaGlob::param->ParaAlgoControleActifs().Penetration_contact_maxi();}
// on calcul un facteur de majoration en fonction de la pénétration du pas précédent
double mult_pene = MaX(1., (-gap_t/max_pene)); // il faut appliquer au facteur précédent !
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 5)
cout << "\n mult_pene_tdt= " << mult_pene ;
// on calcul un facteur en fonction de la distance:
// if (gap <= (-borne_regularisation))
{ fact_penal *= penalisation * mult_pene;d_beta_gap = 0.;}
// else if (Dabs(gap) < borne_regularisation) // borne_regularisation est positif, donc on continue à avoir une pénalisation pour une pénétration positive !!
// { fact_penal *= penalisation * mult_pene * Sqr((gap-borne_regularisation)/borne_regularisation) * 0.25; // formule du même type
// d_beta_gap = penalisation * mult_pene * (gap-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
// }
// else // sinon on annule tout
// { fact_penal = 0;d_beta_gap = 0.;};
}
else if (contact_type == 42)// si == 41, on utilise une mise à jour de la pénalisation
{
};
};
// retour
return fact_penal;
};
// calcul du facteur de pénalisation en tangentiel, en fonction de la géométrie
// du module de compressibilité et des différents possibles
// sauvegarde du dep_T = déplacement tangentiel
// éventuellement, calcul de la dérivée: d_beta_dep_Tdu, du facteur par rapport au dep_T
// la sensibilité dépend du type de calcul du facteur de pénalisation
// suis la même logique que pour la pénétration
double ElContact::CalFactPenalTangentiel(const double& dep_T,double & d_beta_dep_T)
{ // récup du facteur donné par l'utilisateur
double fact_penal = 0.; // init par défaut
if (fct_nD_contact.fct_nD_penalisationTangentielle != NULL)
2023-05-03 17:23:49 +02:00
{fact_penal = Valeur_fct_nD(fct_nD_contact.fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::tqi_const_fct_nD_penalisationTangentielle
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_penalisationTangentielle);
}
else {fact_penal = ParaGlob::param->ParaAlgoControleActifs().PenalisationTangentielleContact();}
double facteur=1.; // un facteur
// choix en fonction du type de calcul
int typ_cal= ParaGlob::param->ParaAlgoControleActifs().TypeCalculPenalisationTangentielle();
// --- premier choix en fonction de typ_cal ---
if (typ_cal != 0)
{switch (typ_cal)
{ case 1: // cas le plus simple : pas de calcul particulier
break; // on ne fait rien
case 2: case 3: case 4: case 5: case 6: case 7: case 8:// calcul du type ls-dyna avec la compressibilité du maître
{ // on choisit en fonction de la géométrie
ElFrontiere* elfrontiere = elfront->Eleme(); // pour simplifier l'écriture
const Element * elem = elfront->PtEI(); // idem
if (((const ElemMeca*) elem)->CompressibiliteMoyenne() > 0.)
{ switch (elfrontiere->Type_geom_front())
{ case SURFACE:
if (elem->ElementGeometrie(X1).Dimension()==3)
{ // cas d'une surface frontière d'un volume
double surf = elfrontiere->SurfaceApprox();
double volume = elem->Volume();
if (Dabs(volume) <= ConstMath::pasmalpetit)
2023-05-03 17:23:49 +02:00
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenalTangentiel()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else if (elem->ElementGeometrie(X1).Dimension()==2)
{ // cas d'une surface frontière d'un élément coque ou plaque
double surf = elfrontiere->SurfaceApprox();
double maxdiag = elfrontiere->MaxDiagonale_tdt();
if (maxdiag <= ConstMath::pasmalpetit)
2023-05-03 17:23:49 +02:00
{ if (Permet_affichage() > 1)
cout << "\n *** attention, la surface de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenalTangentiel()";
facteur = maxdiag;
}
else // sinon c'est bon
{facteur = surf/maxdiag;}
};
break;
// pour mémoire pour la suite POINT_G = 1 , LIGNE , SURFACE, VOLUME, RIEN_TYPE_GEOM
//******** partie en construction
case LIGNE:
2023-05-27 11:33:09 +02:00
// --- on traite les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ // il n'y a pas de notion de surface de contact et l'idée est de récupérer
// une grandeur du type module de compressibilité * une longueur caractéristique de l'élément
// on retient une expression simple
double longueur = elem->LongueurGeometrique_mini(1);
facteur = longueur;
//%%%% essai %%%%
longueur = elem->LongueurGeometrique_mini(1);
double volume = elem->Volume();
facteur = volume / (longueur * longueur);
//%%%% fin essai %%%%
}
2023-05-27 11:33:09 +02:00
else
{// --- cas d'un élément de contact autre que d'angle mort
if (ParaGlob::AxiSymetrie())
// cas où l'on est en axisymétrique,
{ // on regarde la dimension de l'élément associé
if (elem->ElementGeometrie(X1).Dimension()==2)
// élément 2D en axi donc 3D en réalité
{ // récup de la longueur de la frontière
double longueur = elfrontiere->LongueurApprox();
// on calcul la surface associée
double surf = longueur * ConstMath::Pi * 2.;
// on récupère la surface de l'élément qui a créé la frontière
double volume = elem->Volume();
if (Dabs(volume) <= ConstMath::pasmalpetit)
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenalTangentiel()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else // sinon ce n'est pas pris en charge
{cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< " contact sur une ligne axisyme trique"
<< " \n ElContact::CalFactPenalTangentiel() ";
Sortie(1);
};
}
else if (elem->ElementGeometrie(X1).Dimension()==3)
// cas d'une ligne frontière d'un élément coque ou plaque
{
// il faut finir la fonction ElFrontiere::LongueurApprox()
// cf le laïus qui est écrit dans la méthode
2023-05-27 11:33:09 +02:00
double surf = elfrontiere->SurfaceApprox();
double volume = elem->Volume();
// virtual double EpaisseurMoyenne(Enum_dure )
if (Dabs(volume) <= ConstMath::pasmalpetit)
{ if (Permet_affichage() > 1)
cout << "\n *** attention, le volume de l'element " << elem->Num_elt_const() << " du maillage "
<< elem->Num_maillage() << " est nul, on utilise le max de diagonal ";
if (Permet_affichage() > 4)
cout << "\n ElContact::CalFactPenalTangentiel()";
facteur = elfrontiere->MaxDiagonale_tdt();
}
else // sinon c'est bon
{facteur = surf*surf/volume;}
}
else if (elem->ElementGeometrie(X1).Dimension()==2)
// cas d'une ligne frontière d'une plaque
{ double longueur = elfrontiere->LongueurApprox();
double epais = 0.; // init
if (!ParaGlob::AxiSymetrie()) // si on n'est pas en axi
{epais = ((ElemMeca*) elem)->EpaisseurMoyenne(TEMPS_tdt );}
else // si on est en axi
{epais = 1.;};
double surf = elem->Volume() / epais;
facteur = surf/longueur;
};
}
break;
//******** fin partie en construction
case POINT_G:
2023-05-03 17:23:49 +02:00
// --- on traite les cas particuliers des éléments d'angle mort
if (elfront->Angle_mort())
{ // il n'y a pas de notion de surface de contact et l'idée est de récupérer
// une grandeur du type module de compressibilité * une longueur caractéristique de l'élément
// on retient une expression simple
double longueur = elem->LongueurGeometrique_mini(1);
facteur = longueur;
}
else
2023-05-03 17:23:49 +02:00
{ // --- cas d'un élément de contact autre que d'angle mort
// on ne considère que le cas d'une dimension 1D non axi, qui est un cas d'école
// pour les autres cas, on considère que l'on ne doit pas prendre en compte des frontières
// de type point, du coup on génèrera une erreur
if (ParaGlob::Dimension() == 1 )
{// on veut calculer Ke * Ae * Ae / vol , comme on est dans le cas d'une barre
// vol = long * section, et Ae = section , du coup:
// Ke * Ae * Ae / vol = Ke * vol / (long * long) avec long = la longueur de l'élément
double longueur = elem->LongueurGeometrique_mini(1);
double volume = elem->Volume();
facteur = volume / (longueur * longueur);
}
else
{cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< "\n contact en dimension " << ParaGlob::Dimension()
<< " \n ElContact::CalFactPenalTangentiel() ";
Sortie(1);
};
};
break;
default:
cout << "\n *** erreur: cas non pris en charge pour l'instant: "
<< " type de frontiere : " << Nom_type_geom(elfrontiere->Type_geom_front())
<< " \n ElContact::CalFactPenalTangentiel() ";
Sortie(1);
};
// on tiens compte maintenant de la compressibilité (moyenne) de l'élément
facteur *= ((const ElemMeca*) elem)->CompressibiliteMoyenne();
}// fin du test d'existance d'une compressibilité
else
// on n'interdit pas car on pourrait avoir plusieurs maîtres, certains bien définit et
// d'autres sans comportement donc sans compressibilité:
2023-05-03 17:23:49 +02:00
{if (Permet_affichage() >5)
cout << "\n contact: *** attention le module de compressibilite n'est (encore?) pas defini "
<< " on n'en tient pas compte (pour l'instant) pour le calcul du facteur de penalite tangentiel ! ";
};
break;
}
default:
cout << "\n **** erreur cas de calcul du facteur de penalisation tangentielle non existant "
<< " typ_cal= " << typ_cal
<< "\n ElContact::CalFactPenalTangentiel()";
Sortie(1);
};
// --- deuxième choix en fonction de typ_cal ---
// on calcul la valeur final du facteur
switch (typ_cal)
{ case 1: case 2:
{ fact_penal *= facteur;d_beta_dep_T = 0.;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 5)
cout << "\n fact_penal= " << fact_penal ;
break;
}
case 5:case 7: // on fait varier le coef de pénalisation lorsque le déplacement est plus petit qu'une borne
{ // de régularisation
double borne_regularisation;
if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_borne_regularisation);
}
else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation();}
// on calcul un facteur en fonction de la distance
if (Dabs(dep_T) > borne_regularisation)
{fact_penal *= facteur;d_beta_dep_T = 0.;}
else
{ fact_penal *= facteur * Sqr((dep_T-borne_regularisation)/borne_regularisation) * 0.25;
d_beta_dep_T = facteur * (dep_T-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
};
break;
}
case 6: // idem cas 5 mais avec une fonction différente
{ // on récupère le déplacement maxi
double borne_regularisation;
if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{borne_regularisation = Dabs(Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_borne_regularisation));
}
else {borne_regularisation = Dabs(ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation());}
// on calcul un facteur en fonction de la distance: = (0.5*(tanh(4.*dep_T/borne)-1.))
// 0.25*exp(-dep_T/(0.25*borne))
if (Dabs(dep_T) > borne_regularisation)
{fact_penal *= facteur;d_beta_dep_T = 0.;}
else
{ fact_penal *= -facteur * 0.5 * (tanh(dep_T*4./borne_regularisation)-1.); // formule du même type
d_beta_dep_T = 4.*(1.-fact_penal*fact_penal)/borne_regularisation; //
};
break;
}
case 4: case 8: // quelque soit le sens de dep_T
// on fait varier le coef de pénalisation lorsque le déplacement est plus petit qu'un maxi
{
////------ essai à virer
//fact_penal *= facteur;d_beta_dep_T = 0.;
2023-05-03 17:23:49 +02:00
// if (Permet_affichage() >= 5)
// cout << "\n fact_penal= " << fact_penal ;
// break;
////------ fin essai
double borne_regularisation;
if (fct_nD_contact.fct_nD_tangentielle_borne_regularisation != NULL)
2023-05-03 17:23:49 +02:00
{borne_regularisation = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_borne_regularisation
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_borne_regularisation);
}
else {borne_regularisation = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_borne_regularisation();}
double max_dep_T;
if (fct_nD_contact.fct_nD_tangentielle_contact_maxi != NULL)
2023-05-03 17:23:49 +02:00
{max_dep_T = Valeur_fct_nD(fct_nD_contact.fct_nD_tangentielle_contact_maxi
,ElContact::Fct_nD_contact::tqi_fct_nD_tangentielle_contact_maxi
,ElContact::Fct_nD_contact::tqi_const_fct_nD_tangentielle_contact_maxi
,ElContact::Fct_nD_contact::t_num_ordre_fct_nD_tangentielle_contact_maxi);
}
else {max_dep_T = ParaGlob::param->ParaAlgoControleActifs().Tangentielle_contact_maxi();}
// on calcul un facteur de majoration en fonction du déplacement du pas précédent
// double mult_tang = MaX(1., -dep_T_t/max_pene);
double mult_tang = MaX(1., (Dabs(dep_T_t)/max_dep_T)*mult_tang_t); // il faut appliquer au facteur précédent !
mult_tang_tdt = 0.5*(mult_tang_t + mult_tang); // on fait une moyenne glissante de 2
//////debug
//if (mult_tang_tdt == 1)
// {cout << "\n debug ElContact::CalFactPenalTangentiel() temps " << ParaGlob::Variables_de_temps().TempsCourant();
// };
////fin debug
2023-05-03 17:23:49 +02:00
if (Permet_affichage() >= 5)
cout << "\n mult_tang_tdt= " << mult_tang_tdt ;
// on calcul un facteur en fonction de la distance: du même genre que pour la pénétration
// sauf qu'ici c'est vrai quelque soit la direction du déplacement
if (Dabs(dep_T) > borne_regularisation)
{ fact_penal *= facteur * mult_tang_tdt; d_beta_dep_T = 0.;}
else
{ fact_penal *= facteur * mult_tang_tdt * Sqr((-Dabs(dep_T)-borne_regularisation)/borne_regularisation) * 0.25;
d_beta_dep_T = facteur * mult_tang_tdt * (-Dabs(dep_T)-borne_regularisation)/borne_regularisation/borne_regularisation * 0.5;;
};
break;
}
default:
cout << "\n **** erreur 2 cas d'un calcul du facteur de penalisation tangentiel non existant "
<< " typ_cal= " << typ_cal
<< "\n ElContact::CalFactPenalTangentiel()";
Sortie(1);
};
};
// dep_T_tdt = dep_T; // sauvegarde
// retour
return fact_penal;
};
// calcul éventuel de la moyenne glissante des positions successive du noeud esclave
// et changement des coordonnées du point passé en paramètre
void ElContact::ChangeEnMoyGlissante(Coordonnee& Noe_atdt)
{ // pour simplifier
int taille_moyenne_glissante = ParaGlob::param->ParaAlgoControleActifs().Nb_moy_glissant();
// on dimensionne éventuellement le tableau des positions successives
if (tab_posi_esclave.Taille() != taille_moyenne_glissante)
tab_posi_esclave.Change_taille(taille_moyenne_glissante,Coordonnee(ParaGlob::Dimension()));
// on calcul éventuellement la moyenne glissante
if (taille_moyenne_glissante > 1)
{ if (nb_posi_esclave_stocker_t < taille_moyenne_glissante)
{ // c'est le cas où la moyenne n'est pas finalisée
nb_posi_esclave_stocker_tdt = nb_posi_esclave_stocker_t+1;
indice_stockage_glissant_tdt=1;
tab_posi_esclave(nb_posi_esclave_stocker_tdt) = noeud->Coord2();
// calcul de la moyenne
Noe_atdt=tab_posi_esclave(1); // init
for (int i=2;i<=nb_posi_esclave_stocker_tdt;i++)
Noe_atdt += tab_posi_esclave(i);
Noe_atdt /= nb_posi_esclave_stocker_tdt;
}
else // cas ou la moyenne est finalisée
{ tab_posi_esclave(indice_stockage_glissant_t) = noeud->Coord2();
indice_stockage_glissant_tdt=indice_stockage_glissant_t+1; // mise à jour de l'indice pour le prochain stockage
// si l'indice dépasse la taille du taille, on remet au début
if (indice_stockage_glissant_tdt > taille_moyenne_glissante) indice_stockage_glissant_tdt = 1;
// calcul de la moyenne
Noe_atdt=tab_posi_esclave(1); // init
for (int i=2;i<=taille_moyenne_glissante;i++)
Noe_atdt += tab_posi_esclave(i);
Noe_atdt /= taille_moyenne_glissante;
};
};
};
// calcul de la moyenne glissante de la pénalisation
void ElContact::Moyenne_glissante_penalisation(double& penalisation, double& essai_penalisation)
{ // penalisation = la somme pondérée
int tai_val_penal = val_penal.Taille();
// on vérifie que la taille n'a pas changée
if (fct_pilotage_contact4 != NULL)
{if (fct_pilotage_contact4->NbComposante() == 2)
{Tableau <double> & tava = fct_pilotage_contact4->Valeur_pour_variables_globales();
int nouvelle_taille = tava(2);
if (nouvelle_taille != tai_val_penal)
{if (nouvelle_taille > tai_val_penal)
// on se contente d'augmenter la taille de stockage
{val_penal.Change_taille(nouvelle_taille);}
else
// on va changer la taille en gardant les dernières valeurs (= les plus récentes)
{int diff = tai_val_penal-nouvelle_taille;
for (int i=1;i<= nouvelle_taille;i++)
val_penal(i) = val_penal(i+diff);
val_penal.Change_taille(nouvelle_taille);
if (pt_dans_val_penal > nouvelle_taille) pt_dans_val_penal = 1;
tai_val_penal = nouvelle_taille;
};
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 2)
cout << "\n -> Moyenne_glissante_penalisation: change taille "
<< tai_val_penal << " -> " << nouvelle_taille;
};
};
};
if (val_penal(tai_val_penal) == 0.)
// cas où le tableau n'est pas complètement rempli
{ penalisation *= (pt_dans_val_penal-1); // correspond à la somme
penalisation = (penalisation+essai_penalisation)/pt_dans_val_penal;
val_penal(pt_dans_val_penal)=essai_penalisation;
// pour pt_dans_val_penal == 1 cela donne directement essai_penalisation
}
else // sinon le tableau est rempli, on effectue des remplacements
{ penalisation *= tai_val_penal; // la somme
penalisation = (penalisation - val_penal(pt_dans_val_penal) + essai_penalisation )/tai_val_penal;
val_penal(pt_dans_val_penal) = essai_penalisation;
}
pt_dans_val_penal++; // mise en place du retour périodique
if (pt_dans_val_penal > tai_val_penal) pt_dans_val_penal = 1;
};
// calcul d'une fonction nD relative à des données de contact
2023-05-03 17:23:49 +02:00
double ElContact::Valeur_fct_nD(Fonction_nD * pt_fonct,Tableau < TypeQuelconque * >& tqi
,Tableau < const TypeQuelconque * >& tqii,Tableau <int>& t_num_ordre ) const
{ // on commence par récupérer les conteneurs des grandeurs à fournir
List_io <Ddl_enum_etendu>& li_enu_scal = pt_fonct->Li_enu_etendu_scalaire();
List_io <TypeQuelconque >& li_quelc = pt_fonct->Li_equi_Quel_evolue();
2023-05-03 17:23:49 +02:00
const Tableau <EnumTypeQuelconque>& tab_queconque = pt_fonct->Tab_enu_quelconque();
// on passe en revue les grandeurs pour les renseigner
// --- on balaie maintenant la liste des grandeurs à sortir
// 1) tout d'abord les ddl étendues
Tableau <double> val_ddl_enum (li_enu_scal.size());
List_io<Ddl_enum_etendu>::const_iterator ie,iefin=li_enu_scal.end();
int it; // it est l'indice dans le tableau de retour
for (it=1,ie=li_enu_scal.begin(); ie!=iefin;ie++,it++)
{ // si c'est un ddl pure, on regarde si elle est définie au noeud
const Ddl_enum_etendu& enu = (*ie); // pour simplifier
bool trouver = false;
// on regarde d'abord s'il s'agit d'une info spécifique au contact
int posi = (*ie).Position()-NbEnum_ddl();
switch (posi)
{ case 90: // reaction_normale -> en fait pas nécessaire, mais je laisse
// car existe au noeud en contact
{val_ddl_enum(it) = force_contact * N; trouver=true; break;}
// case 91: // reaction_tangentielle déjà stockée au noeud
// donc sera traité par le noeud en contact
///**** en fait les cas X1, X1_t et X1_t0 ne vont pas être traités ici
/// mais vont être traités en grandeurs quelconques car il s'agit de vecteur
// Je laisse quand même mais on ne passera sans doute jamais ici
case 123: // "X1_t"
{ val_ddl_enum(it) = noeud->Coord1()(1);trouver=true; break;}
case 124: // "X2_t"
{ val_ddl_enum(it) = noeud->Coord1()(2);trouver=true; break;}
case 125: // X3_t
{ val_ddl_enum(it) = noeud->Coord1()(3);trouver=true; break;}
case 126: // X1_t0
{ val_ddl_enum(it) = noeud->Coord0()(1);trouver=true; break;}
case 127: // X2_t0
{ val_ddl_enum(it) = noeud->Coord0()(2);trouver=true; break;}
case 128: // X3_t0
{ val_ddl_enum(it) = noeud->Coord0()(3);trouver=true; break;}
//*** fin
default: // sinon on le stock en ddl_étendu
trouver=false; break;
};// fin du switch
// si l'on n'a pas trouver, on regarde si l'info est dispo au noeud en contact
if (!trouver)
{if (enu.Position() <= NbEnum_ddl()) // cas d'un ddl pur
{if (noeud->Existe_ici(enu.Enum()))
{val_ddl_enum(it) = noeud->Ddl_noeud_tdt(enu.Enum()).Valeur();
trouver = true;
};
}
else // cas d'un ddl étendu
{ if (noeud->Existe_ici_ddlEtendu(enu))
{val_ddl_enum(it) = noeud->DdlEtendue(enu).ConstValeur();
trouver = true;
};
};
};
// si on n'a rien trouvé
if (!trouver)
{cout << "\n erreur***: le ddl " << enu.Nom_plein()
<< " n'existe pas pour le noeud en contact "
<< " la fonction nD " << pt_fonct->NomFonction()
<< " ne peut pas etre renseignee " << flush;
2023-05-03 17:23:49 +02:00
if (ParaGlob::NiveauImpression() > 2)
{this->Affiche();
pt_fonct->Affiche();
}
Sortie(1);
};
};// -- fin de la boucle sur la liste de Ddl_enum_etendu
// 2) puis les grandeurs quelconques
2023-05-03 17:23:49 +02:00
{List_io<TypeQuelconque>::iterator ipq,ipqfin=li_quelc.end();
for (ipq=li_quelc.begin();ipq!=ipqfin;ipq++)
{ bool trouver = false;
TypeQuelconque& enuTQ = (*ipq); // pour simplifier
const TypeQuelconque_enum_etendu& en_ET_TQ = enuTQ.EnuTypeQuelconque().EnumTQ();
// on regarde tout d'abord les grandeurs spécifiques à l'élément contact
switch (enuTQ.EnuTypeQuelconque().EnumTQ())
{ // il y a des grandeurs vectorielles qui pour l'instant ne sont pas prises en compte
// cf. fct nD
// NORMALE_CONTACT, GLISSEMENT_CONTACT ,PENETRATION_CONTACT,FORCE_CONTACT,
case CONTACT_NB_DECOL:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = nb_decol_tdt;
trouver = true;
break;
}
case CONTACT_PENALISATION_N:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = penalisation;
trouver = true;
break;
}
case CONTACT_PENALISATION_T:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = penalisation_tangentielle;
trouver = true;
break;
}
case CONTACT_NB_PENET:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = nb_pene_tdt;
trouver = true;
break;
}
case CONTACT_CAS_SOLIDE:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = cas_solide;
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_ELAS:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.EnergieElastique();
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_PLAS:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.DissipationPlastique();
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_VISQ:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.DissipationVisqueuse();
trouver = true;
break;
}
case CONTACT_ENERG_PENAL:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_penalisation;
trouver = true;
break;
}
case NOEUD_PROJECTILE_EN_CONTACT:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
if (actif)
{*(gr.ConteneurDouble()) = 100.;}
else
{*(gr.ConteneurDouble()) = -0.1; };
trouver = true;
break;
}
case NOEUD_FACETTE_EN_CONTACT:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*ipq).Grandeur_pointee()));
int NBNF = tabNoeud.Taille();
if (actif)
{ for (int i=2;i<=NBNF;i++)
*(gr.ConteneurDouble()) += 100.;
}
else
{ for (int i=2;i<=NBNF;i++)
*(gr.ConteneurDouble()) -= 0.1;
};
trouver = true;
break;
}
case NUM_NOEUD:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = noeud->Num_noeud();
trouver = true;
break;
}
case NUM_MAIL_NOEUD:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = noeud->Num_Mail();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord2();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord1();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t0:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord0();
trouver = true;
break;
}
// *** pour l'instant la suite n'est pas opérationelle car il s'agit de vecteur
// dont les composantes n'ont pas d'équivalent en ddl_enum_etendu
// il faudrait les définir si on veut pouvoir s'en servir
case PENETRATION_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= Mtdt-noeud->Coord2();
trouver = true;
break;
}
case PENETRATION_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= Mt-noeud->Coord1();
trouver = true;
break;
}
case GLISSEMENT_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= dep_tangentiel;
trouver = true;
break;
}
case GLISSEMENT_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= dep_T_t;
trouver = true;
break;
}
case NORMALE_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= N;
trouver = true;
break;
}
case FORCE_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= force_contact;
trouver = true;
break;
}
case FORCE_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= force_contact_t;
trouver = true;
break;
}
case CONTACT_COLLANT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = cas_collant;
trouver = true;
break;
}
case NUM_ZONE_CONTACT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = num_zone_contact;
trouver = true;
break;
}
2023-05-03 17:23:49 +02:00
case NUM_ELEMENT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = Elfront()->PtEI()->Num_elt();
trouver = true;
break;
}
case NUM_MAIL_ELEM:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*ipq).Grandeur_pointee()));
*(gr.ConteneurEntier()) = Elfront()->PtEI()->Num_maillage();
trouver = true;
break;
}
//*** fin
default:
trouver = false;
break;
};
// si l'on n'a pas trouver, on regarde si l'info est dispo au noeud en contact
if (!trouver)
{if (noeud->Existe_ici(en_ET_TQ))
{ (*(enuTQ.Grandeur_pointee())) = (*noeud->Grandeur_quelconque(en_ET_TQ).Const_Grandeur_pointee());
trouver = true;
};
};
2023-05-03 17:23:49 +02:00
// si on n'a rien trouvé
if (!trouver)
{cout << "\n erreur***: la grandeur " << en_ET_TQ.NomPlein()
<< " n'existe pas pour le noeud en contact "
<< " la fonction nD " << pt_fonct->NomFonction()
<< " ne peut pas etre renseignee " << flush;
2023-05-03 17:23:49 +02:00
if (ParaGlob::NiveauImpression() > 2)
{this->Affiche();
pt_fonct->Affiche();
}
Sortie(1);
};
};
2023-05-03 17:23:49 +02:00
};
// 3) et enfin les grandeurs quelconques:
// les conteneurs sont normalement déjà bien dimensionné
int tail_tab_queconque = tab_queconque.Taille();
// on va balayer les grandeurs quelconques
for (int i=1;i<= tail_tab_queconque;i++)
{ bool trouver = false;
EnumTypeQuelconque enu = tab_queconque(i);
// 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:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = nb_decol_tdt;
trouver = true;
break;
}
case CONTACT_PENALISATION_N:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = penalisation;
trouver = true;
break;
}
case CONTACT_PENALISATION_T:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = penalisation_tangentielle;
trouver = true;
break;
}
case CONTACT_NB_PENET:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = nb_pene_tdt;
trouver = true;
break;
}
case CONTACT_CAS_SOLIDE:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = cas_solide;
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_ELAS:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.EnergieElastique();
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_PLAS:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.DissipationPlastique();
trouver = true;
break;
}
case CONTACT_ENERG_GLISSE_VISQ:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_frottement.DissipationVisqueuse();
trouver = true;
break;
}
case CONTACT_ENERG_PENAL:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurDouble()) = energie_penalisation;
trouver = true;
break;
}
case NOEUD_PROJECTILE_EN_CONTACT:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
if (actif)
{*(gr.ConteneurDouble()) = 100.;}
else
{*(gr.ConteneurDouble()) = -0.1; };
trouver = true;
break;
}
case NOEUD_FACETTE_EN_CONTACT:
{ Grandeur_scalaire_double& gr= *((Grandeur_scalaire_double*) ((*tqi(i)).Grandeur_pointee()));
int NBNF = tabNoeud.Taille();
if (actif)
{ for (int i=2;i<=NBNF;i++)
*(gr.ConteneurDouble()) += 100.;
}
else
{ for (int i=2;i<=NBNF;i++)
*(gr.ConteneurDouble()) -= 0.1;
};
trouver = true;
break;
}
case NUM_NOEUD:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = noeud->Num_noeud();
trouver = true;
break;
}
case NUM_MAIL_NOEUD:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = noeud->Num_Mail();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord2();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord1();
trouver = true;
break;
}
case POSITION_GEOMETRIQUE_t0:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= noeud->Coord0();
trouver = true;
break;
}
// *** pour l'instant la suite n'est pas opérationelle car il s'agit de vecteur
// dont les composantes n'ont pas d'équivalent en ddl_enum_etendu
// il faudrait les définir si on veut pouvoir s'en servir
case PENETRATION_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= Mtdt-noeud->Coord2();
trouver = true;
break;
}
case PENETRATION_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= Mt-noeud->Coord1();
trouver = true;
break;
}
case GLISSEMENT_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= dep_tangentiel;
trouver = true;
break;
}
case GLISSEMENT_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= dep_T_t;
trouver = true;
break;
}
case NORMALE_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= N;
trouver = true;
break;
}
case FORCE_CONTACT:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= force_contact;
trouver = true;
break;
}
case FORCE_CONTACT_T:
{Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*tqi(i)).Grandeur_pointee()));
(*gr.ConteneurCoordonnee())= force_contact_t;
trouver = true;
break;
}
case CONTACT_COLLANT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = cas_collant;
trouver = true;
break;
}
case NUM_ZONE_CONTACT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = num_zone_contact;
trouver = true;
break;
}
case NUM_ELEMENT:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = Elfront()->PtEI()->Num_elt();
trouver = true;
break;
}
case NUM_MAIL_ELEM:
{ Grandeur_scalaire_entier& gr= *((Grandeur_scalaire_entier*) ((*tqi(i)).Grandeur_pointee()));
*(gr.ConteneurEntier()) = Elfront()->PtEI()->Num_maillage();
trouver = true;
break;
}
//*** fin
default:
trouver = false;
break;
};
2023-05-03 17:23:49 +02:00
// si on n'a rien trouvé
if (!trouver)
{cout << "\n erreur***: la grandeur " << NomTypeQuelconque(enu)
<< " n'existe pas pour le noeud en contact "
<< " la fonction nD " << pt_fonct->NomFonction()
<< " ne peut pas etre renseignee " << flush;
if (ParaGlob::NiveauImpression() > 2)
{this->Affiche();
pt_fonct->Affiche();
}
Sortie(1);
};
};
// tqii pointe aux mêmes endroit que tqi mais est déclaré en const ...
// calcul de la valeur et retour dans tab_ret
2023-05-03 17:23:49 +02:00
Tableau <double> & tab_val = pt_fonct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,&(tqii),&t_num_ordre);
#ifdef MISE_AU_POINT
if (tab_val.Taille() != 1)
{ cout << "\nErreur : la fonction nD " << pt_fonct->NomFonction()
<< " doit calculer un scalaire or le tableau de retour est de taille "
<< tab_val.Taille() << " ce n'est pas normal !\n" << flush;
2023-05-03 17:23:49 +02:00
if (Permet_affichage() > 2 )
cout << "\n ElContact::Valeur(... \n";
Sortie(1);
};
#endif
// on récupère le premier élément du tableau uniquement
return tab_val(1);
};