3176 lines
166 KiB
C++
3176 lines
166 KiB
C++
|
|
// This file is part of the Herezh++ application.
|
|
//
|
|
// The finite element software Herezh++ is dedicated to the field
|
|
// of mechanics for large transformations of solid structures.
|
|
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
|
|
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
|
|
//
|
|
// Herezh++ is distributed under GPL 3 license ou ultérieure.
|
|
//
|
|
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
|
|
// AUTHOR : Gérard Rio
|
|
// E-MAIL : gerardrio56@free.fr
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License,
|
|
// or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty
|
|
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
// See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
//
|
|
// For more information, please consult: <https://herezh.irdl.fr/>.
|
|
|
|
//#include "Debug.h"
|
|
#include "ElemMeca.h"
|
|
#include <iomanip>
|
|
#include "ConstMath.h"
|
|
#include "Util.h"
|
|
#include "Coordonnee2.h"
|
|
#include "Coordonnee3.h"
|
|
#include "TypeQuelconqueParticulier.h"
|
|
#include "TypeConsTens.h"
|
|
#include "Loi_iso_elas3D.h"
|
|
#include "Loi_iso_elas1D.h"
|
|
#include "Loi_iso_elas2D_C.h"
|
|
#include "FrontPointF.h"
|
|
#include "MathUtil2.h"
|
|
#include "Enum_StabMembrane.h"
|
|
|
|
// -------------------- stabilisation d'hourglass -------------------
|
|
// calcul d'élément de contrôle d'hourglass associée à un comportement
|
|
// str_precision : donne le type particulier d'élément à construire
|
|
void ElemMeca::Init_hourglass_comp(const ElemGeomC0& elgeHour, const string & str_precision
|
|
,LoiAbstraiteGeneral * loiHourglass, const BlocGen & bloc)
|
|
{
|
|
//!!!! en fait pour l'instant on n'utilise pas elgehour, on considère que le nombre de pti complet est celui de l'élément sans info annexe !!!
|
|
// sauf pour l'hexaèdre quadratique pour lequel on a définit un str_precision particulier
|
|
// on met à jour les indicateurs
|
|
if (Type_Enum_StabHourglass_existe(bloc.Nom(1)))
|
|
{ type_stabHourglass = Id_Nom_StabHourglass(bloc.Nom(1).c_str());
|
|
coefStabHourglass = bloc.Val(1);
|
|
}
|
|
else
|
|
{ cout << "\n erreur, le type " << bloc.Nom(2) << " de gestion d'hourglass n'existe pas !!";
|
|
if (ParaGlob::NiveauImpression() > 5)
|
|
cout << "\n ElemMeca::Init_hourglass_comp(...";
|
|
cout << endl;
|
|
Sortie(1);
|
|
};
|
|
switch (type_stabHourglass)
|
|
{case STABHOURGLASS_PAR_COMPORTEMENT :
|
|
{ // -- choix de l'element pour le calcul de la raideur -----
|
|
// on recherche un élément de même type,
|
|
// par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage
|
|
// numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas
|
|
// rattachés à un maillage existant en tant que tel
|
|
int nUmMail = this->Num_elt_const();
|
|
int nUmElem = 1000000 + this->Num_elt();
|
|
tab_elHourglass.Change_taille(1);
|
|
tab_elHourglass(1) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision);
|
|
|
|
if (tab_elHourglass(1) == NULL)
|
|
{ // l'operation a echouee
|
|
cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** ";
|
|
cout << "\n l\'element : " << Nom_interpol(id_interpol)
|
|
<< " " << Nom_geom(id_geom) << " " << str_precision
|
|
<< " n\'est pas present dans le programme ! " << endl;
|
|
if (ParaGlob::NiveauImpression() > 5)
|
|
cout << "\n ElemMeca::Init_hourglass_comp(..." << endl;
|
|
Sortie (1);
|
|
};
|
|
// --- définition des noeuds de l'élément -----
|
|
// on construit à partir des mêmes noeuds que ceux de l'élément père
|
|
// affectation des noeuds au nouvel élément
|
|
tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud();
|
|
//--- def de la loi de comportement ---
|
|
// affectation de la loi
|
|
tab_elHourglass(1)->DefLoi(loiHourglass);
|
|
break;
|
|
}
|
|
case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT :
|
|
{ // ici on a besoin de deux éléments. Le premier sert à faire le calcul complet
|
|
// le second sert à faire un calcul réduit, comme l'élément réel
|
|
tab_elHourglass.Change_taille(2);
|
|
|
|
// -- choix pour le calcul de la raideur -----
|
|
// on recherche un élément de même type,
|
|
// par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage
|
|
// numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas
|
|
// rattachés à un maillage existant en tant que tel
|
|
//-- le premier élément:
|
|
int nUmMail = this->Num_elt_const();
|
|
int nUmElem = 1000000 + this->Num_elt();
|
|
tab_elHourglass(1) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision);
|
|
if (tab_elHourglass(1) == NULL)
|
|
{ // l'operation a echouee
|
|
cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** ";
|
|
cout << "\n l\'element : " << Nom_interpol(id_interpol)
|
|
<< " " << Nom_geom(id_geom) << " " << str_precision
|
|
<< " n\'est pas present dans le programme ! " << endl;
|
|
if (ParaGlob::NiveauImpression() > 5)
|
|
cout << "\n ElemMeca::Init_hourglass_comp(..." << endl;
|
|
Sortie (1);
|
|
};
|
|
//-- le second élément identique à this: on utilise le même numéro de maillage
|
|
// même infos annexes
|
|
nUmElem = 20000000 + this->Num_elt(); // on ajoute une unité pour le numéro
|
|
tab_elHourglass(2) = (ElemMeca*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),this->infos_annexes);
|
|
|
|
if (tab_elHourglass(2) == NULL)
|
|
{ // l'operation a echouee
|
|
cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** ";
|
|
cout << "\n l\'element : " << Nom_interpol(id_interpol)
|
|
<< " " << Nom_geom(id_geom) << " " << this->infos_annexes
|
|
<< " n\'est pas present dans le programme ! " << endl;
|
|
if (ParaGlob::NiveauImpression() > 5)
|
|
cout << "\n ElemMeca::Init_hourglass_comp(..." << endl;
|
|
Sortie (1);
|
|
};
|
|
// --- définition des noeuds de l'élément -----
|
|
// on construit à partir des mêmes noeuds que ceux de l'élément père
|
|
// affectation des noeuds au nouvel élément
|
|
tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud();
|
|
tab_elHourglass(2)->Tab_noeud() = this->Tab_noeud();
|
|
//--- def de la loi de comportement ---
|
|
// affectation de la loi
|
|
tab_elHourglass(1)->DefLoi(loiHourglass);
|
|
tab_elHourglass(2)->DefLoi(loiHourglass);
|
|
// def de trois vecteurs de travail s'ils ne sont pas encore définit
|
|
if (vec_hourglass.Taille() < 3)
|
|
vec_hourglass.Change_taille(3);
|
|
break;
|
|
}
|
|
|
|
default :
|
|
cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n";
|
|
cout << "\n ElemMeca::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
// stabilisation pour un calcul implicit
|
|
void ElemMeca::Cal_implicit_hourglass()
|
|
{E_Hourglass=0.; // init par défaut
|
|
switch (type_stabHourglass)
|
|
{case STABHOURGLASS_PAR_COMPORTEMENT :
|
|
{ // --- calcul de la raideur de l'élément, dans le cas implicite ---
|
|
Element::ResRaid resraid = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs());
|
|
// on tiend compte du facteur de modération
|
|
(*(resraid.raid)) *= coefStabHourglass;
|
|
(*(resraid.res)) *= coefStabHourglass;
|
|
// on met à jour la raideur et le résidu de l'élément principal
|
|
(*raideur) += (*(resraid.raid));
|
|
(*residu) += (*(resraid.res));
|
|
// on récupère les énergies stockées à l'élément
|
|
const EnergieMeca& energieTotale = tab_elHourglass(1)->EnergieTotaleElement();
|
|
E_Hourglass = coefStabHourglass * (energieTotale.EnergieElastique()
|
|
+ energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse());
|
|
|
|
//---- debug
|
|
//cout << "\n raideur locale après stabilisation d'hourglass ";
|
|
//matRaideur.Affiche();
|
|
//---- fin debug
|
|
};
|
|
break;
|
|
case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT :
|
|
{ // --- calcul de la raideur de l'élément, dans le cas implicite ---
|
|
// ici on calcul la partie supposée supplémentaire à celle déjà présente dans le calcul réduit
|
|
|
|
// au premier passage ou bien si on demande une grande précision de calcul, on calcul la raideur et le second membre,
|
|
// ensuite on ne calcul que le second membre
|
|
// if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 8))
|
|
// en l'expérience prouve que c'est la forme des éléments du début qui est la moins tordu donc vaut mieux
|
|
// ne pas recalculer la raideur sur des éléments tordus, c'est dans ce cas que ça marche le mieux
|
|
if (raid_hourglass_transitoire == NULL)
|
|
{// 1) calcul de la partie complète
|
|
Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs());
|
|
// 2) calcul de la partie réduite
|
|
Element::ResRaid resraid2 = tab_elHourglass(2)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs());
|
|
// on soustrait en gardant le résultat dans resraid1
|
|
// **** non ce n'est pas une bonne idée, lorsque l'on fait certain test de stabilité: lorsque le facteur est très grand
|
|
// si on ne fait pas la soustraction cela converge, avec la soustraction cela ne converge pas donc il ne faut pas soustraire
|
|
// (*(resraid1.raid)) -= (*(resraid2.raid));
|
|
// (*(resraid1.res)) -= (*(resraid2.res));
|
|
|
|
// ---nouvelle idée:
|
|
// on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément
|
|
int NBN = tab_noeud.Taille();
|
|
int dim = ParaGlob::Dimension();
|
|
if(ParaGlob::AxiSymetrie())
|
|
dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés
|
|
Vecteur& D_X = vec_hourglass(1); // pour simplier
|
|
Vecteur& X = vec_hourglass(2); // pour simplier
|
|
D_X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
for (int ine=1;ine<=NBN;ine++)
|
|
{ Noeud& noe = *(tab_noeud(ine)); // pour simplifier
|
|
Coordonnee delta_X = noe.Coord2() - noe.Coord1();
|
|
Coordonnee Xnoeud = noe.Coord2();
|
|
int ipos = (ine-1)*dim;
|
|
switch (dim)
|
|
{ case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;}
|
|
case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;}
|
|
case 1: {D_X(ipos+1)=delta_X(1);
|
|
X(ipos+1)=Xnoeud(1);break;}
|
|
};
|
|
};
|
|
// on multiplie la matrice par le vecteur delta_X
|
|
(*(resraid1.res)) = resraid1.raid->Prod_mat_vec(D_X);
|
|
// on sauvegarde la raideur initiale
|
|
if (raid_hourglass_transitoire == NULL)
|
|
raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid)));
|
|
// premier calcul de l'accroissement de l'énergie
|
|
E_Hourglass = 0.5 * (D_X * (*(resraid1.res)));
|
|
// on tiend compte du facteur de modération
|
|
double coefMultiplicatif = coefStabHourglass;
|
|
if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2)
|
|
{ coefMultiplicatif = -coefStabHourglass;};
|
|
// grandeurs finales avec le bon signe
|
|
(*(resraid1.raid)) *= coefMultiplicatif;
|
|
(*(resraid1.res)) *= coefMultiplicatif;
|
|
// calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale
|
|
E_Hourglass = 0.5 * (X * (*(resraid1.res)));
|
|
|
|
|
|
//debug
|
|
//cout << "\n premier passage, ";
|
|
//res.Affiche(); (resraid1.raid)->Affiche();
|
|
//fin debug
|
|
// on met à jour la raideur et le résidu de l'élément principal
|
|
(*raideur) += (*(resraid1.raid));
|
|
(*residu) -= (*(resraid1.res));
|
|
}
|
|
else
|
|
{// sinon on utilise la précédente raideur sauvegardée et on ne calcul que la partie résidue
|
|
// dans la nouvelle idée le vecteur doit exister à la bonne dimension, mais CalculResidu_tdt n'a pas besoin
|
|
// d'être appeler **** a améliorer
|
|
// Vecteur* resHourglass1 = NULL;
|
|
// resHourglass1 = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());
|
|
/* Vecteur* resHourglass2 = NULL;
|
|
resHourglass2 = tab_elHourglass(2)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());
|
|
// on soustrait les résidus en gardant le résultat dans resraid1
|
|
(*(resHourglass1)) -= (*(resHourglass2));*/
|
|
|
|
|
|
// ---nouvelle idée:
|
|
// on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément
|
|
int NBN = tab_noeud.Taille();
|
|
int dim = ParaGlob::Dimension();
|
|
if(ParaGlob::AxiSymetrie())
|
|
dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés
|
|
Vecteur& D_X = vec_hourglass(1); // pour simplier
|
|
Vecteur& X = vec_hourglass(2); // pour simplier
|
|
D_X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
for (int ine=1;ine<=NBN;ine++)
|
|
{ Noeud& noe = *(tab_noeud(ine)); // pour simplifier
|
|
Coordonnee delta_X = noe.Coord2() - noe.Coord1();
|
|
Coordonnee Xnoeud = noe.Coord2();
|
|
int ipos = (ine-1)*dim;
|
|
switch (dim)
|
|
{ case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;}
|
|
case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;}
|
|
case 1: {D_X(ipos+1)=delta_X(1);
|
|
X(ipos+1)=Xnoeud(1);break;}
|
|
};
|
|
};
|
|
//debug
|
|
//cout << " res ddl, ";
|
|
//res.Affiche();
|
|
//fin debug
|
|
Vecteur& res = vec_hourglass(2); // pour simplier
|
|
res.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
// on multiplie le vecteur delta_X par la matrice
|
|
res = raid_hourglass_transitoire->Prod_mat_vec(D_X);
|
|
// on définit un facteur de modération qui est fondé sur le ratio des énergies
|
|
|
|
// --- essai d'adaptation du coef, mais ça ne marche pas du tout, il n'y a que quand c'est fixe que c'est ok
|
|
/*
|
|
double energieHourglassDeBase = 0.5 * (D_X * res);
|
|
const EnergieMeca& energieActuelle = this->EnergieTotaleElement(); // récup de l'énergie actuelle
|
|
double val_ref_energie = (Dabs(energieActuelle.EnergieElastique())
|
|
+ Dabs(energieActuelle.DissipationPlastique())
|
|
+ Dabs(energieActuelle.DissipationVisqueuse()));
|
|
double coef_a_appliquer = coefStabHourglass;
|
|
if (Dabs(energieHourglassDeBase*coefStabHourglass) > MaX(ConstMath::petit,val_ref_energie))
|
|
coef_a_appliquer *= val_ref_energie / energieHourglassDeBase;
|
|
// on tiend compte du facteur de modération
|
|
res *= coef_a_appliquer;
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) -= res;
|
|
// pour la partie raideur: on met à jour la raideur de l'élément principal
|
|
(*raideur) += coef_a_appliquer * (*raid_hourglass_transitoire);
|
|
// calcul de l'énergie
|
|
E_Hourglass = energieHourglassDeBase * coef_a_appliquer; //0.5 * (D_X * res);
|
|
*/
|
|
|
|
// premier calcul de l'accroissement de l'énergie
|
|
E_Hourglass = 0.5 * (D_X * res);
|
|
// on tiend compte du facteur de modération
|
|
double coefMultiplicatif = coefStabHourglass;
|
|
if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2)
|
|
{ coefMultiplicatif = -coefStabHourglass;};
|
|
// grandeurs finales avec le bon signe
|
|
res *= coefMultiplicatif;
|
|
// calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale
|
|
E_Hourglass = 0.5 * (X * (res));
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) -= res;
|
|
// pour la partie raideur: on met à jour la raideur de l'élément principal
|
|
(*raideur) += coefMultiplicatif * (*raid_hourglass_transitoire);
|
|
|
|
//debug
|
|
//if (E_Hourglass < 0.)
|
|
// { D_X.Affiche();
|
|
// res.Affiche();
|
|
// raid_hourglass_transitoire->Affiche();
|
|
// cout << "\n E_Hourglass= "<< E_Hourglass << endl ;
|
|
//
|
|
// };
|
|
//res.Affiche(); (raid_hourglass_transitoire)->Affiche();
|
|
//fin debug
|
|
};
|
|
|
|
//---- debug
|
|
//cout << "\n raideur locale après stabilisation d'hourglass ";
|
|
//matRaideur.Affiche();
|
|
//---- fin debug
|
|
};
|
|
break;
|
|
case STABHOURGLASS_NON_DEFINIE :
|
|
// on ne fait rien
|
|
break;
|
|
default :
|
|
cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n";
|
|
cout << "\n ElemMeca::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
|
|
};
|
|
|
|
// stabilisation pour un calcul explicit
|
|
void ElemMeca::Cal_explicit_hourglass(bool atdt)
|
|
{ switch (type_stabHourglass)
|
|
{case STABHOURGLASS_PAR_COMPORTEMENT :
|
|
{ // --- calcul de la raideur de l'élément, dans le cas implicite ---
|
|
Vecteur* resHourglass = NULL;
|
|
if (atdt)
|
|
{resHourglass = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());}
|
|
else
|
|
{resHourglass = tab_elHourglass(1)->CalculResidu_t (ParaGlob::param->ParaAlgoControleActifs());};
|
|
// on tiend compte du facteur de modération
|
|
(*resHourglass) *= coefStabHourglass;
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) += (*resHourglass);
|
|
|
|
//---- debug
|
|
//cout << "\n raideur locale après stabilisation d'hourglass ";
|
|
//matRaideur.Affiche();
|
|
//---- fin debug
|
|
};
|
|
break;
|
|
case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT :
|
|
{ // --- on calcul la raideur de l'élément juste à la définition ---
|
|
if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 18)) // pour le debug
|
|
{ // 1) calcul de la partie complète
|
|
Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs());
|
|
// on sauvegarde la raideur initiale
|
|
if (raid_hourglass_transitoire == NULL)
|
|
raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid)));
|
|
// on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément
|
|
int NBN = tab_noeud.Taille();
|
|
int dim = ParaGlob::Dimension();
|
|
if(ParaGlob::AxiSymetrie())
|
|
dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés
|
|
Vecteur& D_X = vec_hourglass(1); // pour simplier
|
|
Vecteur& X = vec_hourglass(2); // pour simplier
|
|
D_X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
for (int ine=1;ine<=NBN;ine++)
|
|
{ Noeud& noe = *(tab_noeud(ine)); // pour simplifier
|
|
Coordonnee delta_X = noe.Coord2() - noe.Coord1();
|
|
Coordonnee Xnoeud = noe.Coord2();
|
|
int ipos = (ine-1)*dim;
|
|
switch (dim)
|
|
{ case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;}
|
|
case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;}
|
|
case 1: {D_X(ipos+1)=delta_X(1);
|
|
X(ipos+1)=Xnoeud(1);break;}
|
|
};
|
|
};
|
|
// on multiplie la matrice par le vecteur delta_X
|
|
(*(resraid1.res)) = resraid1.raid->Prod_mat_vec(D_X);
|
|
// premier calcul de l'accroissement de l'énergie
|
|
E_Hourglass = 0.5 * (D_X * (*(resraid1.res)));
|
|
// on tiend compte du facteur de modération
|
|
double coefMultiplicatif = coefStabHourglass;
|
|
if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2)
|
|
{ coefMultiplicatif = -coefStabHourglass;};
|
|
// grandeurs finales avec le bon signe
|
|
(*(resraid1.raid)) *= coefMultiplicatif;
|
|
(*(resraid1.res)) *= coefMultiplicatif;
|
|
// calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale
|
|
E_Hourglass = 0.5 * (X * (*(resraid1.res)));
|
|
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) -= (*(resraid1.res));
|
|
// calcul de l'énergie
|
|
E_Hourglass = 0.5 * (D_X * (*(resraid1.res)));
|
|
}
|
|
else // cas courant
|
|
{// on utilise la précédente raideur sauvegardée et on ne calcul qu'une partie résidue linéaire
|
|
// on commence par récupérer dans le vecteur résidu les incréments de ddl correspondant à l'élément
|
|
int NBN = tab_noeud.Taille();
|
|
int dim = ParaGlob::Dimension();
|
|
if(ParaGlob::AxiSymetrie())
|
|
dim--; // on passe à une dimension 2 ! et il y a uniquement les x et les y qui sont concernés
|
|
Vecteur& D_X = vec_hourglass(1); // pour simplier
|
|
Vecteur& X = vec_hourglass(2); // pour simplier
|
|
D_X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
for (int ine=1;ine<=NBN;ine++)
|
|
{ Noeud& noe = *(tab_noeud(ine)); // pour simplifier
|
|
Coordonnee delta_X = noe.Coord2() - noe.Coord1();
|
|
Coordonnee Xnoeud = noe.Coord2();
|
|
int ipos = (ine-1)*dim;
|
|
switch (dim)
|
|
{ case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);X(ipos+3)=Xnoeud(3);break;}
|
|
case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);
|
|
X(ipos+1)=Xnoeud(1);X(ipos+2)=Xnoeud(2);break;}
|
|
case 1: {D_X(ipos+1)=delta_X(1);
|
|
X(ipos+1)=Xnoeud(1);break;}
|
|
};
|
|
};
|
|
Vecteur& res = vec_hourglass(2); // pour simplier
|
|
res.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
// on multiplie le vecteur delta_X par la matrice
|
|
res = raid_hourglass_transitoire->Prod_mat_vec(D_X);
|
|
// premier calcul de l'accroissement de l'énergie
|
|
E_Hourglass = 0.5 * (D_X * res);
|
|
// on tiend compte du facteur de modération
|
|
double coefMultiplicatif = coefStabHourglass;
|
|
if (E_Hourglass < 0.) // on veut un accroissement d'énergie positive (1/2 k deltaX ^2)
|
|
{ coefMultiplicatif = -coefStabHourglass;};
|
|
// grandeurs finales avec le bon signe
|
|
res *= coefMultiplicatif;
|
|
// calcul définitif: correspond à une grandeur qui peut être comparée avec l'énergie élastique totale
|
|
E_Hourglass = 0.5 * (X * (res));
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) -= res;
|
|
};
|
|
};
|
|
break;
|
|
case STABHOURGLASS_NON_DEFINIE :
|
|
// on ne fait rien
|
|
break;
|
|
default :
|
|
cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n";
|
|
cout << "\n ElemMeca::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
|
|
};
|
|
|
|
/*
|
|
// récupération de l'energie d'hourglass éventuelle
|
|
double ElemMeca::Energie_Hourglass()
|
|
{double enerHourglass = 0.;
|
|
switch (type_stabHourglass)
|
|
{case STABHOURGLASS_PAR_COMPORTEMENT :
|
|
{ // on récupère les énergies stockées à l'élément
|
|
const EnergieMeca& energieTotale = tab_elHourglass(1)->EnergieTotaleElement();
|
|
enerHourglass = coefStabHourglass * (energieTotale.EnergieElastique()
|
|
+ energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse());
|
|
break;
|
|
}
|
|
case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT :
|
|
{// --- l'énergie est purement une énergie élastique du type 0.5 <D_X> [K] (D_X) ---
|
|
if (raid_hourglass_transitoire == NULL)
|
|
{ enerHourglass = 0.;} // car rien n'a été calculé
|
|
else
|
|
{ int NBN = tab_noeud.Taille(); // récup du nombre de noeuds
|
|
int dim = ParaGlob::Dimension();
|
|
Vecteur& D_X = vec_hourglass(1); // pour simplier
|
|
D_X.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
for (int ine=1;ine<=NBN;ine++)
|
|
{ Noeud& noe = *(tab_noeud(ine)); // pour simplifier
|
|
Coordonnee delta_X = noe.Coord2() - noe.Coord1();
|
|
int ipos = (ine-1)*dim;
|
|
switch (dim)
|
|
{ case 3: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);D_X(ipos+3)=delta_X(3);break;}
|
|
case 2: {D_X(ipos+1)=delta_X(1);D_X(ipos+2)=delta_X(2);break;}
|
|
case 1: {D_X(ipos+1)=delta_X(1);break;}
|
|
};
|
|
};
|
|
Vecteur& res = vec_hourglass(2); // pour simplier
|
|
res.Change_taille(NBN*dim); // changement de la taille au cas où
|
|
// on multiplie la matrice par le vecteur delta_X
|
|
res = raid_hourglass_transitoire->Prod_mat_vec(D_X);
|
|
enerHourglass = 0.5 * (D_X * res);
|
|
//debug
|
|
//cout << " , " << enerHourglass;
|
|
//fin debug
|
|
|
|
};
|
|
break;
|
|
case STABHOURGLASS_NON_DEFINIE :
|
|
// on ne fait rien
|
|
break;
|
|
}
|
|
};
|
|
return enerHourglass;
|
|
};*/
|
|
|
|
// -------------------- stabilisation transversale de membrane ou biel -------------------
|
|
|
|
// mise à jour de "a_calculer" en fonction du contexte
|
|
// NB: pour l'instant ne concerne que le calcul en implicite
|
|
void ElemMeca::Mise_a_jour_A_calculer_force_stab()
|
|
{if (pt_StabMembBiel != NULL)
|
|
{pt_StabMembBiel->Aa_calculer() = true; // on init par défaut
|
|
Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane();
|
|
switch (enu_stab)
|
|
{ case STABMEMBRANE_BIEL_PREMIER_ITER: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER:
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD:
|
|
case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD:
|
|
{// on récupère le pointeur correspondant aux iteration
|
|
const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Mise_a_jour_A_calculer_force_stab(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
int compteur_iter = *(gr.ConteneurEntier());
|
|
if (compteur_iter > 1) // cela veut dire que la force de stabilisation a déjà été calculé
|
|
{pt_StabMembBiel->Aa_calculer() = false;}
|
|
else // sinon il faut la calculer
|
|
{pt_StabMembBiel->Aa_calculer() = true;};
|
|
break;
|
|
}
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR:
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD:
|
|
case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD:
|
|
{int compteur_iter = 0;// init
|
|
{// on récupère le pointeur correspondant aux iteration
|
|
const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
compteur_iter = *(gr.ConteneurEntier());
|
|
}
|
|
// on récupère le pointeur correspondant aux incréments
|
|
int compteur_incr = 0; // init
|
|
{const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est STABMEMBRANE_BIEL_PREMIER_ITER_INCR "
|
|
<< "et la variable globale COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
compteur_iter = *(gr.ConteneurEntier());
|
|
}
|
|
if ((compteur_incr > 1) && (compteur_iter > 1)) // cela veut dire que la force de stabilisation a déjà été calculé
|
|
{pt_StabMembBiel->Aa_calculer() = false;}
|
|
else // sinon il faut la calculer
|
|
{pt_StabMembBiel->Aa_calculer() = true;};
|
|
break;
|
|
}
|
|
default:
|
|
cout << "\n *** erreur le type de stabilisation de membrane et/ou biel n'est pas definie "
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Mise_a_jour_A_calculer_force_stab(..."<<endl;
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
};
|
|
};
|
|
|
|
// stabilisation pour un calcul implicit,
|
|
// iteg -> donne le numéro du dernier pti sur lequel on a travaillé, auquel met est associé
|
|
// iteg == 0 : un seul calcul global, et on est à la suite d'une boucle
|
|
// iteg == -1 : fin d'un calcul avec boucle sur tous les pti, et on est à la suite de la boucle
|
|
// correspond au calcul d'alpha: == stab_ref
|
|
// iteg entre 1 et nbint: on est dans une boucle de pti
|
|
// nbint : le nombre maxi de pti
|
|
// poids_volume : si iteg > 0 : le poids d'intégration
|
|
// si iteg <= 0 : l'intégrale de l'élément (ici la surface totale)
|
|
void ElemMeca::Cal_implicit_StabMembBiel(int iteg,const Met_abstraite::Impli& ex, const int& nbint
|
|
,const double& poids_volume
|
|
,Tableau <int> * noeud_a_prendre_en_compte)
|
|
{// l'idée est de bloquer la direction normale à l'élément pour une plaque et
|
|
// les deux directions transverses pour une biel
|
|
int niveau_affichage = ParaGlob::NiveauImpression();
|
|
if (pt_StabMembBiel->Affichage_stabilisation() > 0)
|
|
niveau_affichage = pt_StabMembBiel->Affichage_stabilisation();
|
|
|
|
//---- détermination de l'intensité de stabilisation
|
|
// celle-ci n'est calculé que dans le cas ou iteg == 0
|
|
// c'est à dire que l'on n'est pas dans une boucle sur les pti, dans la méthode appelant
|
|
double alpha = 0.; // init
|
|
bool stab_utilisable = false; // init
|
|
// bool alpha_vient_etre_calculee = false;
|
|
Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane();
|
|
switch (enu_stab)
|
|
{ case STABMEMBRANE_BIEL_PREMIER_ITER: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER:
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD :
|
|
case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD:
|
|
{// on récupère le pointeur correspondant aux iteration
|
|
const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
int compteur_iter = *(gr.ConteneurEntier());
|
|
|
|
if ((iteg > 0) && (compteur_iter > 1)) // cela veut dire que la la référence de stabilisation a déjà été calculée
|
|
{alpha = pt_StabMembBiel->Stab_ref(); // récup de l'intensité de stabilisation
|
|
// ce n'est pas un pointeur, alpha est une variable locale
|
|
|
|
// dans le cas d'une fonction multiplicatrice ,
|
|
// et il faut appeler la fonction qui peut varier pendant les itérations
|
|
if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// cas où il y a une fonction nD
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
alpha *= tab_ret(1) ;
|
|
pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha
|
|
}
|
|
else // sinon cela veut dire que l'intensité de stabilisation est fixe
|
|
{alpha *= pt_StabMembBiel->Valgamma();}
|
|
stab_utilisable=true;
|
|
}
|
|
else if ((pt_StabMembBiel->Aa_calculer())
|
|
&& (iteg == 0)
|
|
) // cas ou il faut calculer la référence de stabilisation, mais on ne le fait qu'ici car
|
|
// on est sortie de la boucle sur des pti, de manière à utiliser la raideur totale
|
|
{// on récupère la valeur maxi de la raideur
|
|
int i,j; // def
|
|
double& maxival = pt_StabMembBiel->Stab_ref(); // init
|
|
// là il s'agit d'un pointeur donc on travaille directement sur la grandeur stockée
|
|
|
|
if ( (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER)
|
|
||(enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD))
|
|
{maxival = (*raideur).MaxiValAbs(i,j) / poids_volume;
|
|
// alpha_vient_etre_calculee = true;
|
|
}
|
|
else if ( (enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER)
|
|
||(enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD))
|
|
{maxival = (*raideur).Maxi_ligne_ValAbs(i) / poids_volume;
|
|
// alpha_vient_etre_calculee = true;
|
|
}
|
|
else
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< " pas pris en compte pour l'instant .... "
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// arrivée ici Stab_ref() a une valeur
|
|
|
|
// maintenant on va calculer la valeur locale d'alpha
|
|
// on récupère la stabilisation pour lui donner une valeur
|
|
if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// cas où il y a une fonction nD
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
// ici c'est la métrique correspondante au dernier pti
|
|
// comme iteg == 0 on est donc sortie de la boucle sur les pti, le dernier pti c'est nbint
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
alpha = tab_ret(1) * maxival;
|
|
pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha
|
|
}
|
|
else // sinon cela veut dire que l'intensité de stabilisation est fixe ;
|
|
{alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi
|
|
};
|
|
stab_utilisable = true;
|
|
}
|
|
else if (iteg == -1)// cas de la fin d'une boucle, on passe car il n'y a rien à faire
|
|
{if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
{alpha = pt_StabMembBiel->Valgamma();} // on récupère la dernière valeur d'alpha calculée
|
|
else // sinon il s'agit d'une valeur fixe, on recalcule alpha
|
|
{alpha = pt_StabMembBiel->Valgamma() * pt_StabMembBiel->Stab_ref();};
|
|
stab_utilisable = true;
|
|
}
|
|
else // ce n'est pas prévu
|
|
{ cout << "\n *** erreur, iteg = "<< iteg //<< " local= "<< local
|
|
<< " cas non prevu dans la stabilisation "
|
|
<< "\n ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
Sortie(1);
|
|
};
|
|
|
|
|
|
break;
|
|
}
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_INCR: case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR:
|
|
case STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD:
|
|
case STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD:
|
|
{int compteur_iter = 0;// init
|
|
// on récupère le pointeur correspondant aux iteration
|
|
{const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
compteur_iter = *(gr.ConteneurEntier());
|
|
}
|
|
// on récupère le pointeur correspondant aux incréments
|
|
int compteur_incr = 0; // init
|
|
{const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL));
|
|
if (pointe == NULL)
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< "et la variable globale COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL n'est pas disponible"
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
// récup du conteneur du compteur
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
Grandeur_scalaire_entier& gr
|
|
= *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
compteur_iter = *(gr.ConteneurEntier());
|
|
}
|
|
|
|
if ((iteg != 0) && (compteur_incr > 1) && (compteur_iter > 1)) // cela veut dire que la la référence de stabilisation a déjà été calculée
|
|
{alpha = pt_StabMembBiel->Stab_ref(); // init de l'intensité de stabilisation
|
|
// dans le cas d'une fonction, la partie liée à la raideur est stockée dans Valgamma()
|
|
// et il faut appeler la fonction qui peut varier pendant les itérations
|
|
if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// cas où il y a une fonction nD
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
alpha *= tab_ret(1);
|
|
pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha
|
|
}
|
|
else // sinon cela veut dire que l'intensité de stabilisation est fixe
|
|
{alpha *= pt_StabMembBiel->Valgamma();}
|
|
stab_utilisable=true;
|
|
}
|
|
else if ((pt_StabMembBiel->Aa_calculer())
|
|
&& (iteg == 0)
|
|
) // cas ou il faut calculer la référence de stabilisation, mais on ne le fait qu'ici car
|
|
// on est sortie de la boucle sur des pti, de manière à utiliser la raideur totale
|
|
{// on récupère la valeur maxi de la raideur
|
|
int i,j; // def
|
|
double& maxival = pt_StabMembBiel->Stab_ref(); // init
|
|
if ( (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_INCR)
|
|
|| (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_INCR_NORMALE_AU_NOEUD))
|
|
{maxival = (*raideur).MaxiValAbs(i,j);
|
|
// alpha_vient_etre_calculee = true;
|
|
}
|
|
else if ( (enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR)
|
|
||(enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_INCR_NORMALE_AU_NOEUD))
|
|
{maxival = (*raideur).Maxi_ligne_ValAbs(i);
|
|
// alpha_vient_etre_calculee = true;
|
|
}
|
|
else
|
|
{ cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
<< " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
<< " pas pris en compte pour l'instant .... "
|
|
<< " on ne peut pas continuer "
|
|
<< "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
Sortie(1);
|
|
};
|
|
|
|
// on récupère la stabilisation
|
|
if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// cas où il y a une fonction nD
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
// ici c'est la métrique correspondante au dernier pti
|
|
// comme iteg == 0 on est donc sortie de la boucle sur les pti, le dernier pti c'est nbint
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
alpha = tab_ret(1) * maxival;
|
|
pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha
|
|
}
|
|
else // sinon cela veut dire que l'intensité de stabilisation est fixe ;
|
|
{alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi
|
|
};
|
|
stab_utilisable = true;
|
|
}
|
|
else if (iteg == -1)// cas de la fin d'une boucle, on passe car il n'y a rien à faire
|
|
{if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
{alpha = pt_StabMembBiel->Valgamma();} // on récupère la dernière valeur d'alpha calculée
|
|
else // sinon il s'agit d'une valeur fixe, on recalcule alpha
|
|
{alpha = pt_StabMembBiel->Valgamma() * pt_StabMembBiel->Stab_ref();};
|
|
stab_utilisable = true;
|
|
}
|
|
else // ce n'est pas prévu
|
|
{ cout << "\n *** erreur, iteg = "<< iteg //<< " local= "<< local
|
|
<< " cas non prevu dans la stabilisation "
|
|
<< "\n ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
Sortie(1);
|
|
};
|
|
break;
|
|
}
|
|
/*
|
|
// case STAB_M_B_ITER_1_VIA_F_EXT: case STAB_M_B_ITER_1_VIA_F_EXT_NORMALE_AU_NOEUD:
|
|
// {// on récupère le pointeur correspondant aux iteration
|
|
// const void* pointe = (ParaGlob::param->GrandeurGlobal(COMPTEUR_ITERATION_ALGO_GLOBAL));
|
|
// if (pointe == NULL)
|
|
// { cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
// << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
// << "et la variable globale COMPTEUR_ITERATION_ALGO_GLOBAL n'est pas disponible"
|
|
// << " on ne peut pas continuer "
|
|
// << "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
// Sortie(1);
|
|
// };
|
|
// // récup du conteneur du compteur
|
|
// TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
// Grandeur_scalaire_entier& gr
|
|
// = *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
// int compteur_iter = *(gr.ConteneurEntier());
|
|
// if (compteur_iter > 1) // cela veut dire que la force de stabilisation a déjà été calculé
|
|
// {// dans le cas d'une fonction, la partie liée à la raiseur est stockée dans Valgamma()
|
|
// // et il faut appeler la fonction qui peut varier pendant les itérations
|
|
// if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// // cas où il y a une fonction nD
|
|
// { Tableau <double>& tab_val = pt_StabMembBiel->Pt_fct_gamma()->Valeur_pour_variables_globales();
|
|
// // seule la première valeur est ok
|
|
// alpha = tab_val(1) * pt_StabMembBiel->Valgamma();
|
|
// pt_StabMembBiel->FF_StabMembBiel() = alpha; // on sauvegarde
|
|
// }
|
|
// else // sinon cela veut dire que l'intensité de stabilisation est fixe
|
|
// {alpha = pt_StabMembBiel->FF_StabMembBiel();}
|
|
// alpha_utilisable=true;
|
|
// }
|
|
// else if (!local) // sinon il faut la calculer, mais on ne le fait que
|
|
// // si on est sortie de la boucle sur des pti,
|
|
// {// ***** à faire ***** on récupère la valeur maxi de la raideur
|
|
// { cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
// << " partie pas operationnelle pour l'instant !! "
|
|
// << " on ne peut pas continuer "
|
|
// << "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
// Sortie(1);
|
|
// };
|
|
// int i,j; // def
|
|
// double maxival = 0.; // init
|
|
// if ( (enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER)
|
|
// ||(enu_stab == STABMEMBRANE_BIEL_PREMIER_ITER_NORMALE_AU_NOEUD))
|
|
// {maxival = (*raideur).MaxiValAbs(i,j);
|
|
// alpha_vient_etre_calculee = true;
|
|
// }
|
|
// else if ( (enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER)
|
|
// ||(enu_stab == STABMEMBRANE_BIEL_Gerschgorin_PREMIER_ITER_NORMALE_AU_NOEUD))
|
|
// {maxival = (*raideur).Maxi_ligne_ValAbs(i);
|
|
// alpha_vient_etre_calculee = true;
|
|
// }
|
|
// else
|
|
// { cout << "\n *** pb dans la stabilisation de membrane et/ou biel "
|
|
// << " le type de stabilisation est " << Nom_StabMembraneBiel(enu_stab)
|
|
// << " pas pris en compte pour l'instant .... "
|
|
// << " on ne peut pas continuer "
|
|
// << "\nElemMeca::Cal_implicit_StabMembBiel(..."<<endl;
|
|
// Sortie(1);
|
|
// };
|
|
// // on récupère la stabilisation
|
|
// alpha=0.; // init
|
|
// if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// // cas où il y a une fonction nD
|
|
// { Tableau <double>& tab_val = pt_StabMembBiel->Pt_fct_gamma()->Valeur_pour_variables_globales();
|
|
// // seule la première valeur est ok
|
|
// alpha = tab_val(1) * maxival;
|
|
// pt_StabMembBiel->Valgamma() = maxival; // sauvegarde
|
|
// }
|
|
// else // sinon cela veut dire que l'intensité de stabilisation est fixe ;
|
|
// {alpha = pt_StabMembBiel->Valgamma() * maxival; // on prend une proportion du maxi
|
|
// };
|
|
// pt_StabMembBiel->FF_StabMembBiel() = alpha; // on sauvegarde
|
|
// alpha_utilisable = true;
|
|
// };
|
|
// break;
|
|
// }
|
|
*/
|
|
|
|
default:
|
|
cout << "\n *** erreur le type de stabilisation de membrane et/ou biel n'est pas definie "
|
|
<< " on ne peut pas continuer " << endl;
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
|
|
// si la stabilisation est utilisable on s'en sert
|
|
if (stab_utilisable)
|
|
// if ( (alpha_utilisable)
|
|
// // et soit la stabilisation vient juste d'être calculée, donc on est en dehors de la boucle sur les pti
|
|
// // donc on calcule globalement l'impact sur la raideur
|
|
// // ou soit on est en local : et on calcul localement l'impact sur la raideur, mais à la sortie de la boucle
|
|
// // on ne recalculera pas en globa
|
|
// && (alpha_vient_etre_calculee || local)
|
|
// )
|
|
{// choix en fonction de la géométrie
|
|
Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie());
|
|
switch (enu_type_geom)
|
|
{ case SURFACE:
|
|
//#ifdef MISE_AU_POINT
|
|
// if (num_elt==25) // -----debug à virer
|
|
// {cout << "\n ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
// cout << "\n iteg= "<< iteg << flush;
|
|
// };
|
|
//#endif
|
|
if (!Contient_Normale_au_noeud(enu_stab))
|
|
// cas où on utilise la normale au pti
|
|
{// la normale vaut le produit vectoriel des 2 premiers vecteurs
|
|
Coordonnee normale = Util::ProdVec_coor( (*ex.giB_tdt).Coordo(1), (*ex.giB_tdt).Coordo(2));
|
|
// calcul de la variation de la normale
|
|
// 1) variation du produit vectoriel
|
|
Tableau <Coordonnee > D_pasnormale =
|
|
Util::VarProdVect_coor( (*ex.giB_tdt).Coordo(1),(*ex.giB_tdt).Coordo(2),(*ex.d_giB_tdt));
|
|
// 2) de la normale
|
|
Tableau <Coordonnee> D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme());
|
|
|
|
// calcul de la normale normée et pondérée par la stabilisation
|
|
normale.Normer();
|
|
int nbddl = (*residu).Taille();
|
|
int dimf = 3; // ne fonctionne qu'en dim 3
|
|
if(ParaGlob::AxiSymetrie())
|
|
// cas axisymétrique, dans ce cas on ne prend en compte que les
|
|
// dimf-1 coordonnées donc on décrémente
|
|
dimf--;
|
|
int nbne = tab_noeud.Taille();
|
|
double ponder_F_t = 1.; // init
|
|
|
|
// si iteg == 0 ==> un seul calcul, global: correspond au calcul d'alpha: == stab_ref
|
|
// si teg == 1 ==> premier calcul correspondant au premier pti
|
|
if ((iteg == 0) || (iteg == 1))
|
|
{ matD->Initialise(0.);
|
|
resD->Inita(0.);
|
|
maxi_F_t = 0.;
|
|
// on initialise les forces et énergie
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) = 0.;
|
|
pt_StabMembBiel->EE_StabMembBiel(i) = pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
}
|
|
};
|
|
// on récupère l'élément géométrique
|
|
ElemGeomC0& elemGeom = this->ElementGeometrique();
|
|
// récup des fonctions d'interpolation
|
|
const Tableau <Vecteur>& taphi = elemGeom.TaPhi();
|
|
|
|
int nb_noeud_pris_en_compte = 0; //pour faire la moyenne dans le cas iteg == 0
|
|
// on applique une force de stabilisation
|
|
// uniquement suivant la direction de la normale
|
|
int num_pti=iteg; // init
|
|
if (iteg <= 0) num_pti = nbint;
|
|
// la force est proportionelle au déplacement suivant la normale
|
|
if (iteg > -1) // c-a-d == 0 ou plus
|
|
{ int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
nb_noeud_pris_en_compte++;
|
|
|
|
// on va bloquer le déplacement dans la direction de la normale calculée au pti
|
|
|
|
//dans un calcul implicit on utilise la position à l'itération 0
|
|
// celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément
|
|
// on commence par récupérer les coordonnées pour l'itération 0
|
|
TypeQuelconque_enum_etendu enu(XI_ITER_0);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu);
|
|
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
|
|
Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const();
|
|
|
|
double normal_fois_delta_X = normale * delta_X; // le déplacement au noeud suivant la normale au pti
|
|
// dans le cas où on veut pondérer F_t, on calcule la fonction
|
|
if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL)
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi
|
|
(absolue,TEMPS_tdt,li_enu_scal,num_pti,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_pti,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
ponder_F_t = tab_ret(1) ;
|
|
}
|
|
// un - car la force doit s'opposer au déplacement
|
|
double intensite = -alpha * normal_fois_delta_X
|
|
+ ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
// on enregistre le maxi de la force à t
|
|
maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(num_pti));
|
|
|
|
// d'où une variation réelle d'intensité
|
|
double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
pt_StabMembBiel->EE_StabMembBiel(num_pti) += 0.5 * delta_intensite * normal_fois_delta_X;
|
|
#ifdef MISE_AU_POINT
|
|
if (niveau_affichage>5)
|
|
// if (num_elt==25) // -----debug à virer
|
|
{cout << "\n ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
cout << "\n noeud ("<<ne<<"), alpha= "<<alpha << " intensite= "<< intensite
|
|
<< " delta_intensite= " << delta_intensite
|
|
<< " delta_X= "<< delta_X
|
|
<< "\n normale= "<<normale << " normal_fois_delta_X= " << normal_fois_delta_X << flush;
|
|
};
|
|
#endif
|
|
|
|
// //----- debug -----
|
|
// if (num_elt==25) // -----debug à virer
|
|
// {int nb_pti = pt_StabMembBiel->Taille();
|
|
// for (int i=1;i<=nb_pti;i++)
|
|
// {cout << "\n avant update F_stab_t("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel_t(i)<< " ";
|
|
// cout << " F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
// cout << " ponder_F_t= " << ponder_F_t;
|
|
// }
|
|
// };
|
|
// //--- fin debug ----
|
|
// calcul de la raideur: on traite les cas :
|
|
// iteg >0 et iteg == 0
|
|
// le cas iteg == -1 n'est pas à prendre en compte car il correspond
|
|
// au cas où on vient de balayer tous les pti
|
|
if (iteg > 0) // cas où on est dans une boucle d'intégration
|
|
{// un premier coef pour optimiser
|
|
double phi_jacob_poids = taphi(iteg)(ne) * (*ex.jacobien_tdt) * poids_volume ;
|
|
|
|
pt_StabMembBiel->FF_StabMembBiel(iteg) += intensite * taphi(iteg)(ne); // * phi_jacob_poids;
|
|
// taphi(iteg)(ne) * intensite * (*ex.jacobien_tdt) * poids_volume ;
|
|
// NB: 1) comme on multiplie par taphi(iteg)(ne), et que l'on boucle sur les noeuds (ne = 1 à nbne)
|
|
// au sortir de la boucle on a l'intensité totale qui est due au déplacement de tous les noeuds
|
|
// 2) si alpha * normal_fois_delta_X = 0 c-a-d pas d'accroissement d'intensité, on va obtenir
|
|
// somme_noeud(ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti) * taphi(iteg)(ne))
|
|
// et comme somme_noeud(taphi(iteg)(ne))=1, on devrait obtenir une intensité globale identique
|
|
// à celle à t
|
|
|
|
pt_StabMembBiel->EE_StabMembBiel(iteg) += 0.5 * intensite * normal_fois_delta_X * phi_jacob_poids;
|
|
// 0.5 * delta_intensite * normal_fois_delta_X * taphi(iteg)(ne) * (*ex.jacobien_tdt) * poids_volume ;
|
|
|
|
// un second coef pour optimiser
|
|
double phi_poids = taphi(iteg)(ne) * poids_volume ;
|
|
|
|
// pour mémoire: intensite = -alpha * normal_fois_delta_X
|
|
// + pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
{ // = (- normale(i) * alpha * normal_fois_delta_X + F_t)
|
|
// * (taphi(iteg)(ne) * poids * jacobien) ;
|
|
(*resD)(ix) += normale(i) * intensite * phi_jacob_poids;
|
|
// taphi(iteg)(ne)* normale(i) * intensite
|
|
// * (*ex.jacobien_tdt) * poids_volume ; // ok
|
|
// contribution à la raideur: de signe inverse à celui du résidu
|
|
int j=1;
|
|
int me = 1; // numéro de noeud dans la direction des ddl
|
|
|
|
for (int jx = 1; jx <= nbddl; jx++,j++)
|
|
{if (j>dimf) {j=1;me++;};
|
|
(*matD)(ix,jx) += phi_poids // == taphi(iteg)(ne) * poids_volume
|
|
*( (*ex.jacobien_tdt) *
|
|
( D_normale(jx)(i) * alpha * normal_fois_delta_X
|
|
+ normale(i) * alpha * (D_normale(jx) * delta_X)
|
|
)
|
|
+ (*ex.d_jacobien_tdt)(jx) * normale(i) * (-intensite)
|
|
);
|
|
if (ne == me)
|
|
{(*matD)(ix,jx) += phi_poids * normale(i) * alpha * normale(j) * (*ex.jacobien_tdt);
|
|
// taphi(iteg)(ne)* alpha * normale(i) * normale(j) * poids_volume;
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else if (iteg == 0)// on est hors boucle poids_volume == toute la surface
|
|
{// pour le cas particulier d'iteg == 0, on n'a qu'un calcul global
|
|
// et on affecte la même intensité à tous les pti
|
|
// du coup on sauvegarde uniquement pour le dernier
|
|
// ensuite après on répartira sur l'ensemble de pti
|
|
// --> en fait on cumulle l'influence de tous les normales
|
|
// il faudra ensuite prendre la moyenne
|
|
|
|
pt_StabMembBiel->FF_StabMembBiel(num_pti) += intensite ; //* poids_volume;
|
|
// taphi(iteg)(ne) * intensite * poids_volume ;
|
|
pt_StabMembBiel->EE_StabMembBiel(num_pti) += 0.5 * intensite * normal_fois_delta_X * poids_volume;
|
|
// 0.5 * intensite * normal_fois_delta_X * taphi(iteg)(ne) * poids_volume ;
|
|
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
{ // - normale(i) * alpha * normal_fois_delta_X;
|
|
(*resD)(ix) += normale(i) * intensite * poids_volume ; // ok
|
|
// contribution à la raideur: de signe inverse à celui du résidu
|
|
int j=1;
|
|
int me = 1; // numéro de noeud dans la direction des ddl
|
|
for (int jx = 1; jx <= nbddl; jx++,j++)
|
|
{if (j>dimf) {j=1;me++;};
|
|
(*matD)(ix,jx) += poids_volume
|
|
*(( D_normale(jx)(i) * alpha * normal_fois_delta_X
|
|
+ normale(i) * alpha * (D_normale(jx) * delta_X)
|
|
)
|
|
);
|
|
if (ne == me)
|
|
{(*matD)(ix,jx) += poids_volume * normale(i) * alpha * normale(j);
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
}; // fin de la boucle sur les noeuds
|
|
};
|
|
|
|
// dans le cas particulier de iteg == 0, c-a-d correspond au calcul d'alpha: == stab_ref
|
|
// on n'a pas bouclé sur les pti, c'est uniquement un calcul global qui a été effectué
|
|
if (iteg == 0)
|
|
{ // on commence par moyenner: se rappeller que l'on a bouclé aussi sur les noeuds !
|
|
int taille = pt_StabMembBiel->Taille();
|
|
pt_StabMembBiel->FF_StabMembBiel(num_pti) /= (nb_noeud_pris_en_compte);
|
|
pt_StabMembBiel->EE_StabMembBiel(num_pti) /= (nb_noeud_pris_en_compte);
|
|
// ensuite on répartie la même moyenne sur tous les pti
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) = pt_StabMembBiel->FF_StabMembBiel(num_pti);
|
|
pt_StabMembBiel->EE_StabMembBiel(i) = pt_StabMembBiel->EE_StabMembBiel(num_pti);
|
|
};
|
|
// également sur le résidu et la raideur, car due à la boucle sur les noeuds
|
|
if (nb_noeud_pris_en_compte > 0)
|
|
{ double inverse = 1./nb_noeud_pris_en_compte;
|
|
(*matD) *= inverse;
|
|
(*resD) *= inverse;
|
|
};
|
|
};
|
|
////----- debug -----
|
|
// if (num_elt==25) // -----debug à virer
|
|
// {int nb_pti = pt_StabMembBiel->Taille();
|
|
// for (int i=1;i<=nb_pti;i++)
|
|
// cout << "\n final F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
// };
|
|
////--- fin debug ----
|
|
|
|
// on est en dehors de la boucle, on effectue 2 choses
|
|
// 1) application d'une limitation éventuelle des efforts
|
|
// 2) prise en compte dans la raideur et résidu de l'élément, de la stabilisation
|
|
|
|
if ((iteg == 0) || (iteg == -1)) // signifie que l'on est en dehors de la boucle
|
|
{
|
|
if (pt_StabMembBiel->Gestion_maxi_mini())
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (niveau_affichage>9)
|
|
// if (num_elt==1) // -----debug à virer
|
|
{cout << "\n residu de stabilisation avant limitation: "<< (*resD)
|
|
<< "\n residu initial (sans stabilisation): "<< (*residu)
|
|
<< "\n maxi_F_t= " << maxi_F_t;
|
|
};
|
|
if (niveau_affichage > 5)
|
|
// if (num_elt==25) // -----debug à virer
|
|
{int nb_pti = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=nb_pti;i++)
|
|
cout << "\n F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
};
|
|
#endif
|
|
|
|
// 1) ---- on regarde s'il faut limiter la valeur de la stabilisation
|
|
// et on prend en compte dans la raideur globale et le résidu global
|
|
// la stabilisation
|
|
bool limitation = false;
|
|
double coef=1.; // coef de limitation éventuelle si limitation devient true
|
|
|
|
// récup des limitations éventuelles
|
|
double beta = pt_StabMembBiel->Beta();
|
|
double F_mini = pt_StabMembBiel->F_mini();
|
|
double d_maxi = pt_StabMembBiel->D_maxi();
|
|
|
|
// on fait une boucle sur les noeuds
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
// récup de la force de stabilisation généralisée au noeud
|
|
// c'est différent de celle au pti car elle inclue la surface de l'élément
|
|
Coordonnee force_stab(dimf); // init
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
force_stab(i) = (*resD)(ix);
|
|
double intensite_generalise = force_stab.Norme();
|
|
|
|
// on récupère la force externe au noeud à l'instant t
|
|
TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext);
|
|
const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee());
|
|
|
|
// on calcule l'intensité de la force externe selon la normale
|
|
double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale);
|
|
// si l'intensité de la stabilisation est supérieure à beta * intensite_Fext
|
|
// on limite
|
|
|
|
double maxi_intensite = beta * intensite_Fext;
|
|
double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max
|
|
|
|
// on applique l'algo théorique cf. doc théorique
|
|
// erreur, maxi_intensité est une limitation, mais ce que l'on cherche à voir c'est
|
|
// est-ce que les forces externes sont non-nulles, donc c'est intensite_Fext qu'il faut tester
|
|
// if (maxi_intensite >= F_mini)
|
|
if (intensite_Fext >= F_mini)
|
|
// on est dans le cas où les forces externes sont à prendre en compte
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites
|
|
)
|
|
{limitation = true;
|
|
if (niveau_affichage>3)
|
|
{cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite;
|
|
if (niveau_affichage > 5)
|
|
cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
// sinon pas de pb donc on ne fait rien
|
|
}
|
|
else // cas où l'intensité dans la direction normale, des forces externes n'existent pas
|
|
// la limitation va s'exercée via un déplacement maxi
|
|
{maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t);
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites
|
|
&& (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due deplace maxi acceptable, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite
|
|
<< " (max_intens_via_Fext= "<<max_intens_via_Fext<<")" ;
|
|
if ((niveau_affichage > 4))
|
|
cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= "
|
|
<< (alpha*d_maxi)
|
|
<< " alpha= " << alpha
|
|
<< " d_maxi= " << d_maxi;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
};// fin de la boucle sur les noeuds
|
|
|
|
if (limitation)
|
|
{ (*resD) *= coef; // mise à jour de la force de stabilisation
|
|
// idem au niveau des pti
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) *=coef;
|
|
// cas des énergies
|
|
double delta_energie_initiale =
|
|
pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
// on coefficiente le delta
|
|
double delta_energie = delta_energie_initiale * coef;
|
|
//ce qui donne au final:
|
|
pt_StabMembBiel->EE_StabMembBiel(i) =
|
|
delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
};
|
|
};
|
|
};
|
|
|
|
// 2) ---- on met à jour la raideur et résidu global
|
|
// en tenant compte de la stabilisation
|
|
(*residu) += (*resD);
|
|
(*raideur) += (*matD);
|
|
|
|
//et du coup on ne boucle pas sur les pti et on peut limiter la force sauf qu'une fois le calcul des forces
|
|
//aux noeuds fait, il faut ramener par interpolation, la force au pti pour la sauvegarder... bordel
|
|
//non... on sauvegarde dans un tableau indicé par les num de noeud, et seulement pour le post-traitement
|
|
//on calcul la valeur aux pti
|
|
//
|
|
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 9))
|
|
// if (num_elt==1) // -----debug à virer
|
|
{cout << "\n residu de stabilisation: "<< (*resD);
|
|
cout << "\n raideur de stabilisation: "; matD->Affiche();
|
|
cout << "\n fin ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
};
|
|
#endif
|
|
}; // fin du cas iteg == 0 ou -1
|
|
} // fin du cas où on utilise la normale aux pti
|
|
|
|
else
|
|
{if (iteg < 1)
|
|
// on ne calcul que si iteg < 1, c-a-d qu'on est sortie
|
|
// de la boucle sur les pti
|
|
// sinon cas où on utilise la normale aux noeuds
|
|
{int nbddl = (*residu).Taille();
|
|
int dimf = 3; // ne fonctionne qu'en dim 3
|
|
if(ParaGlob::AxiSymetrie())
|
|
// cas axisymétrique, dans ce cas on ne prend en compte que les
|
|
// dimf-1 coordonnées donc on décrémente
|
|
dimf--;
|
|
int nbne = tab_noeud.Taille();
|
|
matD->Initialise(0.);
|
|
resD->Inita(0.);
|
|
maxi_F_t = 0.;
|
|
|
|
#ifdef MISE_AU_POINT
|
|
// on vérifie le bon dimensionnement
|
|
int taille = pt_StabMembBiel->Taille();
|
|
if (taille != nbne)
|
|
{cout << "\n erreur** ElemMeca::Cal_implicit_StabMembBiel(.."
|
|
<< " le stockage est mal dimensionne: taille = " << taille
|
|
<< " alors qu'il devrait etre : nbe = " << nbne << flush ;
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
|
|
// on applique une force de stabilisation aux noeuds
|
|
// uniquement suivant la direction de la normale
|
|
// la force est proportionelle au déplacement suivant la normale au noeud
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
|
|
// on initialise les forces et énergie
|
|
pt_StabMembBiel->FF_StabMembBiel(ne) = 0.;
|
|
pt_StabMembBiel->EE_StabMembBiel(ne) = pt_StabMembBiel->EE_StabMembBiel_t(ne);
|
|
|
|
// pour chaque noeud on va bloquer le déplacement dans la direction de la normale au noeud à t
|
|
// on récupère la normale au noeud
|
|
const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t);
|
|
const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
|
|
const Coordonnee& normale = gr.ConteneurCoordonnee_const();
|
|
|
|
|
|
//dans un calcul implicit on utilise la position à l'itération 0
|
|
// celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément
|
|
// on commence par récupérer les coordonnées pour l'itération 0
|
|
TypeQuelconque_enum_etendu enu(XI_ITER_0);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu);
|
|
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
|
|
Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const();
|
|
double normal_fois_delta_X = normale * delta_X;
|
|
double ponder_F_t = 1.; // init
|
|
// dans le cas où on veut pondérer F_t, on calcule la fonction
|
|
if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL)
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
// au dernier pti !
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi
|
|
(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
ponder_F_t = tab_ret(1) ;
|
|
}
|
|
|
|
// un - car la force doit s'opposer au déplacement
|
|
double intensite = -alpha * normal_fois_delta_X
|
|
+ ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne);
|
|
// on enregistre le maxi de la force à t
|
|
maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(ne));
|
|
|
|
// d'où une variation réelle d'intensité
|
|
double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne);
|
|
pt_StabMembBiel->EE_StabMembBiel(ne) += 0.5 * delta_intensite * normal_fois_delta_X;
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 5))
|
|
{cout << "\n ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
cout << "\n alpha= "<<alpha << " intensite= "<< intensite
|
|
<< " delta_intensite= " << delta_intensite
|
|
<< " delta_X= "<< delta_X
|
|
<< "\n normale= "<<normale << " normal_fois_delta_X= " << normal_fois_delta_X << flush;
|
|
};
|
|
#endif
|
|
|
|
// pour mémoire: intensite = -alpha * normal_fois_delta_X
|
|
// + pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
{ // - normale(i) * stabili * normal_fois_delta_X;
|
|
(*resD)(ix) += normale(i) * intensite ;
|
|
// contribution à la raideur: de signe inverse à celui du résidu
|
|
int j=1;
|
|
int me = 1; // numéro de noeud dans la direction des ddl
|
|
for (int jx = 1; jx <= nbddl; jx++,j++)
|
|
{if (j>dimf) {j=1;me++;};
|
|
if (ne == me)
|
|
{(*matD)(ix,jx) += alpha * normale(i) * normale(j);
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin de la boucle sur les noeuds
|
|
|
|
// on est en dehors de la boucle, on effectue 2 choses
|
|
// 1) application d'une limitation éventuelle des efforts
|
|
// 2) prise en compte dans la raideur et résidu de l'élément, de la stabilisation
|
|
|
|
if (pt_StabMembBiel->Gestion_maxi_mini())
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 9))
|
|
{cout << "\n residu de stabilisation avant limitation: "<< (*resD)
|
|
<< "\n residu initial (sans stabilisation): "<< (*residu)
|
|
<< "\n maxi_F_t= " << maxi_F_t;
|
|
};
|
|
if ((niveau_affichage > 5))
|
|
{int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
cout << "\n F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
};
|
|
#endif
|
|
|
|
// 1) ---- on regarde s'il faut limiter la valeur de la stabilisation
|
|
// et on prend en compte dans la raideur globale et le résidu global
|
|
// la stabilisation
|
|
bool limitation = false;
|
|
double coef=1.; // coef de limitation éventuelle si limitation devient true
|
|
|
|
// récup des limitations éventuelles
|
|
double beta = pt_StabMembBiel->Beta();
|
|
double F_mini = pt_StabMembBiel->F_mini();
|
|
double d_maxi = pt_StabMembBiel->D_maxi();
|
|
// on refait une boucle sur les noeuds
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
// récup de la force de stabilisation généralisée au noeud
|
|
// c'est différent de celle au pti car elle inclue la surface de l'élément
|
|
Coordonnee force_stab(dimf); // init
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
force_stab(i) = (*resD)(ix);
|
|
double intensite_generalise = force_stab.Norme();
|
|
|
|
// on récupère la force externe au noeud à l'instant t
|
|
TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext);
|
|
const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee());
|
|
// on récupère la normale au noeud
|
|
const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t);
|
|
const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
|
|
const Coordonnee& normale = gr.ConteneurCoordonnee_const();
|
|
|
|
// on calcule l'intensité de la force externe selon la normale
|
|
double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale);
|
|
// si l'intensité de la stabilisation est supérieure à beta * intensite_Fext
|
|
// on limite
|
|
|
|
double maxi_intensite = beta * intensite_Fext;
|
|
double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max
|
|
|
|
|
|
// on applique l'algo théorique cf. doc théorique
|
|
if (intensite_Fext >= F_mini)
|
|
// on est dans le cas où les forces externes existent
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite;
|
|
if ((niveau_affichage>4)
|
|
|| (pt_StabMembBiel->Affichage_stabilisation() > 4))
|
|
cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
// sinon pas de pb donc on ne fait rien
|
|
}
|
|
else // cas où les forces externes n'existent pas
|
|
// la limitation va s'exercée via un déplacement maxi
|
|
{maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t);
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites
|
|
&& (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due deplace maxi acceptable, F_s"<< intensite_generalise
|
|
<< " ==> " << maxi_intensite
|
|
<< " (max_intens_via_Fext= "<<max_intens_via_Fext<<")" ;
|
|
|
|
if ((niveau_affichage > 4))
|
|
cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= "
|
|
<< (alpha*d_maxi)
|
|
<< " alpha= " << alpha
|
|
<< " d_maxi= " << d_maxi;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
};// fin de la boucle sur les noeuds
|
|
|
|
if (limitation)
|
|
{ (*resD) *= coef; // mise à jour de la force de stabilisation
|
|
// idem au niveau des noeuds
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) *=coef;
|
|
// cas des énergies
|
|
double delta_energie_initiale =
|
|
pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
// on coefficiente le delta
|
|
double delta_energie = delta_energie_initiale * coef;
|
|
//ce qui donne au final:
|
|
pt_StabMembBiel->EE_StabMembBiel(i) =
|
|
delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
};
|
|
|
|
// 2) ---- on met à jour la raideur et résidu global
|
|
// en tenant compte de la stabilisation
|
|
(*residu) += (*resD);
|
|
(*raideur) += (*matD);
|
|
}; // fin du cas if (limitation)
|
|
}; // fin du cas ou on applique éventuellement une limitation
|
|
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 9))
|
|
{cout << "\n residu de stabilisation: "<< (*resD);
|
|
cout << "\n raideur de stabilisation: "; matD->Affiche();
|
|
cout << "\n fin debug ElemMeca::Cal_implicit_StabMembBiel(..";
|
|
};
|
|
#endif
|
|
} // fin du cas où on utilise la normale aux noeuds
|
|
};
|
|
|
|
break;
|
|
|
|
case LIGNE:
|
|
break;
|
|
|
|
default: // on ne fait rien pour l'instant pour les autres types
|
|
break;
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
// stabilisation pour un calcul explicit
|
|
void ElemMeca::Cal_explicit_StabMembBiel(int iteg,const Met_abstraite::Expli_t_tdt ex
|
|
, const int& nbint,const double& poids_volume
|
|
,Tableau <int> * noeud_a_prendre_en_compte)
|
|
{
|
|
// la stabilisation en explicite n'est possible que s'il existe soit:
|
|
// - une force de stabilisation déjà enregistrée
|
|
// - un coefficient alpha non nulle que l'on peut calculer avec les données déjà enregistrées
|
|
|
|
// l'idée est de bloquer la direction normale à l'élément pour une plaque et
|
|
// les deux directions transverses pour une biel
|
|
int niveau_affichage = ParaGlob::NiveauImpression();
|
|
if (pt_StabMembBiel->Affichage_stabilisation() > 0)
|
|
niveau_affichage = pt_StabMembBiel->Affichage_stabilisation();
|
|
|
|
//---- détermination de l'intensité de stabilisation
|
|
// ici on ne s'occupe pas de l'itération ni de l'incrément, dans tous les cas
|
|
// on utilise les grandeurs déjà stockées
|
|
// ceci quelque soit le type de stabilisation
|
|
|
|
double alpha = 0.; // init
|
|
bool stab_utilisable = false; // init
|
|
Enum_StabMembraneBiel enu_stab = pt_StabMembBiel->Type_stabMembrane();
|
|
|
|
|
|
if (pt_StabMembBiel != NULL)
|
|
if (pt_StabMembBiel->Activite_en_explicite())
|
|
{ //alpha = pt_StabMembBiel->Stab_ref(); // récup de l'intensité de stabilisation
|
|
// ce n'est pas un pointeur, alpha est une variable locale
|
|
// stab_ref, par défaut == 1, mais dans le cas d'un passage
|
|
// implicit -> explicite : vaut la dernière valeur implicite calculée
|
|
// cela permet de profiter du passage en implicite, en récupérant l'intensité
|
|
// de raideur réelle
|
|
alpha = pt_StabMembBiel->Stab_ref(); // init
|
|
|
|
// dans le cas d'une fonction multiplicatrice ,
|
|
// et il faut appeler la fonction qui peut varier
|
|
if (pt_StabMembBiel->Pt_fct_gamma() != NULL)
|
|
// cas où il y a une fonction nD
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_gamma(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
int num_iteg_a_considerer; // init
|
|
if (iteg > 0) // on est dans la boucle
|
|
num_iteg_a_considerer = iteg;
|
|
else // sinon on est à la sortie de la boucle
|
|
num_iteg_a_considerer = nbint;
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi
|
|
(absolue,TEMPS_tdt,li_enu_scal,num_iteg_a_considerer,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_iteg_a_considerer,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
alpha *= tab_ret(1) ;
|
|
pt_StabMembBiel->Valgamma() = alpha; // on sauvegarde la valeur d'alpha
|
|
}
|
|
else // sinon cela veut dire que l'intensité de stabilisation est fixe
|
|
// en explicite c'est directement la valeur lue
|
|
{alpha *= pt_StabMembBiel->Valgamma() ;}
|
|
stab_utilisable=true;
|
|
};
|
|
|
|
// si la stabilisation est utilisable on s'en sert
|
|
if (stab_utilisable)
|
|
{// choix en fonction de la géométrie
|
|
Enum_type_geom enu_type_geom = Type_geom_generique(this->Id_geometrie());
|
|
switch (enu_type_geom)
|
|
{ case SURFACE:
|
|
if (!Contient_Normale_au_noeud(enu_stab))
|
|
// --- cas où on utilise la normale au pti
|
|
{// la normale vaut le produit vectoriel des 2 premiers vecteurs
|
|
Coordonnee normale = Util::ProdVec_coor( (*ex.giB_tdt).Coordo(1), (*ex.giB_tdt).Coordo(2));
|
|
|
|
// calcul de la normale normée et pondérée par la stabilisation
|
|
normale.Normer();
|
|
int nbddl = (*residu).Taille();
|
|
int dimf = 3; // ne fonctionne qu'en dim 3
|
|
if(ParaGlob::AxiSymetrie())
|
|
// cas axisymétrique, dans ce cas on ne prend en compte que les
|
|
// dimf-1 coordonnées donc on décrémente
|
|
dimf--;
|
|
int nbne = tab_noeud.Taille();
|
|
double ponder_F_t = 1.; // init
|
|
|
|
// si iteg == 1 ==> premier calcul correspondant au premier pti
|
|
if (iteg == 1)
|
|
{ resD->Inita(0.);
|
|
maxi_F_t = 0.;
|
|
// on initialise les forces et énergie
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) = 0.;
|
|
pt_StabMembBiel->EE_StabMembBiel(i) = pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
}
|
|
};
|
|
// on récupère l'élément géométrique
|
|
ElemGeomC0& elemGeom = this->ElementGeometrique();
|
|
// récup des fonctions d'interpolation
|
|
const Tableau <Vecteur>& taphi = elemGeom.TaPhi();
|
|
|
|
// on applique une force de stabilisation
|
|
// uniquement suivant la direction de la normale
|
|
// ici iteg peut soit == -1 : on est sortie de la boucle sur les pti
|
|
// soit > 0 : on et dans la boucle des pti
|
|
|
|
int num_pti=iteg; // init
|
|
if (iteg == -1) num_pti = nbint;
|
|
// la force est proportionelle au déplacement suivant la normale
|
|
if (iteg > 0)
|
|
{ int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
|
|
// pour chaque noeud on va rectifier la normale par rapport à celle calculée au pti
|
|
// on va bloquer le déplacement dans la direction de la normale au noeud à t
|
|
// celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément
|
|
// on commence par récupérer les coordonnées pour l'itération 0
|
|
TypeQuelconque_enum_etendu enu(XI_ITER_0);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu);
|
|
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
|
|
Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const();
|
|
|
|
double normal_fois_delta_X = normale * delta_X; // le déplacement suivant la normale
|
|
// dans le cas où on veut pondérer F_t, on calcule la fonction
|
|
if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL)
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi
|
|
(absolue,TEMPS_tdt,li_enu_scal,num_pti,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,num_pti,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
ponder_F_t = tab_ret(1) ;
|
|
}
|
|
// un - car la force doit s'opposer au déplacement
|
|
double intensite = -alpha * normal_fois_delta_X
|
|
+ ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
// on enregistre le maxi de la force à t
|
|
maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(num_pti));
|
|
|
|
// d'où une variation réelle d'intensité
|
|
double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
pt_StabMembBiel->EE_StabMembBiel(num_pti) += 0.5 * delta_intensite * normal_fois_delta_X;
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 5))
|
|
{cout << "\n ElemMeca::Cal_explicit_StabMembBiel(..";
|
|
cout << "\n alpha= "<<alpha << " intensite= "<< intensite
|
|
<< " delta_intensite= " << delta_intensite
|
|
<< " delta_X= "<< delta_X
|
|
<< "\n normale= "<<normale << " normal_fois_delta_X= " << normal_fois_delta_X << flush;
|
|
};
|
|
#endif
|
|
|
|
// calcul de la raideur: on traite les cas :
|
|
// iteg >0 et iteg == 0
|
|
// le cas iteg == -1 n'est pas à prendre en compte car il correspond
|
|
// au cas où on vient de balayer tous les pti
|
|
if (iteg > 0) // cas où on est dans une boucle d'intégration
|
|
{// un premier coef pour optimiser
|
|
double phi_jacob_poids = taphi(iteg)(ne) * (*ex.jacobien_tdt) * poids_volume ;
|
|
|
|
pt_StabMembBiel->FF_StabMembBiel(iteg) += intensite * taphi(iteg)(ne); // * phi_jacob_poids;
|
|
// taphi(iteg)(ne) * intensite * (*ex.jacobien_tdt) * poids_volume ;
|
|
pt_StabMembBiel->EE_StabMembBiel(iteg) += 0.5 * intensite * normal_fois_delta_X * phi_jacob_poids;
|
|
// 0.5 * delta_intensite * normal_fois_delta_X * taphi(iteg)(ne) * (*ex.jacobien_tdt) * poids_volume ;
|
|
|
|
// un second coef pour optimiser
|
|
// double phi_poids = taphi(iteg)(ne) * poids_volume ;
|
|
|
|
// pour mémoire: intensite = -alpha * normal_fois_delta_X
|
|
// + pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
{ // = (- normale(i) * alpha * normal_fois_delta_X + F_t)
|
|
// * (taphi(iteg)(ne) * poids * jacobien) ;
|
|
(*resD)(ix) += normale(i) * intensite * phi_jacob_poids;
|
|
// taphi(iteg)(ne)* normale(i) * intensite
|
|
// * (*ex.jacobien_tdt) * poids_volume ; // ok
|
|
};
|
|
}
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
}; // fin de la boucle sur les noeuds
|
|
};
|
|
|
|
// on est en dehors de la boucle, on effectue 2 choses
|
|
// 1) application d'une limitation éventuelle des efforts
|
|
// 2) prise en compte dans la raideur et résidu de l'élément, de la stabilisation
|
|
// ici seul le cas iteg == -1 est pris en compte contrairement à l'implicite
|
|
if (iteg == -1) // signifie que l'on est en dehors de la boucle
|
|
{
|
|
if (pt_StabMembBiel->Gestion_maxi_mini())
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 5))
|
|
{cout << "\n residu de stabilisation avant limitation: "<< (*resD)
|
|
<< "\n residu initial (sans stabilisation): "<< (*residu)
|
|
<< "\n maxi_F_t= " << maxi_F_t;
|
|
};
|
|
if ((niveau_affichage > 5))
|
|
{int nb_pti = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=nb_pti;i++)
|
|
cout << "\n F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
};
|
|
#endif
|
|
|
|
// 1) ---- on regarde s'il faut limiter la valeur de la stabilisation
|
|
// et on prend en compte dans la raideur globale et le résidu global
|
|
// la stabilisation
|
|
bool limitation = false;
|
|
double coef=1.; // coef de limitation éventuelle si limitation devient true
|
|
|
|
// récup des limitations éventuelles
|
|
double beta = pt_StabMembBiel->Beta();
|
|
double F_mini = pt_StabMembBiel->F_mini();
|
|
double d_maxi = pt_StabMembBiel->D_maxi();
|
|
|
|
// on refait une boucle sur les pti
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
// récup de la force de stabilisation généralisée au noeud
|
|
// c'est différent de celle au pti car elle inclue la surface de l'élément
|
|
Coordonnee force_stab(dimf); // init
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
force_stab(i) = (*resD)(ix);
|
|
double intensite_generalise = force_stab.Norme();
|
|
|
|
// on récupère la force externe au noeud à l'instant t
|
|
TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext);
|
|
const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee());
|
|
|
|
// on calcule l'intensité de la force externe selon la normale
|
|
double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale);
|
|
// si l'intensité de la stabilisation est supérieure à beta * intensite_Fext
|
|
// on limite
|
|
|
|
double maxi_intensite = beta * intensite_Fext;
|
|
double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est dep max
|
|
|
|
|
|
// on applique l'algo théorique cf. doc théorique
|
|
if (intensite_Fext >= F_mini)
|
|
// on est dans le cas où les forces externes existent
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite;
|
|
if ((niveau_affichage > 5))
|
|
cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
// sinon pas de pb donc on ne fait rien
|
|
}
|
|
else // cas où les forces externes n'existent pas
|
|
// la limitation va s'exercée via un déplacement maxi
|
|
{maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t);
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intensite et intensite très petites
|
|
&& (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due deplace maxi acceptable, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite
|
|
<< " (max_intens_via_Fext= "<<max_intens_via_Fext<<")" ;
|
|
|
|
if ((niveau_affichage > 4))
|
|
cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= "
|
|
<< (alpha*d_maxi)
|
|
<< " alpha= " << alpha
|
|
<< " d_maxi= " << d_maxi;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
};// fin de la boucle sur les noeuds
|
|
|
|
if (limitation)
|
|
{ (*resD) *= coef; // mise à jour de la force de stabilisation
|
|
// idem au niveau des pti
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) *=coef;
|
|
// cas des énergies
|
|
double delta_energie_initiale =
|
|
pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
// on coefficiente le delta
|
|
double delta_energie = delta_energie_initiale * coef;
|
|
//ce qui donne au final:
|
|
pt_StabMembBiel->EE_StabMembBiel(i) =
|
|
delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
};
|
|
};
|
|
}; // fin mise en place d'une limitation éventuelle
|
|
|
|
// 2) ---- on met à jour le résidu global
|
|
// en tenant compte de la stabilisation
|
|
(*residu) += (*resD);
|
|
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 9))
|
|
{cout << "\n residu de stabilisation: "<< (*resD);
|
|
cout << "\n fin ElemMeca::Cal_explicit_StabMembBiel(..";
|
|
};
|
|
#endif
|
|
}; // fin du cas iteg == -1
|
|
} // fin du cas où on utilise la normale aux pti
|
|
|
|
else //--- cas où on utilise la normale au noeud
|
|
{if (iteg == -1)
|
|
// on ne calcul que si iteg == -1, c-a-d qu'on est sortie
|
|
// de la boucle sur les pti
|
|
// sinon cas où on utilise la normale aux noeuds
|
|
{int nbddl = (*residu).Taille();
|
|
int dimf = 3; // ne fonctionne qu'en dim 3
|
|
if(ParaGlob::AxiSymetrie())
|
|
// cas axisymétrique, dans ce cas on ne prend en compte que les
|
|
// dimf-1 coordonnées donc on décrémente
|
|
dimf--;
|
|
int nbne = tab_noeud.Taille();
|
|
resD->Inita(0.);
|
|
maxi_F_t = 0.;
|
|
|
|
#ifdef MISE_AU_POINT
|
|
// on vérifie le bon dimensionnement
|
|
int taille = pt_StabMembBiel->Taille();
|
|
if (taille != nbne)
|
|
{cout << "\n erreur** ElemMeca::Cal_explicit_StabMembBiel(.."
|
|
<< " le stockage est mal dimensionne: taille = " << taille
|
|
<< " alors qu'il devrait etre : nbe = " << nbne << flush ;
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
|
|
// on applique une force de stabilisation aux noeuds
|
|
// uniquement suivant la direction de la normale
|
|
// la force est proportionelle au déplacement suivant la normale au noeud
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
|
|
// on initialise les forces et énergie
|
|
pt_StabMembBiel->FF_StabMembBiel(ne) = 0.;
|
|
pt_StabMembBiel->EE_StabMembBiel(ne) = pt_StabMembBiel->EE_StabMembBiel_t(ne);
|
|
|
|
// pour chaque noeud on va bloquer le déplacement dans la direction de la normale au noeud à t
|
|
// on récupère la normale au noeud
|
|
const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t);
|
|
const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
|
|
const Coordonnee& normale = gr.ConteneurCoordonnee_const();
|
|
|
|
|
|
//dans un calcul implicit on utilise la position à l'itération 0
|
|
// celle-ci peut-être différente de celle à t=0, lorsque l'on a une succession d'algo sur le même incrément
|
|
// on commence par récupérer les coordonnées pour l'itération 0
|
|
TypeQuelconque_enum_etendu enu(XI_ITER_0);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel = noe.Grandeur_quelconque(enu);
|
|
const Grandeur_coordonnee& cofo = *((Grandeur_coordonnee*) typquel.Const_Grandeur_pointee());
|
|
Coordonnee delta_X = noe.Coord2() - cofo.ConteneurCoordonnee_const();
|
|
double normal_fois_delta_X = normale * delta_X;
|
|
double ponder_F_t = 1.; // init
|
|
// dans le cas où on veut pondérer F_t, on calcule la fonction
|
|
if (pt_StabMembBiel->Pt_fct_ponder_Ft() != NULL)
|
|
{Fonction_nD* fct = pt_StabMembBiel->Pt_fct_ponder_Ft(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = -1; // signifie que l'on utilise la métrique qui vient juste d'être calculée
|
|
// au dernier pti !
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi
|
|
(absolue,TEMPS_tdt,li_enu_scal,nbint,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,nbint,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// seule la première valeur est ok
|
|
ponder_F_t = tab_ret(1) ;
|
|
}
|
|
|
|
// un - car la force doit s'opposer au déplacement
|
|
double intensite = -alpha * normal_fois_delta_X
|
|
+ ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne);
|
|
// on enregistre le maxi de la force à t
|
|
maxi_F_t = DabsMaX(maxi_F_t, pt_StabMembBiel->FF_StabMembBiel_t(ne));
|
|
|
|
// d'où une variation réelle d'intensité
|
|
double delta_intensite = intensite - ponder_F_t * pt_StabMembBiel->FF_StabMembBiel_t(ne);
|
|
pt_StabMembBiel->EE_StabMembBiel(ne) += 0.5 * delta_intensite * normal_fois_delta_X;
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 5))
|
|
{cout << "\n ElemMeca::Cal_explicit_StabMembBiel(..";
|
|
cout << "\n alpha= "<<alpha << " intensite= "<< intensite
|
|
<< " delta_intensite= " << delta_intensite
|
|
<< " delta_X= "<< delta_X
|
|
<< "\n normale= "<<normale << " normal_fois_delta_X= " << normal_fois_delta_X << flush;
|
|
};
|
|
#endif
|
|
|
|
// pour mémoire: intensite = -alpha * normal_fois_delta_X
|
|
// + pt_StabMembBiel->FF_StabMembBiel_t(num_pti);
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
{ // - normale(i) * stabili * normal_fois_delta_X;
|
|
(*resD)(ix) += normale(i) * intensite ;
|
|
};
|
|
|
|
}; // fin de la boucle sur les noeuds
|
|
|
|
// on est en dehors de la boucle, on effectue 2 choses
|
|
// 1) application d'une limitation éventuelle des efforts
|
|
// 2) prise en compte dans la raideur et résidu de l'élément, de la stabilisation
|
|
|
|
if (pt_StabMembBiel->Gestion_maxi_mini())
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 4))
|
|
{cout << "\n residu de stabilisation avant limitation: "<< (*resD)
|
|
<< "\n residu initial (sans stabilisation): "<< (*residu)
|
|
<< "\n maxi_F_t= " << maxi_F_t;
|
|
};
|
|
if ((niveau_affichage > 4))
|
|
{int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
cout << "\n F_stab("<<i<<")= "<<pt_StabMembBiel->FF_StabMembBiel(i)<< " ";
|
|
};
|
|
#endif
|
|
|
|
// 1) ---- on regarde s'il faut limiter la valeur de la stabilisation
|
|
// et on prend en compte dans la raideur globale et le résidu global
|
|
// la stabilisation
|
|
bool limitation = false;
|
|
double coef=1.; // coef de limitation éventuelle si limitation devient true
|
|
|
|
// récup des limitations éventuelles
|
|
double beta = pt_StabMembBiel->Beta();
|
|
double F_mini = pt_StabMembBiel->F_mini();
|
|
double d_maxi = pt_StabMembBiel->D_maxi();
|
|
// on refait une boucle sur les noeuds
|
|
int ix=1;
|
|
for (int ne =1; ne<= nbne; ne++)
|
|
{bool continuer = true;
|
|
if (noeud_a_prendre_en_compte != NULL)
|
|
if (!(*noeud_a_prendre_en_compte)(ne))
|
|
continuer = false;
|
|
if (continuer)
|
|
{Noeud& noe = *(tab_noeud(ne)); // pour simplifier
|
|
// récup de la force de stabilisation généralisée au noeud
|
|
// c'est différent de celle au pti car elle inclue la surface de l'élément
|
|
Coordonnee force_stab(dimf); // init
|
|
for (int i=1;i<= dimf;i++,ix++)
|
|
force_stab(i) = (*resD)(ix);
|
|
double intensite_generalise = force_stab.Norme();
|
|
|
|
// on récupère la force externe au noeud à l'instant t
|
|
TypeQuelconque_enum_etendu enu_ext(FORCE_GENE_EXT_t);
|
|
// récupération du conteneur pour lecture uniquement
|
|
const TypeQuelconque& typquel_ext = noe.Grandeur_quelconque(enu_ext);
|
|
const Grandeur_coordonnee& cofo_ext = *((Grandeur_coordonnee*) typquel_ext.Const_Grandeur_pointee());
|
|
// on récupère la normale au noeud
|
|
const TypeQuelconque& tiq = noe.Grandeur_quelconque(NN_SURF_t);
|
|
const Grandeur_coordonnee& gr= *((const Grandeur_coordonnee*) (tiq.Const_Grandeur_pointee()));
|
|
const Coordonnee& normale = gr.ConteneurCoordonnee_const();
|
|
|
|
// on calcule l'intensité de la force externe selon la normale
|
|
double intensite_Fext = Dabs(cofo_ext.ConteneurCoordonnee_const() * normale);
|
|
// si l'intensité de la stabilisation est supérieure à beta * intensite_Fext
|
|
// on limite
|
|
|
|
double maxi_intensite = beta * intensite_Fext;
|
|
double max_intens_via_Fext = maxi_intensite; // on sauve pour le cas où on est en dep max
|
|
|
|
|
|
// on applique l'algo théorique cf. doc théorique
|
|
if (intensite_Fext >= F_mini)
|
|
// on est dans le cas où les forces externes existent
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due aux forces externes, F_stab gene= "<< intensite_generalise
|
|
<< " ==> " << maxi_intensite;
|
|
if ((niveau_affichage > 4))
|
|
cout << "\n F_mini= "<< F_mini << " intensite_Fext= "<< intensite_Fext;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
// sinon pas de pb donc on ne fait rien
|
|
}
|
|
else // cas où les forces externes n'existent pas
|
|
// la limitation va s'exercée via un déplacement maxi
|
|
{maxi_intensite = Dabs(-alpha*d_maxi + maxi_F_t);
|
|
{if ((intensite_generalise > maxi_intensite)
|
|
&& (intensite_generalise > ConstMath::petit) // au cas où maxi_intintensite très petites
|
|
&& (Dabs(alpha) > ConstMath::pasmalpetit) // il faut qu'alpha ne soit pas nul
|
|
)
|
|
{limitation = true;
|
|
if ((niveau_affichage > 3))
|
|
{cout << "\n limitation stabilisation due deplace maxi acceptable, F_s"<< intensite_generalise
|
|
<< " ==> " << maxi_intensite << " (max_intens_via_Fext= "<<max_intens_via_Fext<<")" ;
|
|
if ((niveau_affichage > 4))
|
|
cout << "\n maxi_F_t= "<< maxi_F_t << " alpha*d_maxi= "
|
|
<< (alpha*d_maxi)
|
|
<< " alpha= " << alpha
|
|
<< " d_maxi= " << d_maxi;
|
|
};
|
|
coef = DabsMiN(coef, maxi_intensite/intensite_generalise);
|
|
};
|
|
};
|
|
};
|
|
|
|
}; // fin du test sur les noeuds à considérer
|
|
|
|
};// fin de la boucle sur les noeuds
|
|
|
|
if (limitation)
|
|
{ (*resD) *= coef; // mise à jour de la force de stabilisation
|
|
// idem au niveau des noeuds
|
|
int taille = pt_StabMembBiel->Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
{pt_StabMembBiel->FF_StabMembBiel(i) *=coef;
|
|
// cas des énergies
|
|
double delta_energie_initiale =
|
|
pt_StabMembBiel->EE_StabMembBiel(i) - pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
// on coefficiente le delta
|
|
double delta_energie = delta_energie_initiale * coef;
|
|
//ce qui donne au final:
|
|
pt_StabMembBiel->EE_StabMembBiel(i) =
|
|
delta_energie + pt_StabMembBiel->EE_StabMembBiel_t(i);
|
|
};
|
|
|
|
}; // fin du cas if (limitation)
|
|
}; // fin du cas ou on applique éventuellement une limitation
|
|
|
|
// 2) ---- on met à jour la raideur et résidu global
|
|
// en tenant compte de la stabilisation
|
|
(*residu) += (*resD);
|
|
|
|
#ifdef MISE_AU_POINT
|
|
if ((niveau_affichage > 9))
|
|
{cout << "\n residu de stabilisation: "<< (*resD);
|
|
cout << "\n fin debug ElemMeca::Cal_explicit_StabMembBiel(..";
|
|
};
|
|
#endif
|
|
} // fin du cas où on utilise la normale aux noeuds
|
|
};
|
|
|
|
break;
|
|
|
|
case LIGNE:
|
|
break;
|
|
|
|
default: // on ne fait rien pour l'instant pour les autres types
|
|
break;
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
|
|
// fonction a renseigner par les classes dérivées, concernant les répercutions
|
|
// éventuelles due à la suppression de tous les frontières
|
|
// nums_i : donnent les listes de frontières supprimées
|
|
void ElemMeca::Prise_en_compte_des_consequences_suppression_tous_frontieres()
|
|
{// il faut supprimer toutes les déformations liés aux frontières
|
|
int tail_S = defSurf.Taille();
|
|
for (int i=1;i<=tail_S;i++)
|
|
{ delete defSurf(i);
|
|
defSurf(i)=NULL;
|
|
};
|
|
int tail_A = defArete.Taille();
|
|
for (int i=1;i<=tail_A;i++)
|
|
{ delete defArete(i);
|
|
defArete(i)=NULL;
|
|
};
|
|
};
|
|
|
|
// idem pour une frontière (avant qu'elle soit supprimée)
|
|
void ElemMeca::Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront)
|
|
{ int taille = tabb.Taille();
|
|
// on choisit en fonction du type de frontière
|
|
if (( elemFront->Type_geom_front() == LIGNE)&& (defArete.Taille()!=0))
|
|
{int taille_ligne = taille - posi_tab_front_lin; // a priori = cas sans les points
|
|
if (posi_tab_front_point != 0) // cas où il y a des points
|
|
taille_ligne = posi_tab_front_point-posi_tab_front_lin;
|
|
for (int i=1; i<=taille_ligne; i++)
|
|
{if ((tabb(i+posi_tab_front_lin) == elemFront)&& (defArete(i) != NULL))
|
|
{delete defArete(i);defArete(i)=NULL;break;}
|
|
}
|
|
}
|
|
else if (( elemFront->Type_geom_front() == SURFACE) && (defSurf.Taille()!=0))
|
|
{if (posi_tab_front_lin != 0) // si == 0 cela signifie qu'il n'y a pas de surface à supprimer !!
|
|
{ for (int i=1; i<=posi_tab_front_lin; i++) // posi_tab_front_lin == le nombre de surfaces, qui sont obligatoirement en début de tableau
|
|
if ((tabb(i) == elemFront)&& (defSurf(i) != NULL))
|
|
{delete defSurf(i);defSurf(i)=NULL;break;}
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
// Calcul des frontieres de l'element
|
|
// creation des elements frontieres et retour du tableau de ces elements
|
|
// la création n'a lieu qu'au premier appel
|
|
// ou lorsque l'on force le paramètre force a true
|
|
// dans ce dernier cas seul les frontière effacées sont recréée
|
|
// cas :
|
|
// = 0 -> on veut toutes les frontières
|
|
// = 1 -> on veut uniquement les surfaces
|
|
// = 2 -> on veut uniquement les lignes
|
|
// = 3 -> on veut uniquement les points
|
|
// = 4 -> on veut les surfaces + les lignes
|
|
// = 5 -> on veut les surfaces + les points
|
|
// = 6 -> on veut les lignes + les points
|
|
Tableau <ElFrontiere*> const & ElemMeca::Frontiere_elemeca(int cas, bool force)
|
|
{// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
int taille = tabb.Taille(); // la taille initiales des frontières
|
|
if (force) // dans ce cas on commence par tout effacer
|
|
{ // on efface les surfaces (s'il y en a)
|
|
for (int i=1;i<=posi_tab_front_lin;i++)
|
|
{if (tabb(i) != NULL)
|
|
{delete tabb(i); //on commence par supprimer
|
|
tabb(i)=NULL;
|
|
// on supprime également éventuellement la déformation associée
|
|
if (defSurf.Taille() != 0)
|
|
if (defSurf(i) != NULL)
|
|
{delete defSurf(i);defSurf(i)=NULL;};
|
|
ind_front_surf = 0; // on indique qu'il ne reste plus de frontière surface
|
|
};
|
|
};
|
|
// on efface les lignes (s'il y en a)
|
|
for (int i=1;i<=posi_tab_front_point - posi_tab_front_lin;i++)
|
|
{if (tabb(i+posi_tab_front_lin) != NULL)
|
|
{delete tabb(i+posi_tab_front_lin); //on commence par supprimer
|
|
tabb(i+posi_tab_front_lin)=NULL;
|
|
// on supprime également éventuellement la déformation associée
|
|
if (defArete.Taille() != 0)
|
|
if (defArete(i) != NULL)
|
|
{delete defArete(i);defArete(i)=NULL;};
|
|
ind_front_lin = 0; // on indique qu'il ne reste plus de frontière ligne
|
|
};
|
|
};
|
|
// on efface les points (s'il y en a)
|
|
for (int i=1;i<=taille - posi_tab_front_point;i++)
|
|
{if (tabb(i+posi_tab_front_point) != NULL)
|
|
{delete tabb(i+posi_tab_front_point); //on commence par supprimer
|
|
tabb(i+posi_tab_front_point)=NULL;
|
|
ind_front_point = 0; // on indique qu'il ne reste plus de frontière ligne
|
|
};
|
|
};
|
|
};
|
|
|
|
// -- maintenant on s'occupe de la construction conditionnelle
|
|
bool built_surf = false;bool built_ligne = false; bool built_point = false;
|
|
switch (cas)
|
|
{case 0: built_surf = built_ligne = built_point = true; break;
|
|
case 1: built_surf = true; break;
|
|
case 2: built_ligne = true; break;
|
|
case 3: built_point = true; break;
|
|
case 4: built_surf = built_ligne = true; break;
|
|
case 5: built_surf = built_point = true; break;
|
|
case 6: built_ligne = built_point = true; break;
|
|
};
|
|
|
|
if ( ((ind_front_surf == 0)&& (ind_front_lin == 0) && (ind_front_point == 0)) || force )
|
|
{
|
|
// récup de l'élément géométrique
|
|
ElemGeomC0& el = ElementGeometrique();
|
|
int tail_ar = el.NbSe(); // nombre potentiel d'arêtes
|
|
int tail_fa = el.NbFe(); // nombre potentiel de faces
|
|
int tail_po = el.Nbne(); // nombre potentiel de points
|
|
// récup du tableau de ddl actuel
|
|
const DdlElement & tdd = TableauDdl();
|
|
|
|
// --- on va construire en fonction des indicateurs des tableaux intermédiaires
|
|
int new_posi_tab_front_point = 0; //init par défaut
|
|
int new_posi_tab_front_lin = 0; //init par défaut
|
|
int new_ind_front_point = 0;
|
|
int new_ind_front_lin = 0;
|
|
int new_ind_front_surf = 0;
|
|
// -- pour les surfaces
|
|
Tableau <ElFrontiere*> tabb_surf;
|
|
if ((built_surf)&& ((ind_front_surf == 0)||force))
|
|
{tabb_surf.Change_taille(tail_fa,NULL);// init par défaut
|
|
for (int num=1;num<=tail_fa;num++)
|
|
{ int nbnoe = el.Nonf()(num).Taille(); // nb noeud de la surface
|
|
Tableau <Noeud *> tab(nbnoe); // les noeuds de la frontiere
|
|
DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres
|
|
for (int i=1;i<= nbnoe;i++)
|
|
{ tab(i) = tab_noeud(el.Nonf()(num)(i));
|
|
ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i)));
|
|
};
|
|
tabb_surf(num) = new_frontiere_surf(num,tab,ddelem);
|
|
};
|
|
// nouveau indicateur d'existence
|
|
new_ind_front_surf = 1;
|
|
// on positionne les nouvelles positions
|
|
new_posi_tab_front_point += tail_fa;
|
|
new_posi_tab_front_lin += tail_fa;
|
|
};
|
|
// -- pour les lignes
|
|
Tableau <ElFrontiere*> tabb_ligne;
|
|
if ((built_ligne)&& ((ind_front_lin == 0)||force))
|
|
{tabb_ligne.Change_taille(tail_ar,NULL);// init par défaut
|
|
for (int num=1;num<=tail_ar;num++)
|
|
{ int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête
|
|
Tableau <Noeud *> tab(nbnoe); // les noeuds de l'arête frontiere
|
|
DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres
|
|
for (int i=1;i<= nbnoe;i++)
|
|
{ tab(i) = tab_noeud(el.NonS()(num)(i));
|
|
ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i)));
|
|
};
|
|
tabb_ligne(num) = new_frontiere_lin(num,tab,ddelem);
|
|
};
|
|
// nouveau indicateur d'existence
|
|
new_ind_front_lin = 1;
|
|
// on positionne les nouvelles positions
|
|
new_posi_tab_front_point += tail_ar;
|
|
};
|
|
// -- pour les points
|
|
Tableau <ElFrontiere*> tabb_point;
|
|
if ((built_point) && ((ind_front_point == 0)||force))
|
|
{tabb_point.Change_taille(tail_po,NULL);// init par défaut
|
|
// maintenant création des frontière point éventuellement
|
|
Tableau <Noeud *> tab(1); // les noeuds de la frontiere (tab de travail)
|
|
DdlElement ddelem(1); // les ddlelements des points frontieres (tab de travail)
|
|
for (int i=1;i<=tail_po;i++)
|
|
if (tabb_point(i) == NULL)
|
|
{ tab(1) = tab_noeud(i);
|
|
ddelem.Change_un_ddlNoeudElement(1,tdd(i));
|
|
tabb_point(i) = new FrontPointF(tab,ddelem);
|
|
};
|
|
// nouveau indicateur d'existence
|
|
new_ind_front_point = 1;
|
|
};
|
|
|
|
// --- mise à jour du tableau globale et des indicateurs ad hoc
|
|
int taille_finale = tabb_surf.Taille()+tabb_ligne.Taille()+tabb_point.Taille();
|
|
tabb.Change_taille(taille_finale);
|
|
// cas des points
|
|
if (new_ind_front_point) // là is s'agit de nouveaux éléments
|
|
{for (int i=tail_po;i>0;i--) // transfert pour les noeuds
|
|
{ tabb(i+new_posi_tab_front_point) = tabb_point(i);}
|
|
}
|
|
else if (ind_front_point) // là il s'agit d'anciens éléments
|
|
{for (int i=tail_po;i>0;i--) // transfert pour les noeuds en descendant
|
|
{ tabb(i+new_posi_tab_front_point) = tabb(i+posi_tab_front_point);}
|
|
};
|
|
// cas des lignes
|
|
if (new_ind_front_lin) // là il s'agit de nouveaux éléments
|
|
{for (int i=1;i<=tail_ar;i++) // transfert
|
|
{ tabb(i+new_posi_tab_front_lin) = tabb_ligne(i);}
|
|
}
|
|
else if (ind_front_lin) // là il s'agit d'anciens éléments
|
|
{for (int i=tail_ar;i>0;i--) // transfert en descendant
|
|
{ tabb(i+new_posi_tab_front_lin) = tabb(i+posi_tab_front_lin);}
|
|
};
|
|
// cas des surfaces
|
|
if (new_ind_front_surf) // là is s'agit de nouveaux éléments
|
|
{for (int i=1;i<=tail_fa;i++) // transfert
|
|
{ tabb(i) = tabb_surf(i);}
|
|
};
|
|
// dans le cas où il y avait des anciens éléments, il n'y a rien n'a faire
|
|
// car le redimentionnement de tabb ne change pas les premiers éléments
|
|
|
|
// mis à jour des indicateurs
|
|
ind_front_surf = new_ind_front_surf;
|
|
posi_tab_front_lin = new_posi_tab_front_lin;
|
|
ind_front_lin = new_ind_front_lin;
|
|
posi_tab_front_point = new_posi_tab_front_point;
|
|
ind_front_point = new_ind_front_point;
|
|
};
|
|
// retour du tableau
|
|
return (Tableau <ElFrontiere*>&)tabb;
|
|
};
|
|
|
|
// ramène la frontière point
|
|
// éventuellement création des frontieres points de l'element et stockage dans l'element
|
|
// si c'est la première fois sinon il y a seulement retour de l'elements
|
|
// a moins que le paramètre force est mis a true
|
|
// dans ce dernier cas la frontière effacéee est recréée
|
|
// num indique le numéro du point à créer (numérotation EF)
|
|
ElFrontiere* const ElemMeca::Frontiere_points(int num,bool force)
|
|
{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière point à calculer
|
|
// récup de l'élément géométrique
|
|
ElemGeomC0& el = ElementGeometrique();
|
|
int tail_po = el.Nbne(); // nombre potentiel de points
|
|
if (num > tail_po)
|
|
return NULL;
|
|
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
// on regarde si les frontières points existent sinon on les crée
|
|
if (ind_front_point == 1)
|
|
{return (ElFrontiere*)tabb(posi_tab_front_point+num);}
|
|
else if ( ind_front_point == 2)
|
|
// cas où certaines frontières existent
|
|
{if (tabb(posi_tab_front_point+num) != NULL)
|
|
return (ElFrontiere*)tabb(posi_tab_front_point+num);
|
|
};
|
|
|
|
// arrivée ici cela veut dire que la frontière point n'existe pas
|
|
// on l'a reconstruit éventuellement
|
|
|
|
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
if ((ind_front_point == 0) || force )
|
|
{// récup du tableau de ddl
|
|
const DdlElement & tdd = TableauDdl();
|
|
int taille = tabb.Taille(); // la taille initiales des frontières
|
|
int tail_fa = el.NbFe(); // nombre potentiel de faces
|
|
int tail_ar = el.NbSe(); // nombre potentiel d'arêtes
|
|
// dimensionnement du tableau de frontières ligne si nécessaire
|
|
if (ind_front_point == 0)
|
|
{if ((ind_front_lin > 0) && (ind_front_surf == 0))
|
|
// cas où les frontières lignes existent seules, on ajoute les points
|
|
{ int taille_finale = tail_ar + tail_po;
|
|
tabb.Change_taille(taille_finale);
|
|
for (int i=1;i<= tail_ar;i++) // transfert pour les lignes
|
|
tabb(i) = tabb(i+tail_ar);
|
|
posi_tab_front_point=tail_ar;
|
|
posi_tab_front_lin = 0; // car on n'a pas de surface
|
|
}
|
|
else if ((ind_front_lin > 0) && (ind_front_surf > 0))
|
|
// cas où les frontières lignes existent et surfaces et pas de points, donc on les rajoutes
|
|
{ int taille_finale = tail_fa + tail_po+tail_ar;
|
|
tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces et les lignes sont
|
|
// conservées, donc pas de transferts à prévoir
|
|
posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes
|
|
posi_tab_front_lin = tail_fa; // après les surfaces
|
|
}
|
|
else
|
|
{ // cas où il n'y a pas de frontières lignes
|
|
if (ind_front_surf == 0) // cas où il n'y a pas de surface
|
|
{tabb.Change_taille(tail_po,NULL); // on n'a pas de ligne, pas de point et pas de surface
|
|
posi_tab_front_point = posi_tab_front_lin = 0;}
|
|
else {tabb.Change_taille(tail_po+tail_fa); // cas où les surfaces existent
|
|
// le redimensionnement n'affecte pas les surfaces qui sont en début de tableau
|
|
posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces
|
|
};
|
|
};
|
|
// et on met les pointeurs de points en NULL
|
|
for (int i=1;i<= tail_po;i++)
|
|
{ tabb(i+posi_tab_front_point) = NULL;}
|
|
};
|
|
// maintenant création de la frontière point
|
|
Tableau <Noeud *> tab(1); // les noeuds de la frontiere
|
|
tab(1) = tab_noeud(num);
|
|
DdlElement ddelem(1); // les ddlelements des points frontieres
|
|
ddelem.Change_un_ddlNoeudElement(1,tdd(num));
|
|
tabb(posi_tab_front_point+num) = new FrontPointF(tab,ddelem);
|
|
// on met à jour l'indicateur ind_front_point
|
|
ind_front_point = 1; // a priori
|
|
for (int npoint=1;npoint<=tail_po;npoint++)
|
|
if (tabb(posi_tab_front_point+npoint) == NULL)
|
|
{ ind_front_point = 2; break;};
|
|
};
|
|
// maintenant normalement la frontière est créé on la ramène
|
|
return (ElFrontiere*)tabb(posi_tab_front_point+num);
|
|
};
|
|
|
|
// ramène la frontière linéique
|
|
// éventuellement création des frontieres linéique de l'element et stockage dans l'element
|
|
// si c'est la première fois et en 3D sinon il y a seulement retour de l'elements
|
|
// a moins que le paramètre force est mis a true
|
|
// dans ce dernier cas la frontière effacéee est recréée
|
|
// num indique le numéro de l'arête à créer (numérotation EF)
|
|
// nbneA: nombre de noeuds des segments frontières
|
|
// el : l'élément
|
|
ElFrontiere* const ElemMeca::Frontiere_lineique(int num,bool force)
|
|
{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière linéique à calculer
|
|
// récup de l'élément géométrique
|
|
ElemGeomC0& el = ElementGeometrique();
|
|
int tail_ar = el.NbSe(); // nombre potentiel d'arêtes
|
|
if (num > tail_ar)
|
|
return NULL;
|
|
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
// on regarde si les frontières linéiques existent sinon on les crée
|
|
if (ind_front_lin == 1)
|
|
{return (ElFrontiere*)tabb(posi_tab_front_lin+num);}
|
|
else if ( ind_front_lin == 2)
|
|
// cas où certaines frontières existent
|
|
{if (tabb(posi_tab_front_lin+num) != NULL)
|
|
return (ElFrontiere*)tabb(posi_tab_front_lin+num);
|
|
};
|
|
|
|
// arrivée ici cela veut dire que la frontière ligne n'existe pas
|
|
// on l'a reconstruit
|
|
|
|
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
if ((ind_front_lin == 0) || force )
|
|
{// récup du tableau de ddl
|
|
const DdlElement & tdd = TableauDdl();
|
|
int taille = tabb.Taille(); // la taille initiales des frontières
|
|
int tail_fa = el.NbFe(); // nombre potentiel de faces
|
|
int tail_po = el.Nbne(); // nombre potentiel de points
|
|
// dimensionnement du tableau de frontières ligne si nécessaire
|
|
if (ind_front_lin == 0)
|
|
{if ((ind_front_point > 0) && (ind_front_surf == 0))
|
|
// cas où les frontières points existent seules, on ajoute les lignes
|
|
{ int taille_finale = tail_ar + tail_po;
|
|
tabb.Change_taille(taille_finale);
|
|
for (int i=1;i<= tail_po;i++)
|
|
tabb(i+tail_ar) = tabb(i);
|
|
posi_tab_front_point=tail_ar;
|
|
posi_tab_front_lin = 0; // car on n'a pas de surface
|
|
}
|
|
else if ((ind_front_point > 0) && (ind_front_surf > 0))
|
|
// cas où les frontières points existent et surfaces et pas de ligne, donc on les rajoutes
|
|
{ int taille_finale = tail_fa + tail_po+tail_ar;
|
|
tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces sont conservées
|
|
for (int i=1;i<= tail_po;i++) // transfert pour les noeuds
|
|
{ tabb(i+tail_ar+tail_fa) = tabb(i+tail_fa);};
|
|
posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes
|
|
posi_tab_front_lin = tail_fa; // après les surfaces
|
|
}
|
|
else
|
|
{ // cas où il n'y a pas de frontières points
|
|
if (ind_front_surf == 0) // cas où il n'y a pas de surface
|
|
{tabb.Change_taille(tail_ar,NULL); // on n'a pas de ligne, pas de point et pas de surface
|
|
posi_tab_front_lin = 0; posi_tab_front_point = tail_ar;
|
|
}
|
|
else {tabb.Change_taille(tail_ar+tail_fa); // cas où les surfaces existent
|
|
// le redimensionnement n'affecte pas les surfaces qui sont en début de tableau
|
|
posi_tab_front_lin = tail_fa; // après les surfaces
|
|
posi_tab_front_point = tail_fa+tail_ar;
|
|
};
|
|
};
|
|
// et on met les pointeurs de lignes en NULL
|
|
for (int i=1;i<= tail_ar;i++) // transfert pour les noeuds
|
|
{ tabb(i+posi_tab_front_lin) = NULL;}
|
|
};
|
|
// maintenant création de la ligne
|
|
int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête
|
|
Tableau <Noeud *> tab(nbnoe); // les noeuds de l'arête frontiere
|
|
DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres
|
|
for (int i=1;i<= nbnoe;i++)
|
|
{ tab(i) = tab_noeud(el.NonS()(num)(i));
|
|
ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i)));
|
|
};
|
|
tabb(posi_tab_front_lin+num) = new_frontiere_lin(num,tab,ddelem);
|
|
ind_front_lin = 1; // a priori
|
|
for (int nlign=1;nlign<=tail_ar;nlign++)
|
|
if (tabb(posi_tab_front_lin+nlign) == NULL)
|
|
{ ind_front_lin = 2; break;};
|
|
};
|
|
// maintenant normalement la frontière est créé on la ramène
|
|
return (ElFrontiere*)tabb(posi_tab_front_lin+num);
|
|
};
|
|
|
|
// ramène la frontière surfacique
|
|
// éventuellement création des frontieres surfacique de l'element et stockage dans l'element
|
|
// si c'est la première fois sinon il y a seulement retour de l'elements
|
|
// a moins que le paramètre force est mis a true
|
|
// dans ce dernier cas la frontière effacéee est recréée
|
|
// num indique le numéro de la surface à créer (numérotation EF)
|
|
ElFrontiere* const ElemMeca::Frontiere_surfacique(int num,bool force)
|
|
{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer
|
|
// récup de l'élément géométrique
|
|
ElemGeomC0& el = ElementGeometrique();
|
|
int tail_fa = 0; // init
|
|
|
|
// test --- retour rapide si l'existance n'est pas possible
|
|
if (ParaGlob::AxiSymetrie())
|
|
// dans le cas axiSymétrique, le test est un peu différent car les surfaces sont générées
|
|
// par les lignes,
|
|
{tail_fa = el.NbSe(); // nombre potentiel de segments
|
|
if (num > tail_fa)
|
|
return NULL;
|
|
}
|
|
else // dans le cas où on n'est pas en axi, test simple
|
|
{tail_fa = el.NbFe(); // nombre potentiel de faces
|
|
if (num > tail_fa)
|
|
return NULL;
|
|
};
|
|
|
|
// --- la suite concerne le cas où on peut faire des surfaces (non axi ou axi !)
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
// on regarde si les frontières surfacique existent sinon on les crée
|
|
if (ind_front_surf == 1)
|
|
{return (ElFrontiere*)tabb(num);}
|
|
else if ( ind_front_surf == 2)
|
|
// cas où certaines frontières existent
|
|
{if (tabb(num) != NULL)
|
|
return (ElFrontiere*)tabb(num);
|
|
};
|
|
|
|
// arrivée ici cela veut dire que la frontière surface n'existe pas
|
|
// on l'a reconstruit
|
|
|
|
|
|
// le calcul et la création ne sont effectués qu'au premier appel
|
|
// ou lorsque l'on veut forcer une recréation
|
|
if ((ind_front_surf == 0) || force )
|
|
{// récup du tableau de ddl
|
|
const DdlElement & tdd = TableauDdl();
|
|
int taille = tabb.Taille(); // la taille initiales des frontières
|
|
int tail_ar = el.NbSe(); // nombre potentiel d'arêtes
|
|
int tail_po = el.Nbne(); // nombre potentiel de points
|
|
// dimensionnement du tableau de frontières surfaces si nécessaire
|
|
if (ind_front_surf == 0)
|
|
{if ((ind_front_point > 0) && (ind_front_lin == 0))
|
|
// cas où les frontières points existent seules, on ajoute les surfaces
|
|
{ int taille_finale = tail_fa + tail_po;
|
|
tabb.Change_taille(taille_finale);
|
|
for (int i=1;i<= tail_po;i++)
|
|
tabb(i+tail_fa) = tabb(i);
|
|
posi_tab_front_lin=posi_tab_front_point=tail_fa;
|
|
}
|
|
else if ((ind_front_point > 0) && (ind_front_lin > 0))
|
|
// cas où les frontières points existent et lignes et pas de surfaces, donc on les rajoutes
|
|
{ int taille_finale = tail_fa + tail_po+tail_ar;
|
|
tabb.Change_taille(taille_finale);
|
|
// --transfert pour les noeuds et les lignes
|
|
for (int i=1;i<= tail_po;i++) // transfert pour les noeuds
|
|
{ tabb(i+tail_ar+tail_fa) = tabb(i+tail_ar);};
|
|
for (int i=1;i<= tail_ar;i++) // transfert pour les lignes
|
|
{ tabb(i+tail_fa) = tabb(i);};
|
|
// --def des indicateurs
|
|
posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes
|
|
posi_tab_front_lin = tail_fa; // après les surfaces
|
|
}
|
|
else
|
|
{ // cas où il n'y a pas de frontières points
|
|
if (ind_front_lin == 0) // cas où il n'y a pas de lignes
|
|
{tabb.Change_taille(tail_fa,NULL); // on n'a pas de ligne, pas de point et pas de surface
|
|
posi_tab_front_lin = posi_tab_front_point = tail_fa;
|
|
} // on peut tout mettre à NULL
|
|
else {tabb.Change_taille(tail_ar+tail_fa); // cas où les lignes existent
|
|
for (int i=1;i<= tail_ar;i++) // transfert pour les lignes
|
|
tabb(i+tail_fa) = tabb(i);
|
|
posi_tab_front_lin = tail_fa; // après les surfaces
|
|
posi_tab_front_point = tail_fa + tail_ar;
|
|
};
|
|
};
|
|
// --et on met les pointeurs de surfaces en NULL
|
|
for (int i=1;i<=tail_fa;i++)
|
|
tabb(i)=NULL;
|
|
};
|
|
// maintenant création de la surface
|
|
int nbnoe = el.Nonf()(num).Taille(); // b noeud de la surface
|
|
Tableau <Noeud *> tab(nbnoe); // les noeuds de la frontiere
|
|
DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres
|
|
for (int i=1;i<= nbnoe;i++)
|
|
{ tab(i) = tab_noeud(el.Nonf()(num)(i));
|
|
ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i)));
|
|
};
|
|
tabb(num) = new_frontiere_surf(num,tab,ddelem);
|
|
ind_front_surf = 1; // a priori
|
|
for (int nsurf=1;nsurf<=tail_fa;nsurf++)
|
|
if (tabb(nsurf) == NULL)
|
|
{ ind_front_surf = 2; break;};
|
|
};
|
|
// maintenant normalement la frontière est créé on la ramène
|
|
return (ElFrontiere*)tabb(num);
|
|
};
|
|
|
|
// calcul des intégrales de volume et de volume + temps
|
|
// cas = 1 : pour un appel après un calcul implicit
|
|
// cas = 2 : pour un appel après un calcul explicit
|
|
void ElemMeca::Calcul_Integ_vol_et_temps(int cas,const double& poid_jacobien,int iteg)
|
|
{ // 1) intégration de volume uniquement
|
|
//List_io <TypeQuelconque> integ_vol_typeQuel,integ_vol_typeQuel_t;
|
|
if (integ_vol_typeQuel != NULL)
|
|
// on balaie les conteneurs
|
|
{ int taille = integ_vol_typeQuel->Taille();
|
|
Tableau <TypeQuelconque> & tab_integ = *integ_vol_typeQuel; // pour simplifier
|
|
for (int il =1;il <= taille ;il++)
|
|
// l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit
|
|
// d'une valeur figée
|
|
if ((*index_Integ_vol_typeQuel)(il))
|
|
{// différent choix
|
|
switch (tab_integ(il).Const_Grandeur_pointee()->Type_enumGrandeurParticuliere())
|
|
{case PARTICULIER_DDL_ETENDU:
|
|
{ Grandeur_Ddl_etendu& gr
|
|
= *((Grandeur_Ddl_etendu*) tab_integ(il).Grandeur_pointee()); // pour simplifier
|
|
Ddl_etendu& ddl = *(gr.ConteneurDdl_etendu());// récup du ddl
|
|
// on va utiliser la méthode Valeur_multi ce qui n'est pas optimal en vitesse
|
|
// mais 1) c'est cohérent avec l'implantation existante
|
|
// 2) identique avec les ddl déjà accessibles
|
|
List_io<Ddl_enum_etendu> inter; // une liste intermédiaire
|
|
inter.push_back(ddl.DdlEnumEtendu());
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// calcul de la valeur et retour dans tab_d
|
|
Tableau <double> tab_d(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,inter,iteg,-cas));
|
|
// on cumule l'intégrale
|
|
ddl.Valeur() += tab_d(1) * poid_jacobien;
|
|
////---- debug
|
|
//cout << "\n debug: ElemMeca::Calcul_Integ_vol_et_temps(";
|
|
//cout << " tab_d(1)= "<< tab_d(1) << " ";ddl.Affiche();
|
|
//tab_noeud(1)->Affiche();
|
|
////---- fin debug
|
|
|
|
break;
|
|
}
|
|
case PARTICULIER_VECTEUR_NOMMER:
|
|
{ Grandeur_Vecteur_Nommer& gr
|
|
= *((Grandeur_Vecteur_Nommer*) tab_integ(il).Grandeur_pointee()); // pour simplifier
|
|
Fonction_nD* fct = gr.Fct(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
|
|
// on cumule l'intégrale
|
|
Vecteur& V = gr.ConteneurVecteur();
|
|
int taille = V.Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
V(i) += tab_ret(i) * poid_jacobien;
|
|
////----- debug
|
|
//cout << "\n debug *** ElemMeca::Grandeur_particuliere( ";
|
|
//cout << "\n li_enu_scal= "<< li_enu_scal << ", val_ddl_enum= " << val_ddl_enum;
|
|
//cout << "\n li_quelc= "<< li_quelc;
|
|
//V.Affiche();cout << " tab_ret= " << tab_ret << endl;;
|
|
////----- fin debug
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
cout << " \n *** pas d'integration prevu pour la grandeur " << tab_integ(il);
|
|
if (ParaGlob::NiveauImpression() > 0)
|
|
cout << "\n ElemMeca::Calcul_Integ_vol_et_temps(..." << endl;
|
|
};
|
|
};
|
|
};
|
|
// 2) intégration de volume et en temps
|
|
//List_io <TypeQuelconque> integ_vol_t_typeQuel,integ_vol_t_typeQuel_t;
|
|
if (integ_vol_t_typeQuel != NULL)
|
|
// on balaie les conteneurs
|
|
{ int taille = integ_vol_t_typeQuel->Taille();
|
|
Tableau <TypeQuelconque> & tab_integ = *integ_vol_t_typeQuel; // pour simplifier
|
|
// recup de l'incrément de temps
|
|
double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant();
|
|
for (int il =1;il <= taille ;il++)
|
|
// l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit
|
|
// d'une valeur figée
|
|
if ((*index_Integ_vol_t_typeQuel)(il))
|
|
{// différent choix
|
|
switch (tab_integ(il).Const_Grandeur_pointee()->Type_enumGrandeurParticuliere())
|
|
{case PARTICULIER_DDL_ETENDU:
|
|
{ Grandeur_Ddl_etendu& gr
|
|
= *((Grandeur_Ddl_etendu*) tab_integ(il).Grandeur_pointee()); // pour simplifier
|
|
Ddl_etendu& ddl = *(gr.ConteneurDdl_etendu());// récup du ddl
|
|
// on va utiliser la méthode Valeur_multi ce qui n'est pas optimal en vitesse
|
|
// mais 1) c'est cohérent avec l'implantation existante
|
|
// 2) identique avec les ddl déjà accessibles
|
|
List_io<Ddl_enum_etendu> inter; // une liste intermédiaire
|
|
inter.push_back(ddl.DdlEnumEtendu());
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// calcul de la valeur et retour dans tab_d
|
|
Tableau <double> tab_d(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,inter,iteg,-cas));
|
|
// on cumule l'intégrale
|
|
ddl.Valeur() += deltat * tab_d(1) * poid_jacobien;
|
|
break;
|
|
}
|
|
case PARTICULIER_VECTEUR_NOMMER:
|
|
{ Grandeur_Vecteur_Nommer& gr
|
|
= *((Grandeur_Vecteur_Nommer*) tab_integ(il).Grandeur_pointee()); // pour simplifier
|
|
Fonction_nD* fct = gr.Fct(); // récupération de la fonction nD
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_tdt,li_enu_scal,iteg,-cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_tdt,li_quelc,iteg,-cas);
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
|
|
// on cumule l'intégrale
|
|
Vecteur& V = gr.ConteneurVecteur();
|
|
int taille = V.Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
V(i) += deltat * tab_ret(i) * poid_jacobien;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
cout << " \n *** pas d'integration prevu pour la grandeur " << tab_integ(il);
|
|
if (ParaGlob::NiveauImpression() > 0)
|
|
cout << "\n ElemMeca::Calcul_Integ_vol_et_temps(..." << endl;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
// au premier pti init éventuel des intégrales de volume et temps
|
|
void ElemMeca::Init_Integ_vol_et_temps()
|
|
{ // 1) intégration de volume uniquement
|
|
if (integ_vol_typeQuel != NULL)
|
|
{int taille = integ_vol_typeQuel->Taille();
|
|
Tableau <TypeQuelconque> & tab_integ = *integ_vol_typeQuel; // pour simplifier
|
|
for (int il =1;il <= taille ;il++)
|
|
// l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit
|
|
// d'une valeur figée
|
|
if ((*index_Integ_vol_typeQuel)(il))
|
|
{tab_integ(il).Grandeur_pointee()->InitParDefaut(); // on initialise le conteneur
|
|
};
|
|
};
|
|
// 2) intégration de volume et en temps
|
|
if (integ_vol_t_typeQuel != NULL)
|
|
{int taille = integ_vol_t_typeQuel->Taille();
|
|
Tableau <TypeQuelconque> & tab_integ = *integ_vol_t_typeQuel; // pour simplifier
|
|
Tableau <TypeQuelconque> & tab_integ_t = *integ_vol_t_typeQuel_t; // ""
|
|
for (int il =1;il <= taille ;il++)
|
|
// l'intégrale n'est effectuée que si l'index est positif, sinon, il s'agit
|
|
// d'une valeur figée
|
|
if ((*index_Integ_vol_t_typeQuel)(il))
|
|
{(*tab_integ(il).Grandeur_pointee()) = (*tab_integ_t(il).Grandeur_pointee());
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
// définition d'un repère d'anisotropie à un point d'intégration
|
|
BaseH ElemMeca::DefRepereAnisotropie
|
|
(int iteg,LesFonctions_nD* lesFonctionsnD,const BlocGen & bloc)
|
|
{ // la définition du repère dépend du type de définition
|
|
// (cf. la def du bloc dans LesMaillages::Completer .... dans LesMaillages.cc)
|
|
if (bloc.Nom(4) == "par_fonction_nD_")
|
|
{// on doit simplement appeler la fonction nD
|
|
// Nom(5) est le nom de la fonction nD
|
|
Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(5));
|
|
// on commence par récupérer les conteneurs des grandeurs à fournir
|
|
List_io <Ddl_enum_etendu>& li_enu_scal = fct->Li_enu_etendu_scalaire();
|
|
List_io <TypeQuelconque >& li_quelc = fct->Li_equi_Quel_evolue();
|
|
bool absolue = true; // on se place systématiquement en absolu
|
|
|
|
const Met_abstraite::Impli* ex_impli = NULL;
|
|
const Met_abstraite::Expli_t_tdt* ex_expli_tdt = NULL;
|
|
const Met_abstraite::Expli* ex_expli = NULL;
|
|
// pour l'instant on ne peut s'occuper que des grandeurs à t au maximum: mais pas
|
|
// à tdt
|
|
bool premier_calcul = true;
|
|
// def->ChangeNumInteg(iteg);
|
|
// const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
|
|
// ex_expli = &ex;
|
|
// // on va utiliser la méhode Valeur_multi_interpoler_ou_calculer
|
|
// // pour les grandeurs strictement scalaire
|
|
// Tableau <double> val_ddl_enum(Valeur_multi_interpoler_ou_calculer
|
|
// (absolue,TEMPS_t,li_enu_scal,*def,ex_impli,ex_expli_tdt,ex_expli)
|
|
// );
|
|
// // on utilise la méthode Valeurs_Tensorielles_interpoler_ou_calculer
|
|
// // pour les Coordonnees et Tenseur
|
|
// Valeurs_Tensorielles_interpoler_ou_calculer
|
|
// (absolue,TEMPS_t,li_quelc,*def,ex_impli,ex_expli_tdt,ex_expli);
|
|
|
|
|
|
// on va utiliser la méhode Valeur_multi pour les grandeurs strictement scalaire
|
|
int cas = 1; // on se met dans un cas normal avec utilisation de certaine partie de la métrique implicite
|
|
// a priori ce serait idem avec l'explicite
|
|
Tableau <double> val_ddl_enum(ElemMeca::Valeur_multi(absolue,TEMPS_t,li_enu_scal,iteg,cas));
|
|
// on utilise la méthode des grandeurs évoluées pour les Coordonnees et Tenseur
|
|
Valeurs_Tensorielles(absolue, TEMPS_t,li_quelc,iteg,cas);
|
|
|
|
// calcul de la valeur et retour dans tab_ret
|
|
Tableau <double> & tab_ret = fct->Valeur_FnD_Evoluee(&val_ddl_enum,&li_enu_scal,&li_quelc,NULL,NULL);
|
|
// on doit récupérer 6 composantes en 3D (pour le reste c'est actuellement en attente)
|
|
int dim = ParaGlob::Dimension();
|
|
if (dim != 3)
|
|
{ cout << "\n arret: le type de construction de repere: par_fonction_nD_ "
|
|
<< " n'est implante que pour la dimension 3 pour l'instant !!! "
|
|
<< " affaire a suivre ....(et se plaindre! ) ";
|
|
Sortie(1);
|
|
};
|
|
int nb_composante = tab_ret.Taille();
|
|
if (nb_composante != 6)
|
|
{ cout << "\n erreur dans la construction d'un repere d'orthotropie par_fonction_nD_ "
|
|
<< " la fonction nD ramene "<<nb_composante << " composante(s) "
|
|
<< " or il en faut 6 uniquement ! ";
|
|
Sortie(1);
|
|
};
|
|
// arrivée ici, cela veut dire que tout est ok
|
|
// --- construction de la base dans I_a -------
|
|
BaseH baseH(3,3);
|
|
// premier vecteur:
|
|
CoordonneeH& c1 = baseH.CoordoH(1);
|
|
for (int i=1;i<4;i++)
|
|
c1(i) = tab_ret(i);
|
|
// on norme si c'est demandé
|
|
if ( bloc.Nom(3) == "orthonorme_")
|
|
{c1.Normer();
|
|
}
|
|
else
|
|
{ cout << "\n arret: le type de repere: "<<bloc.Nom(3)
|
|
<< " n'est pas encore implante !!! affaire a suivre ....(et se plaindre! ) ";
|
|
Sortie(1);
|
|
};
|
|
// le deuxième vecteur:
|
|
CoordonneeH& c2 = baseH.CoordoH(2);
|
|
for (int i=1;i<4;i++)
|
|
c2(i) = tab_ret(i+3);
|
|
// on norme
|
|
c2.Normer();
|
|
// le troisième vecteur
|
|
CoordonneeH& c3 = baseH.CoordoH(3);
|
|
c3 = Util::ProdVec_coorH(c1, c2);
|
|
|
|
/* ***** la suite est supprimée: elle correspond au calcul des coordonnées locales alpha_a^{.i}
|
|
du repère d'anisotropie. Le pb est que le repère local g_i à t= 0 peut changer pendant le calcul
|
|
par exemple dans le cas de l'utilisation des contraintes planes on va avoir un repère de travail
|
|
qui change. Sans doute que ce sera un pb identique avec les Umat
|
|
donc on passe en paramètre le repère en coordonnée absolue et au moment de l'utilisation
|
|
les coordonnées locales seront calculées
|
|
|
|
si c'est ok par la suite, il faudra supprimer la partie commentée qui suit
|
|
|
|
// --- maintenant on s'occupe de calculer la base en local -----
|
|
// en fait il s'agit de définir les coordonnées locales par projection de la base
|
|
// globale en local
|
|
def->ChangeNumInteg(iteg);
|
|
const Met_abstraite::InfoExp_t & ex_infoExp_t = def->RemontExp_t();
|
|
int nb_vec = ex_infoExp_t.giB_0->NbVecteur(); // nb vecteur local
|
|
BaseH base_ret_H(3,3);
|
|
// les coordonnées locales : théta^te = V * g^te
|
|
// soit O_a la base d'anisotropie: O_a = beta_a^{.i} g_i
|
|
// ona beta_a^{.i} = O_a . g^i
|
|
// et on stocke dans base_ret_H de la manière suivante
|
|
// base_ret_H(a)(i) = beta_a^{.i}
|
|
for (int a = 1;a <= 3; a++)
|
|
{CoordonneeH& inter = base_ret_H.CoordoH(a);
|
|
for (int i=1;i<nb_vec;i++)
|
|
inter(i)= baseB.CoordoB(a) * (*ex_infoExp_t.giH_0)(i);
|
|
};
|
|
// dans le cas où nb_vec n'est pas égale à 3 il faut complèter la base
|
|
switch (nb_vec)
|
|
{ case 3: break; // cas où c'est déjà ok
|
|
case 2: // cas où l'élément est une surface, le troisième vecteur est la normale
|
|
{CoordonneeH N_H = Util::ProdVec_coorH((*ex_infoExp_t.giH_0)(1),(*ex_infoExp_t.giH_0)(2));
|
|
for (int a = 1;a <= 3; a++)
|
|
base_ret_H.CoordoH(a)(3)= baseB.CoordoB(a) * N_H;
|
|
break;
|
|
}
|
|
case 1: // cas où l'élément est un segment, il faut définir deux autres vecteurs
|
|
{// on génère
|
|
la suite est problèmatique car lorsque l'on changera de repère local, les coordonnées locales
|
|
devraient changer donc on arrête
|
|
|
|
CoordonneeH N_H = Util::ProdVec_coorH((*ex_infoExp_t.giH_0)(1),(*ex_infoExp_t.giH_0)(2));
|
|
for (int a = 1;a <= 3; a++)
|
|
base_ret_H.CoordoH(a)(3)= baseB.CoordoB(a) * N_H;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
|
|
|
|
for (int i=1;i<4;i++)
|
|
{CoordonneeH& inter = base_ret_H.CoordoH(i);
|
|
for (int te = 1;te <= nb_vec; te++)
|
|
inter(te)= baseB.CoordoB(i) * (*ex_infoExp_t.giH_0)(te);
|
|
};
|
|
return base_ret_H;
|
|
*/
|
|
//cout << "\n debug ElemMeca::DefRepereAnisotropie ";
|
|
//for (int a = 1;a < 4; a++)
|
|
// {cout << "\n baseH("<<a<<"): ";
|
|
// baseH(a).Affiche();
|
|
// };
|
|
|
|
|
|
return baseH;
|
|
}
|
|
else if (bloc.Nom(4) == "Par_projection_et_normale_au_plan_")
|
|
{ cout << "\n arret: le type de construction de repere: "<<bloc.Nom(3)
|
|
<< " n'est pas encore implante !!! affaire a suivre ....(et se plaindre! ) ";
|
|
Sortie(1);
|
|
}
|
|
else
|
|
{ cout << "\n **** erreur: type de construction de repere: "<<bloc.Nom(3)
|
|
<< " inconnu ?? ";
|
|
Sortie(1);
|
|
|
|
};
|
|
return BaseH(); // pour faire taire le compilo
|
|
};
|
|
|
|
|
|
// calcul éventuel de la normale à un noeud
|
|
// ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D
|
|
// qui possède un repère d'orientation
|
|
// en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace
|
|
// si le calcul n'existe pas --> coor.Dimension() = 0
|
|
// ramène un entier :
|
|
// == 1 : calcul normal
|
|
// == 0 : problème de calcul -> coor.Dimension() = 0
|
|
// == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre
|
|
// c'est le cas par exemple des noeuds exterieurs pour les éléments SFE
|
|
// mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour
|
|
// calculer la normale à ce noeud là
|
|
// temps: indique à quel moment on veut le calcul
|
|
// pour des éléments particulier (ex: SFE) la méthode est surchargée
|
|
int ElemMeca::CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor)
|
|
{
|
|
int retour = 1; // init du retour : on part d'un bon a priori
|
|
Enum_type_geom enutygeom = Type_geom_generique(this->Id_geometrie());
|
|
// if ((enutygeom == LIGNE) || (enutygeom == SURFACE))
|
|
if (enutygeom != SURFACE) // dans une première étape on ne s'occupe que des surfaces
|
|
{coor.Libere(); // pas de calcul possible
|
|
retour = 0;
|
|
}
|
|
else // sinon le calcul est possible
|
|
{ // on commence par repérer le noeud dans la numérotation locale
|
|
int nuoe=0;
|
|
int borne_nb_noeud=tab_noeud.Taille()+1;
|
|
for (int i=1;i< borne_nb_noeud;i++)
|
|
{Noeud& noeloc = *tab_noeud(i);
|
|
if ( (noe.Num_noeud() == noeloc.Num_noeud())
|
|
&& (noe.Num_Mail() == noeloc.Num_Mail())
|
|
)
|
|
{nuoe = i; break;
|
|
};
|
|
};
|
|
// on ne continue que si on a trouvé le noeud
|
|
if (nuoe != 0)
|
|
{ ElemGeomC0& elemgeom = ElementGeometrique(); // récup de la géométrie
|
|
// récup des coordonnées locales du noeuds
|
|
const Coordonnee& theta_noeud = elemgeom.PtelemRef()(nuoe);
|
|
// récup des phi et dphi au noeud
|
|
const Vecteur & phi = elemgeom.Phi_point(theta_noeud);
|
|
const Mat_pleine& dphi = elemgeom.Dphi_point(theta_noeud);
|
|
switch (temps)
|
|
{case TEMPS_0 :
|
|
{const BaseB& baseB = met->BaseNat_0(tab_noeud,dphi,phi);
|
|
coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2));
|
|
coor.Normer();
|
|
break;
|
|
}
|
|
case TEMPS_t :
|
|
{const BaseB& baseB = met->BaseNat_t(tab_noeud,dphi,phi);
|
|
coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2));
|
|
coor.Normer();
|
|
break;
|
|
}
|
|
case TEMPS_tdt :
|
|
{const BaseB& baseB = met->BaseNat_tdt(tab_noeud,dphi,phi);
|
|
coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2));
|
|
coor.Normer();
|
|
break;
|
|
}
|
|
default :
|
|
cout << "\nErreur : valeur incorrecte du temps demande = "
|
|
<< Nom_dure(temps) << " !\n";
|
|
cout << "\n ElemMeca::CalculNormale_noeud(Enum_dure temps... \n";
|
|
retour = 0;
|
|
Sortie(1);
|
|
};
|
|
}
|
|
else
|
|
{cout << "\n *** erreur le noeud demande num= "<<noe.Num_noeud()
|
|
<< " du maillage "<< noe.Num_Mail()
|
|
<< " ne fait pas parti de l'element "
|
|
<< num_elt << " du maillage "<< noe.Num_Mail()
|
|
<< " on ne peut pas calculer la normale au noeud !!"
|
|
<< "\n ElemMeca::CalculNormale_noeud(...";
|
|
retour = 0;
|
|
Sortie(1);
|
|
}
|
|
};
|
|
// retour
|
|
return retour;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|