847 lines
38 KiB
C++
Executable file
847 lines
38 KiB
C++
Executable file
// 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 "ElemThermi.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"
|
|
|
|
|
|
// -------------------- 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 ElemThermi::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 ElemThermi::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) = (ElemThermi*) 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 ElemThermi::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) = (ElemThermi*) 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 ElemThermi::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) = (ElemThermi*) 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 ElemThermi::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);
|
|
break;
|
|
}
|
|
|
|
default :
|
|
cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n";
|
|
cout << "\n ElemThermi::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
// stabilisation pour un calcul implicit
|
|
void ElemThermi::Cal_implicit_hourglass()
|
|
{ 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));
|
|
|
|
//---- 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))
|
|
{// 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
|
|
(*(resraid1.raid)) -= (*(resraid2.raid));
|
|
(*(resraid1.res)) -= (*(resraid2.res));
|
|
// on tiend compte du facteur de modération
|
|
(*(resraid1.raid)) *= coefStabHourglass;
|
|
(*(resraid1.res)) *= coefStabHourglass;
|
|
// on sauvegarde la raideur
|
|
raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid)));
|
|
// 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
|
|
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));
|
|
// on tiend compte du facteur de modération
|
|
(*(resHourglass1)) *= coefStabHourglass;
|
|
// on met à jour le résidu de l'élément principal
|
|
(*residu) += (*(resHourglass1));
|
|
// pour la partie raideur: on met à jour la raideur de l'élément principal
|
|
(*raideur) += (*raid_hourglass_transitoire);
|
|
};
|
|
|
|
//---- 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 ElemThermi::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
|
|
};
|
|
|
|
// stabilisation pour un calcul explicit
|
|
void ElemThermi::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_NON_DEFINIE :
|
|
// on ne fait rien
|
|
break;
|
|
default :
|
|
cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n";
|
|
cout << "\n ElemThermi::Cal_implicit_hourglass() \n";
|
|
Sortie(1);
|
|
};
|
|
|
|
};
|
|
|
|
|
|
// récupération de l'energie d'hourglass éventuelle
|
|
double ElemThermi::Energie_Hourglass()
|
|
{ double enerHourglass = 0.;
|
|
switch (type_stabHourglass)
|
|
{case STABHOURGLASS_PAR_COMPORTEMENT :
|
|
{ // on récupère les énergies stockées à l'élément
|
|
const EnergieThermi& energieTotale = tab_elHourglass(1)->EnergieTotaleElement();
|
|
enerHourglass = coefStabHourglass * (energieTotale.EnergieElastique()
|
|
+ energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse());
|
|
};
|
|
break;
|
|
};
|
|
return enerHourglass;
|
|
};
|
|
|
|
// 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 ElemThermi::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 ElemThermi::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 & ElemThermi::Frontiere_elethermi(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;
|
|
};
|
|
|
|
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 ElemThermi::Frontiere_points(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_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 ElemThermi::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 = posi_tab_front_point = 0;}
|
|
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 = posi_tab_front_point = tail_fa; // après les surfaces
|
|
};
|
|
};
|
|
// 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 ElemThermi::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 = el.NbFe(); // nombre potentiel de faces
|
|
if (num > tail_fa)
|
|
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 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 = posi_tab_front_point = tail_fa; // après les surfaces
|
|
};
|
|
};
|
|
// --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 é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 ElemThermi::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 ElemThermi::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 ElemThermi::CalculNormale_noeud(...";
|
|
retour = 0;
|
|
Sortie(1);
|
|
}
|
|
};
|
|
// retour
|
|
return retour;
|
|
};
|
|
|