diff --git a/Elements/Thermique/Biellette/BielletteThermi.cc b/Elements/Thermique/Biellette/BielletteThermi.cc
new file mode 100755
index 0000000..031fea9
--- /dev/null
+++ b/Elements/Thermique/Biellette/BielletteThermi.cc
@@ -0,0 +1,1672 @@
+// FICHIER : BielletteThermi.cc
+// CLASSE : BielletteThermi
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+//#include "Debug.h"
+
+
+# include
+using namespace std; //introduces namespace std
+#include
+#include "Sortie.h"
+
+
+#include "BielletteThermi.h"
+#include "FrontPointF.h"
+#include "FrontSegLine.h"
+#include "TypeConsTens.h"
+#include "TypeQuelconqueParticulier.h"
+
+//----------------------------------------------------------------
+// def des donnees commune a tous les elements
+// la taille n'est pas defini ici car elle depend de la lecture
+//----------------------------------------------------------------
+BielletteThermi::DonneeCommune * BielletteThermi::doCo = NULL;
+BielletteThermi::UneFois BielletteThermi::unefois;
+BielletteThermi::NombresConstruire BielletteThermi::nombre_V;
+BielletteThermi::ConstrucElementbiel BielletteThermi::construcElementbiel;
+
+// constructeur définissant les nombres (de noeud, de point d'integ ..)
+// utilisé dans la construction des éléments
+BielletteThermi::NombresConstruire::NombresConstruire()
+ { nbne = 2; // le nombre de noeud de l'élément
+ nbneA = 2;// le nombre de noeud des aretes
+ nbi = 1; // le nombre de point d'intégration pour le calcul mécanique
+ nbiEr = 2;// le nombre de point d'intégration pour le calcul d'erreur
+ nbiA = 1; // le nombre de point d'intégration pour le calcul de second membre linéique
+ nbiMas = 2; // le nombre de point d'intégration pour le calcul de la matrice masse
+ };
+
+// ---- definition du constructeur de la classe conteneur de donnees communes ------------
+BielletteThermi::DonneeCommune::DonneeCommune (GeomSeg& seg,DdlElement& tab,DdlElement& tabErr,DdlElement& tab_Err1flux,
+ Met_biellette& met_bie,
+ Tableau & resEr,Mat_pleine& raidEr,
+ GeomSeg& seEr,Vecteur& residu_int,Mat_pleine& raideur_int,
+ Tableau & residus_extN,Tableau & raideurs_extN,
+ Tableau & residus_extA,Tableau & raideurs_extA,
+ Mat_pleine& mat_masse,GeomSeg& seMa,int nbi) :
+ segment(seg),tab_ddl(tab),tab_ddlErr(tabErr),tab_Err1FLUX(tab_Err1flux)
+ ,met_biellette(met_bie)
+ ,matGeom(tab.NbDdl(),tab.NbDdl())
+ ,matInit(tab.NbDdl(),tab.NbDdl())
+ ,d_gradTB(),d_fluxH(),d2_gradTB(nbi)
+ ,resErr(resEr),raidErr(raidEr)
+ ,segmentEr(seEr)
+ ,residu_interne(residu_int),raideur_interne(raideur_int)
+ ,residus_externeN(residus_extN),raideurs_externeN(raideurs_extN)
+ ,residus_externeA(residus_extA),raideurs_externeA(raideurs_extA)
+ ,matrice_masse(mat_masse)
+ ,segmentMas(seMa)
+ {
+// Tableau d_gradTB; // place pour la variation du gradient
+// Tableau d_fluxH; // place pour la variation du flux
+// Tableau < Tableau2 * > d2_gradTB; // variation seconde des déformations
+ int nbddl = tab.NbDdl();
+ CoordonneeB interB(1); // intermédiaire
+
+ for (int ni=1;ni<=nbi;ni++)
+ {d2_gradTB(ni) = new Tableau2 ;
+ d2_gradTB(ni)->Change_taille(nbddl);
+ };
+ d_gradTB.Change_taille(nbddl,interB);
+ CoordonneeH interH(1); // intermédiaire
+ d_fluxH.Change_taille(nbddl,interH);
+ };
+
+BielletteThermi::DonneeCommune::DonneeCommune(DonneeCommune& a) :
+ segment(a.segment),tab_ddl(a.tab_ddl),tab_ddlErr(a.tab_ddlErr),tab_Err1FLUX(a.tab_Err1FLUX)
+ ,met_biellette(a.met_biellette),matGeom(a.matGeom),matInit(a.matInit)
+ ,d2_gradTB(a.d2_gradTB),resErr(a.resErr),raidErr(a.raidErr),segmentEr(a.segmentEr)
+ ,d_gradTB(a.d_gradTB),d_fluxH(a.d_fluxH)
+ ,residu_interne(a.residu_interne),raideur_interne(a.raideur_interne)
+ ,residus_externeN(a.residus_externeN),raideurs_externeN(a.raideurs_externeN)
+ ,residus_externeA(a.residus_externeA),raideurs_externeA(a.raideurs_externeA)
+ ,matrice_masse(a.matrice_masse),segmentMas(a.segmentMas)
+ {};
+BielletteThermi::DonneeCommune::~DonneeCommune()
+ { int nbddl = tab_ddl.NbDdl();
+ int nbi = d2_gradTB.Taille();
+ for (int ni=1;ni<=nbi;ni++)
+ { if (d2_gradTB(ni)!= NULL)
+ delete d2_gradTB(ni);
+ };
+
+ };
+
+// ---------- fin definition de la classe conteneur de donnees communes ------------
+// -+-+ definition de la classe contenant tous les indicateurs qui sont modifiés une seule fois -+-+-+
+BielletteThermi::UneFois::UneFois () : // constructeur par défaut
+ doCoMemb(NULL),CalResPrem_t(0),CalResPrem_tdt(0),CalimpPrem(0),dualSortbiel(0)
+ ,CalSMlin_t(0),CalSMlin_tdt(0),CalSMRlin(0)
+ ,CalSMvol_t(0),CalSMvol_tdt(0),CalSMvol(0)
+ ,CalDynamique(0),CalPt_0_t_tdt(0)
+ ,nbelem_in_Prog(0)
+ {};
+BielletteThermi::UneFois::~UneFois ()
+ { delete doCoMemb;
+ };
+
+// -+-+ fin definition de la classe contenant tous les indicateurs qui sont modifiés une seule fois -+-+-+
+
+
+// ---------- fin definition de la classe conteneur de donnees communes ------------
+
+BielletteThermi::BielletteThermi () :
+// Constructeur par defaut
+ElemThermi(),lesPtThermiInt(),donnee_specif()
+
+{// on intervient seulement à partir du deuxième élément,
+ if (unefois.nbelem_in_Prog == 0)
+ { unefois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter
+ }
+ else // sinon on construit
+ { lesPtIntegThermiInterne = &lesPtThermiInt; // association avec le pointeur d'ElemThermi
+ id_interpol=BIE1; // donnees de la classe mere
+ id_geom=POUT; //
+ tab_noeud.Change_taille(nombre_V.nbne);
+ // initialisation par défaut
+ doCo = BielletteThermi::Init ();
+ unefois.nbelem_in_Prog++;
+ };
+};
+
+BielletteThermi::BielletteThermi (double sect,int num_maill,int num_id):
+// Constructeur utile si la section de l'element et
+// le numero de l'element sont connus
+ElemThermi(num_maill,num_id,BIE1,POUT),lesPtThermiInt(),donnee_specif(sect)
+{// on intervient seulement à partir du deuxième élément,
+ if (unefois.nbelem_in_Prog == 0)
+ { unefois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter
+ }
+ else // sinon on construit
+ { lesPtIntegThermiInterne = &lesPtThermiInt; // association avec le pointeur d'ElemThermi
+ tab_noeud.Change_taille(nombre_V.nbne);
+ // initialisation
+ doCo = BielletteThermi::Init (donnee_specif);
+ unefois.nbelem_in_Prog++;
+ };
+};
+
+// Constructeur fonction d'un numero de maillage et d'identification
+BielletteThermi::BielletteThermi (int num_maill,int num_id) :
+ ElemThermi(num_maill,num_id,BIE1,POUT),lesPtThermiInt(),donnee_specif()
+{// on intervient seulement à partir du deuxième élément,
+ if (unefois.nbelem_in_Prog == 0)
+ { unefois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter
+ }
+ else // sinon on construit
+ { lesPtIntegThermiInterne = &lesPtThermiInt; // association avec le pointeur d'ElemThermi
+ tab_noeud.Change_taille(nombre_V.nbne);
+ // initialisation par défaut
+ doCo = BielletteThermi::Init ();
+ unefois.nbelem_in_Prog++;
+ };
+};
+
+BielletteThermi::BielletteThermi (double sect,int num_maill,int num_id,const Tableau& tab):
+// Constructeur utile si la section de l'element, le numero de l'element et
+// le tableau des noeuds sont connus
+ElemThermi(num_maill,num_id,tab,BIE1,POUT),lesPtThermiInt(),donnee_specif(sect)
+{// on intervient seulement à partir du deuxième élément,
+ if (unefois.nbelem_in_Prog == 0)
+ { unefois.nbelem_in_Prog++; // au premier passage on se contente d'incrémenter
+ }
+ else // sinon on construit
+ { lesPtIntegThermiInterne = &lesPtThermiInt; // association avec le pointeur d'ElemThermi
+ if (tab_noeud.Taille() != 2)
+ { cout << "\n erreur de dimensionnement du tableau de noeud \n";
+ cout << " BielletteThermi::BielletteThermi (double sect,int num_id,const Tableau& tab)\n";
+ Sortie (1); }
+ // construction du tableau de ddl spécifique à l'élément pour ses
+ ConstTabDdl();
+ // initialisation
+ bool sans_init_noeud = true;
+ doCo = BielletteThermi::Init (donnee_specif,sans_init_noeud);
+ unefois.nbelem_in_Prog++;
+ };
+};
+
+BielletteThermi::BielletteThermi (const BielletteThermi& biel) :
+ ElemThermi (biel),lesPtThermiInt(biel.lesPtThermiInt),donnee_specif(biel.donnee_specif)
+// Constructeur de copie
+{ if (unefois.nbelem_in_Prog == 1)
+ { cout << "\n **** erreur pour l'element BielletteThermi, le constructeur de copie ne doit pas etre utilise"
+ << " pour le premier element !! " << endl;
+ Sortie (1);
+ }
+ else
+ { lesPtIntegThermiInterne = &lesPtThermiInt; // association avec le pointeur d'ElemThermi
+ // initialisation
+ unefois.nbelem_in_Prog++;
+ };
+};
+
+BielletteThermi::~BielletteThermi ()
+// Destructeur
+ { LibereTenseur();
+ if (unefois.nbelem_in_Prog != 0)
+ unefois.nbelem_in_Prog--;
+ // defArete pointe sur la même grandeur que def donc pour éviter
+ // une destruction lors du destructeur générale dans elemméca on le met à null
+ if (defArete.Taille() != 0)
+ defArete(1) = NULL;
+ Destruction();
+ };
+
+// Lecture des donnees de la classe sur fichier
+void
+BielletteThermi::LectureDonneesParticulieres
+ (UtilLecture * entreePrinc,Tableau * tabMaillageNoeud)
+ { int nb;
+ tab_noeud.Change_taille(2);
+ for (int i=1; i<= 2; i++)
+ { *(entreePrinc->entree) >> nb;
+ if ((entreePrinc->entree)->rdstate() == 0)
+ // pour mémoire ici on a
+ /* enum io_state
+ { badbit = 1<<0, // -> 1 dans rdstate()
+ eofbit = 1<<1, // -> 2
+ failbit = 1<<2, // -> 4
+ goodbit = 0 // -> O
+ };*/
+ tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale
+ #ifdef ENLINUX
+ else if ((entreePrinc->entree)->fail())
+ // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
+ { entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement
+ *(entreePrinc->entree) >> nb;
+ tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale
+ }
+ #else
+ /* #ifdef SYSTEM_MAC_OS_X_unix
+ else if ((entreePrinc->entree)->fail())
+ // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
+ { entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement
+ *(entreePrinc->entree) >> nb;
+ tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture normale
+ }
+ #else*/
+ else if ((entreePrinc->entree)->eof())
+ // la lecture est bonne mais on a atteind la fin de la ligne
+ { tab_noeud(i) = (*tabMaillageNoeud)(nb); // lecture
+ // si ce n'est pas la fin de la lecture on appelle un nouvel enregistrement
+ if (i != 2) entreePrinc->NouvelleDonnee(); // lecture d'un nouvelle enregistrement
+ }
+ // #endif
+ #endif
+ else // cas d'une erreur de lecture
+ { cout << "\n erreur de lecture inconnue ";
+ entreePrinc->MessageBuffer("** lecture des données particulières **");
+ cout << "BielletteThermi::LectureDonneesParticulieres";
+ Affiche();
+ Sortie (1);
+ }
+ }
+ // construction du tableau de ddl des noeuds de biellette
+ ConstTabDdl();
+ };
+
+// calcul d'un point dans l'élément réel en fonction des coordonnées dans l'élément de référence associé
+// temps: indique si l'on veut les coordonnées à t = 0, ou t ou tdt
+// 1) cas où l'on utilise la place passée en argument
+Coordonnee & BielletteThermi::Point_physique(const Coordonnee& c_int,Coordonnee & co,Enum_dure temps)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // a) on commence par définir les bonnes grandeurs dans la métrique
+ if( !(unefois.CalPt_0_t_tdt ))
+ { unefois.CalPt_0_t_tdt += 1;
+ Tableau tab(3);
+ tab(1)=iM0;tab(2)=iMt;tab(3)=iMtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // b) calcul de l'interpolation
+ const Vecteur& phi = doCo->segment.Phi(c_int);
+ // c) calcul du point
+ switch (temps)
+ { case TEMPS_0 : co = doCo->met_biellette.PointM_0(tab_noeud,phi); break;
+ case TEMPS_t : co = doCo->met_biellette.PointM_t(tab_noeud,phi); break;
+ case TEMPS_tdt : co = doCo->met_biellette.PointM_tdt(tab_noeud,phi); break;
+ }
+ // d) retour
+ return co;
+ };
+
+// 3) cas où l'on veut les coordonnées aux 1, 2 ou trois temps selon la taille du tableau t_co
+void BielletteThermi::Point_physique(const Coordonnee& c_int,Tableau & t_co)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // a) on commence par définir les bonnes grandeurs dans la métrique
+ if( !(unefois.CalPt_0_t_tdt ))
+ { unefois.CalPt_0_t_tdt += 1;
+ Tableau tab(3);
+ tab(1)=iM0;tab(2)=iMt;tab(3)=iMtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // b) calcul de l'interpolation
+ const Vecteur& phi = doCo->segment.Phi(c_int);
+ // c) calcul des point
+ switch (t_co.Taille())
+ { case 3 : t_co(3) = doCo->met_biellette.PointM_tdt(tab_noeud,phi);
+ case 2 : t_co(2) = doCo->met_biellette.PointM_t(tab_noeud,phi);
+ case 1 : t_co(1) = doCo->met_biellette.PointM_0(tab_noeud,phi);
+ }
+ };
+
+// Calcul du residu local à t ou tdt en fonction du booleen atdt
+ Vecteur* BielletteThermi::CalculResidu (bool atdt,const ParaAlgoControle & pa)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ Tableau & d_gradTB = (doCo->d_gradTB);// "
+ // dimensionnement de la metrique
+ if (!atdt)
+ {if( !(unefois.CalResPrem_t ))
+ { unefois.CalResPrem_t += 1;
+ Tableau tab(10);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };}
+ else
+ {if( !(unefois.CalResPrem_tdt ))
+ {unefois.CalResPrem_tdt += 1;
+ Tableau tab(11);
+ tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0;tab(4) = igijBB_tdt;
+ tab(5) = igijHH_tdt; tab(6) = id_giB_tdt; tab(7) = id_gijBB_tdt ;
+ tab(8) = id_gijBB_t ;tab(9) = id_gijBB_tdt ;
+ tab(10) = igradVBB_tdt;tab(11) = iVtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };};
+ // initialisation du résidu
+ residu->Zero();
+ Vecteur poids =(doCo->segment).TaWi(); // poids d'interpolation = 2
+ ElemThermi::Cal_explicit ( doCo->tab_ddl,d_gradTB,1,poids,pa,atdt);
+ // prise en compte de la section
+ double section_moyenne = 0.;
+ section_moyenne = CalSectionMoyenne_et_vol_pti(atdt);
+ (*residu) *= section_moyenne;
+ energie_totale *= section_moyenne;
+ E_Hourglass *= section_moyenne; // meme si l'énergie d'hourglass est nulle
+ E_elem_bulk_tdt*= section_moyenne; // idem
+ P_elem_bulk *= section_moyenne; // idem
+ volume *= section_moyenne;
+
+ return residu;
+ };
+
+// Calcul du residu local et de la raideur locale,
+// pour le schema implicite
+Element::ResRaid BielletteThermi::Calcul_implicit (const ParaAlgoControle & pa)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ Tableau & d_gradTB = (doCo->d_gradTB);// "
+ Tableau & d_fluxH = (doCo->d_fluxH);// "
+ bool cald_Dvirtuelle = true; //false; non pour l'instant toujours vrai car en fait pas de calcul
+ if (unefois.CalimpPrem == 0)
+ { unefois.CalimpPrem = 1;
+
+ Tableau tab(20);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ;
+ tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ // on ne calcul la dérivée de la déformation virtuelle qu'une fois
+ // car elle est constante dans le temps et indépendante des coordonnées
+// non pour l'instant toujours vrai car en fait pas de calcul cald_Dvirtuelle=true;
+ };
+// // par défaut on initialise les coordonnées à t et tdt aux mêmes valeurs
+// // qu'à 0, ceci pour calculer ensuite les métiques
+// const Coordonnee& co1 = tab_noeud(1)->Coord0();
+// tab_noeud(1)->Change_coord1(co1);
+// tab_noeud(1)->Change_coord2(co1);
+// const Coordonnee& co2 = tab_noeud(2)->Coord0();
+// tab_noeud(2)->Change_coord1(co2);
+// tab_noeud(2)->Change_coord2(co2);
+
+ // initialisation du résidu
+ residu->Zero();
+ // initialisation de la raideur
+ raideur->Zero();
+
+ Vecteur poids =(doCo->segment).TaWi(); // poids d'intégration = 2
+// void Cal_implicit (DdlElement & tab_ddl,Tableau & d_gradTB
+// ,Tableau < Tableau2 * > d2_gradTB,Tableau & d_fluxH,int nbint
+// ,const Vecteur& poids,const ParaAlgoControle & pa,bool cald_DGradTvirtuelle);
+ ElemThermi::Cal_implicit(doCo->tab_ddl, d_gradTB,(doCo->d2_gradTB),d_fluxH,nombre_V.nbi
+ ,poids,pa,cald_Dvirtuelle);
+// ElemThermi::Cal_implicit (DdlElement & tab_ddl
+// ,Tableau & d_gradTB,Tableau < Tableau2 * > d2_gradTB_
+// ,Tableau & d_fluxH,int nbint
+// ,const Vecteur& poids,const ParaAlgoControle & pa,bool cald_DGradTvirtuelle)
+ // prise en compte de la section
+ double section_moyenne = 0.;
+ const bool atdt=true;
+ section_moyenne = CalSectionMoyenne_et_vol_pti(atdt);
+
+ (*residu) *= section_moyenne;
+ (*raideur) *= section_moyenne;
+ energie_totale *= section_moyenne;
+ E_Hourglass *= section_moyenne; // meme si l'énergie d'hourglass est nulle
+ E_elem_bulk_tdt*= section_moyenne; // idem
+ P_elem_bulk *= section_moyenne; // idem
+ volume *= section_moyenne;
+ Element::ResRaid el;
+ el.res = residu;
+ el.raid = raideur;
+ return el;
+ };
+
+// Calcul de la matrice masse pour l'élément
+Mat_pleine * BielletteThermi::CalculMatriceMasse (Enum_calcul_masse type_calcul_masse)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionement de la métrique si nécessaire
+ if (!(unefois.CalDynamique ))
+ { unefois.CalDynamique += 1;
+ Tableau tab(5);
+ tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0;
+ tab(4) = igijBB_tdt;tab(5) = igradVmoyBB_t;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ // on vérifie le bon dimensionnement de la matrice
+ if (type_calcul_masse == MASSE_CONSISTANTE)
+ // dans le cas où la masse est consistante il faut la redimensionner
+ { int nbddl = doCo->tab_ddl.NbDdl();
+ (doCo->matrice_masse).Initialise (nbddl,nbddl,0.);
+ }
+ };
+ Vecteur poids =(doCo->segmentMas).TaWi(); // poids d'intégration = 2
+ // appel de la routine générale
+ ElemThermi::Cal_Mat_masse (doCo->tab_ddl,type_calcul_masse,
+ nombre_V.nbiMas,(doCo->segmentMas).TaPhi(),nombre_V.nbne
+ ,poids);
+ (*mat_masse) *= donnee_specif.secti.section0; // prise en compte de l'épaisseur
+ return mat_masse;
+ };
+
+//------- calcul d'erreur, remontée des contraintes -------------------
+ // 1) calcul du résidu et de la matrice de raideur pour le calcul d'erreur
+ Element::Er_ResRaid BielletteThermi::ContrainteAuNoeud_ResRaid()
+ {
+ if(!( unefois.CalResPrem_t ))
+ { unefois.CalResPrem_t += 1;
+ Tableau tab(10);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // appel du programme général
+ int tabn_taille = tab_noeud.Taille();
+ ElemThermi:: FluxAuNoeud_ResRaid(tab_noeud.Taille()
+ ,(doCo->segment).TaPhi()
+ ,(doCo->segment).TaWi()
+ ,doCo-> resErr,doCo->raidErr
+ ,(doCo->segmentEr).TaPhi()
+ ,(doCo->segmentEr).TaWi());
+ // on tient compte de la section à t, supposée déjà calculée ou récupérée
+ for (int i=1;i<= tabn_taille;i++)
+ (*doCo-> resErr(i)) *= donnee_specif.secti.section_t;
+ doCo->raidErr *= donnee_specif.secti.section_t;
+ return (Element::Er_ResRaid( &(doCo-> resErr),&(doCo->raidErr)));
+ };
+
+ // 2) remontée aux erreurs aux noeuds
+ Element::Er_ResRaid BielletteThermi::ErreurAuNoeud_ResRaid()
+ { if(!( unefois.CalResPrem_t ))
+ { unefois.CalResPrem_t += 1;
+ Tableau tab(10);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // appel du programme général
+ int tabn_taille = tab_noeud.Taille();
+ ElemThermi::Cal_ErrAuxNoeuds(tab_noeud.Taille(), (doCo->segment).TaPhi(),
+ (doCo->segment).TaWi(),doCo-> resErr );
+ // on tient compte de la section à t, supposée déjà calculée ou récupérée
+ for (int i=1;i<= tabn_taille;i++)
+ (*doCo-> resErr(i)) *= donnee_specif.secti.section_t;
+ doCo->raidErr *= donnee_specif.secti.section_t;
+ return (Element::Er_ResRaid( &(doCo-> resErr),&(doCo->raidErr)));
+ };
+
+// actualisation des ddl et des grandeurs actives de t+dt vers t
+void BielletteThermi::TdtversT()
+ { lesPtThermiInt.TdtversT(); // contrainte
+ if (tabSaveDon(1) != NULL) tabSaveDon(1)->TdtversT();
+ if (tabSaveTP(1) != NULL) tabSaveTP(1)->TdtversT();
+ if (tabSaveDefDon(1) != NULL) tabSaveDefDon(1)->TdtversT();
+ donnee_specif.secti.section_t = donnee_specif.secti.section_tdt;
+ ElemThermi::TdtversT_(); // appel de la procédure mère
+ };
+// actualisation des ddl et des grandeurs actives de t vers tdt
+void BielletteThermi::TversTdt()
+ { lesPtThermiInt.TversTdt(); // contrainte
+ if (tabSaveDon(1) != NULL) tabSaveDon(1)->TversTdt();
+ if (tabSaveTP(1) != NULL) tabSaveTP(1)->TversTdt();
+ if (tabSaveDefDon(1) != NULL)tabSaveDefDon(1)->TversTdt();
+ donnee_specif.secti.section_tdt = donnee_specif.secti.section_t;
+ ElemThermi::TversTdt_(); // appel de la procédure mère
+ };
+
+// calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+// qu'une fois la remontée aux contraintes effectuées sinon aucune
+// action. En retour la valeur de l'erreur sur l'élément
+// type indique le type de calcul d'erreur :
+void BielletteThermi::ErreurElement(int type,double& errElemRelative
+ ,double& numerateur, double& denominateur)
+ { if(!( unefois.CalResPrem_t ))
+ { unefois.CalResPrem_t += 1;
+ Tableau tab(10);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // appel du programme général
+ ElemThermi::Cal_ErrElem(type,errElemRelative,numerateur,denominateur,
+ tab_noeud.Taille(),(doCo->segment).TaPhi(),
+ (doCo->segment).TaWi(),
+ (doCo->segmentEr).TaPhi(),(doCo->segmentEr).TaWi());
+ };
+// mise à jour de la boite d'encombrement de l'élément, suivant les axes I_a globales
+// en retour coordonnées du point mini dans retour.Premier() et du point maxi dans .Second()
+// la méthode est différente de la méthode générale car il faut prendre en compte la section de l'élément
+const DeuxCoordonnees& BielletteThermi::Boite_encombre_element(Enum_dure temps)
+ { // on commence par calculer la boite d'encombrement pour l'élément médian
+ Element::Boite_encombre_element( temps);
+ // ensuite on augmente sytématiquement dans toutes directions d'une valeur sqrt(s)/2 majorée
+ double sSur2maj = sqrt(donnee_specif.secti.section_tdt) * 0.5
+ * ParaGlob::param->ParaAlgoControleActifs().Extra_boite_prelocalisation();
+ // ajout d'un extra dans toutes les directions
+ sSur2maj += ParaGlob::param->ParaAlgoControleActifs().Ajout_extra_boite_prelocalisation();
+ // mise à jour
+ boite_encombre.Premier().Ajout_meme_valeur(-sSur2maj); // le min
+ boite_encombre.Second().Ajout_meme_valeur(sSur2maj); // le max
+ // retour
+ return boite_encombre;
+ };
+
+//============= lecture écriture dans base info ==========
+
+// cas donne le niveau de la récupération
+// = 1 : on récupère tout
+// = 2 : on récupère uniquement les données variables (supposées comme telles)
+void BielletteThermi::Lecture_base_info
+ (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas)
+{// tout d'abord appel de la lecture de la classe ElemThermi
+ ElemThermi::Lecture_bas_inf(ent,tabMaillageNoeud,cas);
+ // traitement du cas particulier de la biellette
+ switch (cas)
+ { case 1 : // ------- on récupère tout -------------------------
+ { // construction du tableau de ddl des noeuds du triangle
+ ConstTabDdl();
+ // récup contraintes et déformation
+ // les données spécifiques
+ string nom;
+ ent >> nom;
+ if (nom == "epaisStockeDansElement")
+ ent >> nom >> donnee_specif.secti.section0
+ >> nom >> donnee_specif.secti.section_t
+ >> nom >> donnee_specif.secti.section_tdt
+ >> nom >> donnee_specif.variation_section;
+ lesPtThermiInt.Lecture_base_info(ent,cas);
+ break;
+ }
+ case 2 : // ----------- lecture uniquement de se qui varie --------------------
+ { // récup contraintes et déformation
+ lesPtThermiInt.Lecture_base_info(ent,cas);
+ // les données spécifiques
+ string nom;
+ ent >> nom >> donnee_specif.secti.section_tdt;
+ donnee_specif.secti.section_t = donnee_specif.secti.section_tdt;
+ break;
+ break;
+ }
+ default :
+ { cout << "\nErreur : valeur incorrecte du type de lecture !\n";
+ cout << "BielletteThermi::Lecture_base_info(ofstream& sort,int cas)"
+ << " cas= " << cas << endl;
+ Sortie(1);
+ }
+ }
+ };
+
+// cas donne le niveau de sauvegarde
+// = 1 : on sauvegarde tout
+// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
+void BielletteThermi::Ecriture_base_info(ofstream& sort,const int cas)
+{// tout d'abord appel de l'écriture de la classe ElemThermi
+ ElemThermi::Ecriture_bas_inf(sort,cas);
+ // traitement du cas particulier de la biellette
+ switch (cas)
+ { case 1 : // ------- on sauvegarde tout -------------------------
+ {
+ // des tenseurs déformation et contrainte,
+ lesPtThermiInt.Ecriture_base_info(sort,cas);
+ // les données spécifiques
+ sort << "\n epaisStockeDansElement " << " section0= " << donnee_specif.secti.section0
+ << " section_t= " << donnee_specif.secti.section_t
+ << " section_tdt= " << donnee_specif.secti.section_tdt
+ << " variation= " << donnee_specif.variation_section;
+ break;
+ }
+ case 2 : // ----------- sauvegarde uniquement de se qui varie --------------------
+ { // des tenseurs déformation et contrainte,
+ lesPtThermiInt.Ecriture_base_info(sort,cas);
+ sort << "\n section_tdt= " << donnee_specif.secti.section_tdt;
+ break;
+ }
+ default :
+ { cout << "\nErreur : valeur incorrecte du type d'écriture !\n";
+ cout << "BielletteThermi::Ecriture_base_info(ofstream& sort,int cas)"
+ << " cas= " << cas << endl;
+ Sortie(1);
+ }
+ }
+ };
+
+
+// Calcul de la matrice géométrique et initiale
+ElemThermi::MatGeomInit BielletteThermi::MatricesGeometrique_Et_Initiale (const ParaAlgoControle & pa)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ Tableau & d_gradTB = (doCo->d_gradTB);// "
+ Tableau & d_fluxH = (doCo->d_fluxH);// "
+ bool cald_Dvirtuelle = false;
+ if (unefois.CalimpPrem == 0)
+ { unefois.CalimpPrem = 1;
+ Tableau tab(20);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ;
+ tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ // on ne calcul la dérivée de la déformation virtuelle qu'une fois
+ // car elle est constante dans le temps et indépendante des coordonnées
+ cald_Dvirtuelle=true;
+ };
+ // Par simplicité
+ Mat_pleine & matGeom = doCo->matGeom;
+ Mat_pleine & matInit = doCo->matInit;
+ // mise à zéro de la matrice géométrique
+ matGeom.Initialise();
+ Vecteur poids =(doCo->segment).TaWi(); // poids d'interpolation = 2
+ // prise en compte de la section
+ double section_moyenne = 0.;
+ const bool atdt=true;
+ section_moyenne = CalSectionMoyenne_et_vol_pti(atdt);
+ poids(1) *= section_moyenne;
+ ElemThermi::Cal_matGeom_Init
+ (matGeom,matInit,doCo->tab_ddl, d_gradTB,
+ doCo->d2_gradTB,d_fluxH,1,poids,pa,cald_Dvirtuelle);
+ return MatGeomInit(&matGeom,&matInit);
+ } ;
+
+// retourne les tableaux de ddl associés aux noeuds, gere par l'element
+// ce tableau et specifique a l'element
+const DdlElement & BielletteThermi::TableauDdl() const
+ { // --- debug
+// cout << "\n debug BielletteThermi::TableauDdl() ";
+// for (int i=1;i<=2;i++)
+// { int nbddl = doCo->tab_ddl.NbDdl(i);
+// cout << "\n noeud "<< i <<": ddl: ";
+// for (int j=1; j<= nbddl;j++)
+// cout << " j= "<< j << " " << Nom_ddl(doCo->tab_ddl(i).tb(j))<<" ";
+// };
+// cout << endl;
+ // fin --- debug
+
+
+ return doCo->tab_ddl;
+ };
+// liberation de la place pointee
+void BielletteThermi::Libere ()
+ {Element::Libere (); // liberation de residu et raideur
+ LibereTenseur() ; // liberation des tenseur intermediaires
+ };
+
+// acquisition ou modification d'une loi de comportement
+void BielletteThermi::DefLoi (LoiAbstraiteGeneral * NouvelleLoi)
+ { // verification du type de loi
+ if ((NouvelleLoi->Dimension_loi() != 1) && (NouvelleLoi->Dimension_loi() != 4))
+ { cout << "\n Erreur, la loi de comportement a utiliser avec des biellettes";
+ cout << " doit etre de type 1D, \n ici est de type = "
+ << (NouvelleLoi->Dimension_loi()) << " !!! " << endl;
+ Sortie(1);
+ }
+ // idem pour le type de déformation mécanique associé
+ tabSaveDefDon(1) = def->New_et_Initialise();
+// a priori pour l'instant ne sert à rien ici // cas d'une loi mécanique
+// if (GroupeMecanique(NouvelleLoi->Id_categorie()))
+// {loiComp = (Loi_comp_abstraite *) NouvelleLoi;
+// // initialisation du stockage particulier, ici 1 pt d'integ
+// tabSaveDon(1) = loiComp->New_et_Initialise();
+// // idem pour le type de déformation mécanique associé
+// tabSaveDefDon(1) = def->New_et_Initialise();
+// // définition du type de déformation associé à la loi
+// loiComp->Def_type_deformation(*def);
+// // on active les données particulières nécessaires au fonctionnement de la loi de comp
+// loiComp->Activation_donnees(tab_noeud,dilatation,lesPtThermiInt);
+// };
+ // cas d'une loi thermo physique
+ if (GroupeThermique(NouvelleLoi->Id_categorie()))
+ {loiTP = (CompThermoPhysiqueAbstraite *) NouvelleLoi;
+ // initialisation du stockage particulier, ici 1 pt d'integ
+ tabSaveTP(1) = loiTP->New_et_Initialise();
+ // définition du type de déformation associé à la loi
+ //loiTP->Def_type_deformation(*def);
+ // on active les données particulières nécessaires au fonctionnement de la loi de comp
+ loiTP->Activation_donnees(tab_noeud);
+ };
+ // cas d'une loi de frottement
+ if (GroupeFrottement(NouvelleLoi->Id_categorie()))
+ loiFrot = (CompFrotAbstraite *) NouvelleLoi;
+ };
+
+// test si l'element est complet
+int BielletteThermi::TestComplet()
+ { int res = ElemThermi::TestComplet(); // test dans la fonction mere
+ if ( donnee_specif.secti.section0 == section_defaut)
+ { cout << "\n la section de la biellette n'est pas defini \n";
+ res = 0; }
+ if ( tab_noeud(1) == NULL)
+ { cout << "\n les noeuds de la biellette ne sont pas defini \n";
+ res = 0; }
+ else
+ { int testi =1;
+ int posi = Id_nom_ddl("X1") -1;
+ int dim = ParaGlob::Dimension();
+ for (int i =1; i<= dim; i++)
+ for (int j=1;j<=2;j++)
+ if(!(tab_noeud(j)->Existe_ici(Enum_ddl(posi+i))))
+ testi = 0;
+ if(testi == 0)
+ { cout << "\n les ddls X1,X2 etc des noeuds de la biellette ne sont pas defini \n";
+ cout << " \n utilisez BielletteThermi::ConstTabDdl() pour completer " ;
+ res = 0; }
+ }
+ return res;
+ };
+
+// ajout du tableau de ddl des noeuds de biellette
+ void BielletteThermi::ConstTabDdl()
+ {
+ // tout d'abord on s'intéresse au xi qui servent pour la métrique
+ // mais qui sont hors service
+ Tableau ta(ParaGlob::Dimension()+1);
+ int posi = Id_nom_ddl("X1") -1;
+ int dim = ParaGlob::Dimension();
+ for (int i =1; i<= dim; i++)
+ {Ddl inter((Enum_ddl(i+posi)),0.,HSFIXE);
+ ta(i) = inter;
+ }
+ // maintenant on ajoute le ddl thermique
+ Ddl inter(TEMP,0.,LIBRE);
+ ta(dim+1)=inter;
+ // attribution des ddls aux noeuds
+ tab_noeud(1)->PlusTabDdl(ta);
+ tab_noeud(2)->PlusTabDdl(ta);
+
+ };
+
+// procesure permettant de completer l'element apres
+// sa creation avec les donnees du bloc transmis
+// peut etre appeler plusieurs fois
+ Element* BielletteThermi::Complete(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD)
+ { // complétion avec bloc
+ if (bloc.Nom(1) == "sections")
+ { donnee_specif.secti.section0 = bloc.Val(1);
+ // on initialise aussi les grandeurs à t et tdt
+ donnee_specif.secti.section_tdt = donnee_specif.secti.section_t = bloc.Val(1);
+ return this;
+ }
+ else if (bloc.Nom(1) == "variation_section")
+ { donnee_specif.variation_section = bloc.Val(1);
+ // on initialise aussi les grandeurs à t et tdt
+ return this;
+ }
+ else
+ return ElemThermi::Complete_ElemThermi(bloc,lesFonctionsnD);
+ };
+
+// affichage dans la sortie transmise, des variables duales "nom"
+// dans le cas ou nom est vide, affichage de "toute" les variables
+ void BielletteThermi::AfficheVarDual(ofstream& sort, Tableau& nom)
+ {// affichage de l'entête de l'element
+ sort << "\n******************************************************************";
+ sort << "\n Element bielette (2 noeuds 1 point d'integration) ";
+ sort << "\n******************************************************************";
+ // appel de la procedure de ElemThermi
+ if (!(unefois.dualSortbiel) && (unefois.CalimpPrem))
+ { VarDualSort(sort,nom,1,1);
+ unefois.dualSortbiel += 1;
+ }
+ else if ((unefois.dualSortbiel) && (unefois.CalimpPrem))
+ VarDualSort(sort,nom,1,11);
+ else if (!(unefois.dualSortbiel) && (unefois.CalResPrem_tdt))
+ { VarDualSort(sort,nom,1,2);
+ unefois.dualSortbiel += 1;
+ }
+ else if ((unefois.dualSortbiel) && (unefois.CalResPrem_tdt))
+ VarDualSort(sort,nom,1,12);
+ // sinon on ne fait rien
+ };
+
+// récupération des valeurs au numéro d'ordre = iteg pour
+// les grandeur enu
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+Tableau BielletteThermi::Valeur_a_diff_temps(bool absolue,Enum_dure enu_t,const List_io& enu,int iteg)
+ { // appel de la procedure de ElemThermi
+ int cas;
+ if (!(unefois.dualSortbiel) && (unefois.CalimpPrem))
+ { cas=1;unefois.dualSortbiel = 1;
+ }
+ else if ((unefois.dualSortbiel) && (unefois.CalimpPrem))
+ { cas = 11;}
+ else if (!(unefois.dualSortbiel) && (unefois.CalResPrem_tdt))
+ { cas=2;unefois.dualSortbiel += 1;
+ }
+ else if ((unefois.dualSortbiel) && (unefois.CalResPrem_tdt))
+ { cas = 12;}
+ // sinon pour l'instant pb, car il faut définir des variable dans la métrique
+ else
+ { cout << "\n warning: les grandeurs ne sont pas calculees : il faudrait au moins un pas de calcul"
+ << " pour inialiser les conteneurs des tenseurs resultats ";
+ if (ParaGlob::NiveauImpression() >= 4)
+ cout << "\n cas non prévu, unefois.dualSortbiel= " << unefois.dualSortbiel
+ << " unefois.CalimpPrem= " << unefois.CalimpPrem
+ << "\n BielletteThermi::Valeur_a_diff_temps(Enum_dure enu_t...";
+ Sortie(1);
+ };
+ return ElemThermi::Valeur_multi(absolue,enu_t,enu,iteg,cas);
+ };
+
+// récupération des valeurs au numéro d'ordre = iteg pour les grandeurs enu
+// ici il s'agit de grandeurs tensorielles, le retour s'effectue dans la liste
+// de conteneurs quelconque associée
+void BielletteThermi::ValTensorielle_a_diff_temps(bool absolue,Enum_dure enu_t,List_io& enu,int iteg)
+ { // appel de la procedure de ElemThermi
+ int cas;
+ if (!(unefois.dualSortbiel ) && (unefois.CalimpPrem ))
+ { cas=1;unefois.dualSortbiel += 1;
+ }
+ else if ((unefois.dualSortbiel ) && (unefois.CalimpPrem ))
+ { cas = 11;}
+ else if (!(unefois.dualSortbiel ) && (unefois.CalResPrem_tdt ))
+ { cas=2;unefois.dualSortbiel += 1;
+ }
+ else if ((unefois.dualSortbiel ) && (unefois.CalResPrem_tdt ))
+ { cas = 12;}
+ // sinon pour l'instant pb, car il faut définir des variable dans la métrique
+ else
+ { cout << "\n warning: les grandeurs ne sont pas calculees : il faudrait au moins un pas de calcul"
+ << " pour inialiser les conteneurs des tenseurs resultats ";
+ if (ParaGlob::NiveauImpression() >= 4)
+ cout << "\n cas non prévu, unefois.dualSortbiel= " << unefois.dualSortbiel
+ << " unefois.CalimpPrem= " << unefois.CalimpPrem
+ << "\n BielletteThermi::ValTensorielle_a_diff_temps(Enum_dure enu_t...";
+ Sortie(1);
+ };
+ ElemThermi::Valeurs_Tensorielles(absolue,enu_t,enu,iteg,cas);
+ };
+
+// cas d'un chargement volumique,
+// force indique la force volumique appliquée
+// retourne le second membre résultant
+// ici on considère la section de la biellette pour constituer le volume
+// -> explicite à t ou tdt en fonction de la variable booléenne atdt
+Vecteur BielletteThermi::SM_charge_volumique_E(const Coordonnee& force,bool atdt,const ParaAlgoControle & pa)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionnement de la metrique
+ if (!atdt)
+ {if(!(unefois.CalSMvol_t ))
+ { unefois.CalSMvol_t += 1;
+ Tableau tab(10);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = id_gijBB_t ;tab(9) = igradVBB_t; tab(10) = iVt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };}
+ else
+ {if(!(unefois.CalSMvol_tdt ))
+ { unefois.CalSMvol_tdt += 1;
+ Tableau tab(20);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ;
+ tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };};
+ // initialisation du résidu
+ residu->Zero();
+ // appel du programme général d'elemmeca et retour du vecteur second membre
+ // multiplié par la section pour avoir le volume, on considère que la section est à jour
+ double section = donnee_specif.secti.section_tdt;
+ if (!atdt) section = donnee_specif.secti.section_t;
+ return (section * ElemThermi::SM_charge_vol_E (doCo->tab_ddl,(doCo->segment).TaPhi()
+ ,tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa));
+ };
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement volumique,
+// force indique la force volumique appliquée
+// retourne le second membre résultant
+// ici on l'épaisseur de l'élément pour constituer le volume -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid BielletteThermi::SMR_charge_volumique_I
+ (const Coordonnee& force,const ParaAlgoControle & pa)
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+
+ // initialisation du résidu
+ residu->Zero();
+ // initialisation de la raideur
+ raideur->Zero();
+
+ // -- définition des constantes de la métrique si nécessaire
+ // en fait on fait appel aux même éléments que pour le calcul implicite
+ if (!(unefois.CalSMvol_tdt ))
+ { unefois.CalSMvol_tdt += 1;
+ Tableau tab(20);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = id_gijBB_t ;tab(16) = id_gijBB_tdt ;tab(17) = idMtdt ;
+ tab(18) = igradVBB_tdt; tab(19) = iVtdt; tab(20) = idVtdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+
+ // appel du programme général d'ElemThermi
+ ElemThermi::SMR_charge_vol_I (doCo->tab_ddl,(doCo->segment).TaPhi()
+ ,tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa);
+ // prise en compte de la section
+ (*residu) *= donnee_specif.secti.section_t;
+ (*raideur) *= donnee_specif.secti.section_t;
+ Element::ResRaid el;
+ el.res = residu;
+ el.raid = raideur;
+ return el;
+ };
+
+// cas d'un chargement lineique, sur l'aretes de la biellette
+// force indique la force lineique appliquée
+// numarete indique le numéro de l'arete chargée ici 1
+// retourne le second membre résultant
+// -> explicite à t ou tdt en fonction de la variable booléenne atdt
+Vecteur BielletteThermi::SM_charge_lineique_E(const Coordonnee& force,int ,bool atdt,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu
+ ((*res_extA)(1))->Zero();
+ // on récupère ou on crée la frontière arrête
+ ElFrontiere* elf = Frontiere_lineique(1,true);
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionnement de la metrique
+ if (!atdt)
+ {if( !(unefois.CalSMlin_t ))
+ { unefois.CalSMlin_t += 1;
+ Tableau tab(8);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = igradVBB_t;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };}
+ else
+ {if( !(unefois.CalSMlin_tdt ))
+ { unefois.CalSMlin_tdt += 1;
+ Tableau tab(8);
+ tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0;tab(4) = igijBB_tdt;
+ tab(5) = igijHH_tdt; tab(6) = id_giB_tdt; tab(7) = id_gijBB_tdt ;
+ tab(8) = igradVBB_tdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };};
+ // on définit la déformation a doc si elle n'existe pas déjà
+ if (defArete(1) == NULL)
+ defArete(1) = def; // a priori idem que la biellette
+
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ return ElemThermi::SM_charge_line_E (doCo->tab_ddl,1,(doCo->segment).TaPhi()
+ ,tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa);
+ };
+
+// cas d'un chargement lineique, sur les aretes frontières des éléments
+// force indique la force lineique appliquée
+// numarete indique le numéro de l'arete chargée ici 1 par défaut
+// retourne le second membre résultant
+// -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid BielletteThermi::SMR_charge_lineique_I
+ (const Coordonnee& force,int ,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu et de la raideur
+ ((*res_extA)(1))->Zero();
+ ((*raid_extA)(1))->Zero();
+ // on récupère ou on crée la frontière arrête
+ ElFrontiere* elf =Frontiere_lineique(1,true);
+
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionnement de la metrique
+ if( !(unefois.CalSMRlin ))
+ { unefois.CalSMRlin += 1;
+ Tableau tab(15);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = igradVBB_tdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // on définit la déformation a doc si elle n'existe pas déjà
+ if (defArete(1) == NULL)
+ defArete(1) = def; // a priori idem que la biellette
+
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ return ElemThermi::SMR_charge_line_I (doCo->tab_ddl,1
+ ,(doCo->segment).TaPhi(),tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa);
+ };
+
+
+// cas d'un chargement lineique suiveuse, sur l'aretes frontière de la biellette (2D uniquement)
+// force indique la force lineique appliquée
+// numarete indique le numéro de l'arete chargée
+// retourne le second membre résultant
+// -> explicite à t ou tdt en fonction de la variable booléenne atdt
+Vecteur BielletteThermi::SM_charge_lineique_Suiv_E(const Coordonnee& force,int ,bool atdt,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu
+ ((*res_extA)(1))->Zero();
+ // on récupère ou on crée la frontière arrête
+ ElFrontiere* elf = Frontiere_lineique(1,true);
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionnement de la metrique
+ if (!atdt)
+ {if( !(unefois.CalSMlin_t ))
+ { unefois.CalSMlin_t += 1;
+ Tableau tab(8);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ tab(8) = igradVBB_t;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };}
+ else
+ {if( !(unefois.CalSMlin_tdt ))
+ { unefois.CalSMlin_tdt += 1;
+ Tableau tab(8);
+ tab(1) = igiB_0; tab(2) = igiB_tdt; tab(3) = igijBB_0;tab(4) = igijBB_tdt;
+ tab(5) = igijHH_tdt; tab(6) = id_giB_tdt; tab(7) = id_gijBB_tdt ;
+ tab(8) = igradVBB_tdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };};
+ // on définit la déformation a doc si elle n'existe pas déjà
+ if (defArete(1) == NULL)
+ defArete(1) = def; // a priori idem que la biellette
+
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ return ElemThermi::SM_charge_line_Suiv_E (doCo->tab_ddl,1,(doCo->segment).TaPhi()
+ ,tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa);
+ };
+
+// cas d'un chargement lineique suiveuse, sur l'aretes frontière de la biellette (2D uniquement)
+// force indique la force lineique appliquée
+// numarete indique le numéro de l'arete chargée
+// retourne le second membre résultant
+// -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid BielletteThermi::SMR_charge_lineique_Suiv_I
+ (const Coordonnee& force,int ,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu et de la raideur
+ ((*res_extA)(1))->Zero();
+ ((*raid_extA)(1))->Zero();
+ // on récupère ou on crée la frontière arrête
+ ElFrontiere* elf = Frontiere_lineique(1,true);
+
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // dimensionnement de la metrique
+ if( !(unefois.CalSMRlin ))
+ { unefois.CalSMRlin += 1;
+ Tableau tab(15);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igiB_tdt; tab(4) = igijBB_0;
+ tab(5) = igijBB_t;tab(6) = igijBB_tdt; tab(7) = igijHH_tdt; tab(8) = id_giB_tdt;
+ tab(9) = id_gijBB_tdt ;tab(10) = igiH_tdt;tab(11) = id_giH_tdt;
+ tab(12) = id_gijHH_tdt;tab(13) = id_jacobien_tdt;tab(14) = id2_gijBB_tdt;
+ tab(15) = igradVBB_tdt;
+ doCo->met_biellette.PlusInitVariables(tab) ;
+ };
+ // on définit la déformation a doc si elle n'existe pas déjà
+ if (defArete(1) == NULL)
+ defArete(1) = def; // a priori idem que la biellette
+
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ return ElemThermi::SMR_charge_line_Suiv_I (doCo->tab_ddl,1
+ ,(doCo->segment).TaPhi(),tab_noeud.Taille(),(doCo->segment).TaWi(),force,pa);
+ };
+
+ // cas d'un chargement surfacique hydro-dynamique,
+ // Il y a trois forces: une suivant la direction de la vitesse: de type traînée aerodynamique
+ // Fn = poids_volu * fn(V) * S * (normale*u) * u, u étant le vecteur directeur de V (donc unitaire)
+ // une suivant la direction normale à la vitesse de type portance
+ // Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire, normal à V, et dans le plan n et V
+ // une suivant la vitesse tangente de type frottement visqueux
+ // T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
+ // coef_mul: est un coefficient multiplicateur global (de tout)
+ // retourne le second membre résultant
+ // // -> explicite à t ou à tdt en fonction de la variable booléenne atdt
+Vecteur BielletteThermi::SM_charge_hydrodynamique_E( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int num,const double& coef_mul
+ , Courbe1D* coef_aero_t,bool atdt,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu
+ ((*res_extN)(num))->Zero(); // ici les frontières sont des points
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // on récupère ou on crée la frontière points
+ Frontiere_points(num,true);
+ // ici on fait l'hypothèse d'une section circulaire, n'ayant pas d'autres infos pour l'instant sur les
+ // dimensions de la section, d'où la surface frontale approximativement s'en déduie
+ double section = donnee_specif.secti.section_tdt;
+ if (!atdt) section = donnee_specif.secti.section_t;
+ double dimension_transversale = sqrt(section/ConstMath::Pi);
+ // on utilise l'élément géométique de l'élément, pour TaPhi et TaWi pour les passages de paramètres,
+ // mais ces infos ne sont pas utilisées car pour les frontières points, pas de points d'integ
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ return ElemThermi::SM_charge_hydrodyn_E (poidvol,doCo->segment.TaPhi(),1
+ ,frot_fluid,doCo->segment.TaWi()
+ ,coef_aero_n,num,coef_mul,coef_aero_t,pa,atdt);
+ };
+
+ // -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid BielletteThermi::SMR_charge_hydrodynamique_I( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int num,const double& coef_mul
+ , Courbe1D* coef_aero_t,const ParaAlgoControle & pa)
+ { // initialisation du vecteur résidu et de la raideur
+ ((*res_extN)(num))->Zero();
+ ((*raid_extN)(num))->Zero();
+ BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ // on récupère ou on crée la frontière points
+ Frontiere_points(num,true);
+ // ici on fait l'hypothèse d'une section circulaire, n'ayant pas d'autres infos pour l'instant sur les
+ // dimensions de la section, d'où la surface frontale approximativement s'en déduie
+ double section = donnee_specif.secti.section_tdt;
+ double dimension_transversale = sqrt(section/ConstMath::Pi);
+ // on utilise l'élément géométique de l'élément, pour TaPhi et TaWi pour les passages de paramètres,
+ // mais ces infos ne sont pas utilisées car pour les frontières points, pas de points d'integ
+ // appel du programme général d'ElemThermi et retour du vecteur second membre
+ Element::ResRaid el(ElemThermi::SM_charge_hydrodyn_I (poidvol,doCo->segment.TaPhi(),1
+ ,frot_fluid,doCo->segment.TaWi(),tabb(posi_tab_front_point+num)->DdlElem()
+ ,coef_aero_n,num,coef_mul,coef_aero_t,pa));
+ (*el.res) *= dimension_transversale;
+ (*el.raid) *= dimension_transversale;
+ return el;
+ };
+
+// calcul de la nouvelle section moyenne finale (sans raideur)
+// ramène la section moyenne calculée à atdt
+const double& BielletteThermi::CalSectionMoyenne_et_vol_pti(const bool atdt)
+ { // dépend si l'on veut une variation ou non
+ if (donnee_specif.variation_section)
+ {// S(t+\Delta t) = \frac{(S(t)~\sqrt{g(t)})}{\sqrt{g(t+\Delta t)}}\left ( \frac{K_{t}}{(K_{t} + (P(t+\Delta t) - P(t)))} \right )
+ // il faut avoir en tête que P = - trace(sig)/3 !!!
+
+ //en thermique pour l'instant on ne tient pas compte de la variation, mais dès que cela est possible
+ // on tiendra compte de la dilatation thermique
+ Sect& sect = donnee_specif.secti; // pour simplifier
+ return sect.section0;
+ };
+//
+//
+//
+// // .. en bouclant sur les pt d'integ enregistré ..
+// // -- on récupère et on calcule les jacobiens moyens à t(ou 0) et final
+// double jacobien_moy_ini = 0.; double jacobien_moy_fin = 0.; // init
+// // -- de même on récupère et on calcul la trace moyenne de la contrainte
+// double traceSig_moy = 0.; double traceSig_moy_ini = 0.;
+// // -- de même on récupère et on calcul le module de compressibilité moyen
+// double troisK_moy = 0.;
+// for (int i=1;i<= nombre_V.nbi;i++)
+// { // cas de la compressibilité
+// const double& troisK = 3. * (*lesPtIntegMecaInterne)(i).ModuleCompressibilite_const();
+// troisK_moy += troisK;
+// // cas des jacobiens
+// const double& jacobien_0 = *(tabSaveDefDon(i)->Meti_00().jacobien_);
+// if (atdt)
+// { const double& jacobien_ini = *(tabSaveDefDon(i)->Meti_t().jacobien_);
+// jacobien_moy_ini += jacobien_ini;
+// const double& jacobien_fin = *(tabSaveDefDon(i)->Meti_tdt().jacobien_);
+// jacobien_moy_fin += jacobien_fin;
+// // cas de la trace de sigma
+// const double traceSig = (*lesPtIntegMecaInterne)(i).SigHH_const() && (*(tabSaveDefDon(i)->Meti_tdt().gijBB_));
+// traceSig_moy += traceSig;
+// const double traceSig_ini = (*lesPtIntegMecaInterne)(i).SigHH_t_const() && (*(tabSaveDefDon(i)->Meti_t().gijBB_));
+// traceSig_moy_ini += traceSig_ini;
+// (*lesPtIntegMecaInterne)(i).Volume_pti() *= (sect.section_t * jacobien_ini) / jacobien_fin
+// * troisK / (troisK - traceSig+traceSig_ini);
+// }
+// else
+// { const double& jacobien_ini = *(tabSaveDefDon(i)->Meti_00().jacobien_);
+// jacobien_moy_ini += jacobien_ini;
+// const double& jacobien_fin = *(tabSaveDefDon(i)->Meti_t().jacobien_);
+// jacobien_moy_fin += jacobien_fin;
+// // cas de la trace de sigma
+// const double traceSig = (*lesPtIntegMecaInterne)(i).SigHH_const() && (*(tabSaveDefDon(i)->Meti_t().gijBB_));
+// traceSig_moy += traceSig;
+// (*lesPtIntegMecaInterne)(i).Volume_pti() *= (sect.section0 * jacobien_ini) / jacobien_fin
+// * troisK / (troisK - traceSig);
+// };
+// };
+// jacobien_moy_ini /= nombre_V.nbi;
+// jacobien_moy_fin /= nombre_V.nbi;
+// traceSig_moy /= nombre_V.nbi;
+// troisK_moy /= nombre_V.nbi;
+// // d'où le calcul de la nouvelle section en utilisant la relation:
+// // (V-V_0)/V = trace(sigma)/3 /K_moy
+// if (atdt)
+// { // là on utilise uniquement l'incrément: cf. partie théorique d'herezh
+// // S(t+\Delta t) = \frac{(S(t)~\sqrt{g(t)})}{\sqrt{g(t+\Delta t)}}\left ( \frac{K_{t}}{(K_{t} + (P(t+\Delta t) - P(t)))} \right )
+// sect.section_tdt = (sect.section_t * jacobien_moy_ini) / jacobien_moy_fin
+// * troisK_moy / (troisK_moy - traceSig_moy+traceSig_moy_ini);
+//
+//// ancienne nouvelle formule, via la def logarithmique
+//// double ratio = traceSig_moy/troisK_moy;
+//// sect.section_tdt = (sect.section0 * jacobien_moy_t) / jacobien_moy_fin
+//// * exp(ratio);
+//// ancienne formule * troisK_moy / (troisK_moy - traceSig_moy);
+// //--debug
+// //if (num_elt==1)
+// // { Noeud* noe = tab_noeud(1);
+// // double R_0 = noe->Coord0().Norme(); double R = noe->Coord2().Norme();
+// //cout << "\n e0= " << epais.section_tdt<< " troisK_moy=" << troisK_moy << " traceSig_moy=" << traceSig_moy
+// // << " J0= " << jacobien_moy_0 << " J= " << jacobien_moy_fin << " R_0 " << R_0 << " R= " << R;
+// // };
+// //-- fin debug
+// return sect.section_tdt;
+// }
+// else
+// {// dans le cas où on n'a pas d'incrément, on retiend la formule intégrée
+// // dans laquelle on suppose que le K ne varie pas ... donc une formule qui n'est
+// // pas vraiment valide pour des lois complexes !!
+// double ratio = traceSig_moy/troisK_moy;
+// sect.section_t = (sect.section0 * jacobien_moy_ini) / jacobien_moy_fin
+// * exp(ratio);
+//// * troisK_moy / (troisK_moy - traceSig_moy);
+// return sect.section_t;
+// };
+// }
+// else
+// // si on ne veut pas de variation
+// {if (atdt) { return donnee_specif.secti.section_tdt;}
+// else { return donnee_specif.secti.section_t;};
+// };
+ };
+
+ // retourne la liste abondée de tous les données particulières interne actuellement utilisées
+// par l'élément (actif ou non), sont exclu de cette liste les données particulières des noeuds
+// reliées à l'élément
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+List_io BielletteThermi::Les_types_particuliers_internes(bool absolue) const
+ { // on commence par récupérer la liste général provenant d'ElemMeca
+ List_io ret = ElemThermi::Les_types_particuliers_internes(absolue);
+ // ensuite on va ajouter les données particulières aux sfe
+ Grandeur_scalaire_double grand_courant; // def d'une grandeur courante
+ // $$$ cas de la section initiale
+ TypeQuelconque typQ1(SECTION_MOY_INITIALE,SIG11,grand_courant);
+ ret.push_back(typQ1);
+ // $$$ cas de la section finale
+ TypeQuelconque typQ2(SECTION_MOY_FINALE,SIG11,grand_courant);
+ ret.push_back(typQ2);
+ return ret;
+ };
+
+// récupération de grandeurs particulières au numéro d'ordre = iteg
+// celles-ci peuvent être quelconques
+// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+void BielletteThermi::Grandeur_particuliere (bool absolue,List_io& liTQ,int iteg)
+ {
+ // on balaie la liste transmise pour les grandeurs propres
+ List_io::iterator il,ilfin = liTQ.end();
+ // on commence par appeler la fonction de la classe m่re
+ // il n'y aura pas de calcul des grandeurs inactivées
+ ElemThermi::Grandeur_particuliere (absolue,liTQ,iteg);
+
+ // puis les grandeurs sp้cifiques
+ for (il=liTQ.begin();il!=ilfin;il++)
+ {TypeQuelconque& tipParticu = (*il); // pour simplifier
+ if (tipParticu.EnuTypeQuelconque().Nom_vide()) // veut dire que c'est un enum pur
+ switch (tipParticu.EnuTypeQuelconque().EnumTQ())
+ {
+ // 1) -----cas de la section moyenne initiale, ici elle ne d้pend pas du point d'int้gration
+ case SECTION_MOY_INITIALE:
+ { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=donnee_specif.secti.section0;
+ (*il).Active();
+ break;
+ }
+ // 2) -----cas de la section moyenne finale, ici elle ne d้pend pas du point d'int้gration
+ case SECTION_MOY_FINALE: // on inactive la grandeur quelconque
+ { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=donnee_specif.secti.section_tdt;
+ (*il).Active();
+ break;
+ }
+ default: // on ne fait rien
+ 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
+Tableau const & BielletteThermi::Frontiere(bool force)
+ { int cas = 6; // on veut des lignes et des points
+ return Frontiere_elethermi(cas,force);
+
+//
+// // 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) && (ind_front_surf == 0) && (ind_front_point == 0))
+// || force )
+//// if ((ind_front_point == 0) || force || (ind_front_point == 2))
+// { // dimensionnement des tableaux intermediaires
+// Tableau tab(1); // les noeuds des points frontieres
+// DdlElement ddelem(1); // les ddlelements des points frontieres
+// int tail;
+// if ((ParaGlob::Dimension() == 1) && (ind_front_lin > 0))
+// tail = 3; // deux points et une ligne
+// else if (ParaGlob::Dimension() == 1) // cas sans ligne
+// tail = 2; // 2 points
+// else // cas d'une dimension 2 et 3
+// { tail = 3; // deux points et une ligne
+// ind_front_lin = 1;
+// }
+// tabb.Change_taille(tail); // le tableau total de frontières
+//
+// // premier point
+// tab(1) = tab_noeud(1);
+// ddelem.Change_un_ddlNoeudElement(1,doCo->tab_ddl(1));
+// if (tabb(1+posi_tab_front_point) == NULL)
+// tabb(1+posi_tab_front_point) = new FrontPointF (tab,ddelem);
+// // second point
+// tab(1) = tab_noeud(2);
+// ddelem.Change_un_ddlNoeudElement(1,doCo->tab_ddl(2));
+// if (tabb(2+posi_tab_front_point) == NULL)
+// tabb(2+posi_tab_front_point) = new FrontPointF (tab,ddelem);
+// // 3 ieme cote eventuelle
+// if (ind_front_lin > 0)
+// // cas où il y a une ligne, c'est forcément le premier élément
+// if (tabb(1) == NULL)
+// tabb(1) = new FrontSegLine(tab_noeud,doCo->tab_ddl);
+//
+// // mise à jour des indicateurs
+// ind_front_point = 1;
+// }
+//
+// return 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 BielletteThermi::Frontiere_points(int num,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
+// #ifdef MISE_AU_POINT
+// if ((num > 2)||(num <=0))
+// { cout << "\n *** erreur, pour les biellettes il n'y a que deux frontieres point ! "
+// << "\n Frontiere_points(int num,bool force)";
+// Sortie(1);
+// }
+// #endif
+//
+// if ((ind_front_point == 0) || force || (ind_front_point == 2))
+// {Tableau tab(1); // les noeuds des points frontieres
+// DdlElement ddelem(1); // les ddlelements des points frontieres
+// // 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);
+// // dans tous les autres cas on construit la frontière point
+// // on commence par dimensionner le tableau de frontière
+// if ((ind_front_lin > 0) && (ind_front_point==0))
+// // cas où il y a une frontière ligne (mais pas de point)
+// { tabb.Change_taille(3); posi_tab_front_point = 1;}
+// else if ((ind_front_lin == 0) && (ind_front_point==0))
+// // cas où aucune frontière existe, on crée pour les points
+// { tabb.Change_taille(2); posi_tab_front_point = 0;};
+// // dans les deux autres cas ((ind_front_lin == 0) && (ind_front_point>0)) et
+// // ((ind_front_lin > 0) && (ind_front_point>0)), les points existant déjà on n'a rien n'a faire
+// // on définit les deux points par simplicité
+// // premier point
+// tab(1) = tab_noeud(1);
+// ddelem.Change_un_ddlNoeudElement(1,doCo->tab_ddl(1));
+// if (tabb(1+posi_tab_front_point) == NULL)
+// tabb(1+posi_tab_front_point) = new FrontPointF (tab,ddelem);
+// // second point
+// tab(1) = tab_noeud(2);
+// ddelem.Change_un_ddlNoeudElement(1,doCo->tab_ddl(2));
+// if (tabb(2+posi_tab_front_point) == NULL)
+// tabb(2+posi_tab_front_point) = new FrontPointF (tab,ddelem);
+// ind_front_point=1; // mise à jour de l'indicateur
+// };
+// return (ElFrontiere*)tabb(num+posi_tab_front_point);
+// };
+
+//// 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)
+//ElFrontiere* const BielletteThermi::Frontiere_lineique(int num,bool )
+// { // le calcul et la création ne sont effectués qu'au premier appel
+// // ou lorsque l'on veut forcer une recréation
+// #ifdef MISE_AU_POINT
+// if (num != 1)
+// { cout << "\n *** erreur, pour les biellettes il n'y a qu'une frontière ligne ! "
+// << "\n Frontiere_lineique(int num,bool force)";
+// Sortie(1);
+// }
+// #endif
+//
+// // on regarde si les frontières linéiques existent sinon on les crée
+// if (ind_front_lin == 1)
+// return (ElFrontiere*)tabb(1);
+// else if ( ind_front_lin == 2)
+// // cas où certaines frontières existent
+// if (tabb(1) != NULL)
+// return (ElFrontiere*)tabb(1);
+// // dans tous les autres cas on construit la frontière ligne
+// // on commence par dimensionner le tableau de frontière
+// if (ind_front_point > 0)
+// // cas où il y a des frontières points (mais pas ligne)
+// // on décale le tableau
+// { tabb.Change_taille(3);
+// tabb(3) = tabb(2);
+// tabb(2) = tabb(1);
+// posi_tab_front_point = 1;
+// }
+// else
+// // cas d'une frontière linéique
+// tabb.Change_taille(1);
+// // on définit la ligne
+// tabb(1) = new FrontSegLine(tab_noeud,doCo->tab_ddl);
+// ind_front_lin = 1; // mise à jour de l'indicateur
+// // et normalement posi_tab_front_ligne = 0, car jamais changé
+// return (ElFrontiere*)tabb(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)
+//// ici normalement la fonction ne doit pas être appelée
+//ElFrontiere* const BielletteThermi::Frontiere_surfacique(int ,bool )
+// { cout << "\n *** erreur, pour les biellettes il n'y a pas de frontiere surface ! "
+// << "\n Frontiere_surfacique(int ,bool force = false)";
+// Sortie(1);
+// return NULL;
+// };
+
+// =====>>>> methodes privées appelees par les classes dérivees <<<<=====
+
+// fonction d'initialisation servant au niveau du constructeur
+BielletteThermi::DonneeCommune * BielletteThermi::Init
+ (Donnee_specif donnee_spec,bool sans_init_noeud)
+{ // bien que la grandeur donnee_specif est défini dans la classe generique
+ // le fait de le passer en paramètre permet de tout initialiser dans Init
+ // et ceci soit avec les valeurs par défaut soit avec les bonnes valeurs
+ donnee_specif =donnee_spec;
+ // le fait de mettre les pointeurs a null permet
+ // de savoir que l'element n'est pas complet
+ tab_noeud.Change_taille(nombre_V.nbne);
+ // dans le cas d'un constructeur avec tableau de noeud, il ne faut pas mettre
+ // les pointeurs à nuls d'où le test
+ if (!sans_init_noeud)
+ for (int i =1;i<= nombre_V.nbne;i++) tab_noeud(i) = NULL;
+ // definition des donnees communes aux BielletteThermixxx
+ // a la premiere definition d'une instance
+ if (unefois.doCoMemb == NULL)
+ BielletteThermi::Def_DonneeCommune();
+ unefois.doCoMemb = doCo ;
+ met = &(doCo->met_biellette); // met est defini dans ElemThermi
+ // def pointe sur la deformation specifique a l'element pour le calcul thermique
+ def = new Deformation(*met,tab_noeud,(doCo->segment).TaDphi(),(doCo->segment).TaPhi());
+ // idem pour la remontee aux contraintes et le calcul d'erreur
+ defEr = new Deformation(*met,tab_noeud,(doCo->segmentEr).TaDphi(),(doCo->segmentEr).TaPhi());
+ // idem pour la remontee aux contraintes et le calcul d'erreur
+ defMas = new Deformation(*met,tab_noeud,(doCo->segmentMas).TaDphi(),(doCo->segmentMas).TaPhi());
+ // idem pour le calcul de second membre
+ defArete.Change_taille(1); // 1 arrête utilisée pour le second membre
+ // la déformation sera construite si nécessaire au moment du calcul de second membre
+ defArete(1) = NULL;
+
+ //dimensionnement des deformations et contraintes etc..
+ int dimtens = 1;
+ lesPtThermiInt.Change_taille_PtIntegThermi(1,dimtens);
+
+ // stockage des donnees particulieres de la loi de comportement au point d'integ
+ tabSaveDon.Change_taille(nombre_V.nbi);
+ tabSaveTP.Change_taille(nombre_V.nbi);
+ tabSaveDefDon.Change_taille(nombre_V.nbi);
+ tab_energ.Change_taille(nombre_V.nbi);
+ tab_energ_t.Change_taille(nombre_V.nbi);
+ // initialisation des pointeurs définis dans la classe Element concernant les résidus et
+ // raideur
+ // --- cas de la puissance interne ---
+ residu = &(doCo->residu_interne); // residu local
+ raideur = &(doCo->raideur_interne); // raideur locale
+ // --- cas de la dynamique -----
+ mat_masse = &(doCo->matrice_masse);
+ // --- cas des efforts externes concernant les noeuds ------
+ res_extN = &(doCo->residus_externeN); // pour les résidus et second membres
+ raid_extN= &(doCo->raideurs_externeN);// pour les raideurs
+ // --- cas des efforts externes concernant les aretes ------
+ res_extA = &(doCo->residus_externeA); // pour les résidus et second membres
+ raid_extA= &(doCo->raideurs_externeA);// pour les raideurs
+
+ return doCo;
+};
+
+
+// fonction privee
+// dans cette fonction il ne doit y avoir que les données communes !!
+void BielletteThermi::Def_DonneeCommune()
+ { int nbn = nombre_V.nbne;
+ // interpollation : element geometrique correspondant: 1 pt integ, 2 noeuds
+ GeomSeg seg(nombre_V.nbi,nbn) ;
+ // degre de liberte: ici de thermique
+ int dim = ParaGlob::Dimension();
+ DdlElement tab_ddl(nbn,dim);
+ int posi = Id_nom_ddl("TEMP");
+ int i =1;
+ for (int j=1; j<= nbn; j++)
+ tab_ddl.Change_Enum(j,i,Enum_ddl(posi));
+ // cas des ddl éléments secondaires pour le calcul d'erreur
+ // def du nombre de composantes du tenseur de contrainte en absolu
+ int nbcomposante = ParaGlob::Dimension();
+ DdlElement tab_ddlErr(nbn,nbcomposante);
+ posi = Id_nom_ddl("FLUXD1") -1;
+ for (int j=1; j<= nbn; j++)
+ { // on definit le nombre de composante du flux en absolu
+ switch (nbcomposante)
+ { case 3 : tab_ddlErr.Change_Enum(j,3,Enum_ddl(3+posi)); // cas de FLUXD3
+ case 2 : tab_ddlErr.Change_Enum(j,2,Enum_ddl(2+posi)); // cas de FLUXD2
+ case 1 : tab_ddlErr.Change_Enum(j,1,Enum_ddl(1+posi)); // cas de FLUXD1
+ };
+ };
+ // egalement pour tab_Err1FLUX, def d'un tableau de un ddl : enum FLUXD1
+ // par noeud
+ DdlElement tab_Err1FLUX(nbn,DdlNoeudElement(FLUXD1));
+ // toujours pour le calcul d'erreur definition des fonctions d'interpolation
+ // pour le calcul du hession de la fonctionnelle :
+ // 2 points d'integration et 2 noeuds
+ GeomSeg segEr(nombre_V.nbiEr,nbn) ;
+ // pour le calcul de la matrice masse definition des fonctions d'interpolation
+ // 2 points d'integration et 2 noeuds, en particulier pour le calcul de la masse consistante
+ GeomSeg segMa(nombre_V.nbiMas,nbn) ;
+ // def metrique
+ // on definit les variables a priori toujours utiles
+ Tableau tab(24);
+ tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt ;
+ tab(4) = igiB_0; tab(5) = igiB_t; tab(6) = igiB_tdt;
+ tab(7) = igiH_0; tab(8) = igiH_t; tab(9) = igiH_tdt ;
+ tab(10)= igijBB_0; tab(11)= igijBB_t; tab(12)= igijBB_tdt;
+ tab(13)= igijHH_0; tab(14)= igijHH_t; tab(15)= igijHH_tdt ;
+ tab(16)= id_gijBB_tdt; tab(17)= id_giH_tdt; tab(18)= id_gijHH_tdt;
+ tab(19)= idMtdt ; tab(20)= id_jacobien_tdt;tab(21)= id2_gijBB_tdt;
+ tab(22)= igradVBB_tdt; tab(23) = iVtdt; tab(24)= idVtdt;
+ // dim du pb , nb de vecteur de la base , tableau de ddl et la def de variables
+ // ici il s'agit des ddl Xi + ddl de thermique: a priori les ddl de Xi
+ // ne serviront que pour les pb couplés
+ int posi_x1 = Id_nom_ddl("X1") -1;
+ DdlElement tab_ddl_metrique(nbn,dim+1); // une métrique d'élément contenant les Xi et la température
+ for (int i =1; i<= dim; i++)
+ for (int j=1; j<= nbn; j++)
+ {for (int i =1; i<= dim; i++)
+ tab_ddl_metrique.Change_Enum(j,i,Enum_ddl(i+posi)); // cas des Xi
+ tab_ddl_metrique.Change_Enum(j,dim+1,TEMP);
+ };
+ Met_biellette metri(ParaGlob::Dimension(),tab_ddl_metrique,tab,nbn) ;
+ // ---- cas du calcul d'erreur sur sigma ou epsilon
+ // les tenseurs sont exprimees en absolu donc nombre de composante fonction
+ // de la dimension absolue
+ Tableau resEr(nbcomposante);
+ for (int i = 1;i<= nbcomposante; i++)
+ resEr(i)=new Vecteur (nbn); // une composante par noeud
+ Mat_pleine raidEr(nbn,nbn); // la raideur pour l'erreur
+ // dimensionnement des différents résidus et raideurs pour le calcul mécanique
+ int nbddl = tab_ddl.NbDdl();
+ Vecteur residu_int(nbddl); Mat_pleine raideur_int(nbddl,nbddl);
+ // cas de la dynamique
+ Mat_pleine matmasse(1,nbddl); // a priori on dimensionne en diagonale
+ // il y a deux extrémités mais identiques
+ Tableau residus_extN(2); residus_extN(1) = new Vecteur(dim);
+ residus_extN(2) = residus_extN(1);
+ int nbddlA = nombre_V.nbneA * dim; int nbA = 1; // 1 arêtes
+ Tableau residus_extA(nbA); residus_extA(1) = new Vecteur(nbddlA);
+ Tableau raideurs_extA(nbA); raideurs_extA(1) = new Mat_pleine(nbddlA,nbddlA);
+ Tableau raideurs_extN(2);raideurs_extN(1) = new Mat_pleine(dim,dim);
+ raideurs_extN(2) = raideurs_extN(1);
+ // definition de la classe static contenant toute les variables communes aux biellettes
+ doCo = new DonneeCommune(seg,tab_ddl,tab_ddlErr,tab_Err1FLUX,metri,resEr,raidEr,segEr,
+ residu_int,raideur_int,residus_extN,raideurs_extN,residus_extA,raideurs_extA
+ ,matmasse,segMa,nombre_V.nbi);
+ };
+
+// destructions de certaines grandeurs pointées, créées au niveau de l'initialisation
+void BielletteThermi::Destruction()
+ { // tout d'abord l'idée est de détruire certaines grandeurs pointées que pour le dernier élément
+ if ((unefois.nbelem_in_Prog == 0)&& (unefois.doCoMemb != NULL))
+ // cas de la destruction du dernier élément
+ { BielletteThermi::DonneeCommune* doCo = unefois.doCoMemb; // pour simplifier l'écriture
+ int resErrTaille = doCo->resErr.Taille();
+ for (int i=1;i<= resErrTaille;i++)
+ delete doCo->resErr(i);
+ delete doCo->residus_externeN(1);
+ delete doCo->raideurs_externeN(1);
+ delete doCo->residus_externeA(1);
+ delete doCo->raideurs_externeA(1);
+ }
+ };
+
+
+
diff --git a/Elements/Thermique/Biellette/BielletteThermi.h b/Elements/Thermique/Biellette/BielletteThermi.h
new file mode 100755
index 0000000..4126c3d
--- /dev/null
+++ b/Elements/Thermique/Biellette/BielletteThermi.h
@@ -0,0 +1,661 @@
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 06/03/2023 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: La classe BielletteThermi permet de declarer des elements *
+ * biellettes et de realiser le calcul du residu local et de la raideur*
+ * locale pour une loi de comportement donnee. La dimension de l'espace *
+ * pour un tel element est 1. *
+ * *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * VERIFICATION: *
+ * *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * ! ! ! ! *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' *
+ * MODIFICATIONS: *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * $ *
+ ************************************************************************/
+// -----------classe pour un calcul de mecanique---------
+
+
+
+#ifndef BIELLETTETHERMI_H
+#define BIELLETTETHERMI_H
+
+#include "ParaGlob.h"
+#include "ElemThermi.h"
+//#include "Loi_comp_abstraite.h"
+#include "Met_abstraite.h"
+#include "Met_biellette.h"
+#include "Noeud.h"
+#include "UtilLecture.h"
+#include "Tenseur.h"
+#include "NevezTenseur.h"
+#include "Deformation.h"
+#include "ElFrontiere.h"
+#include "GeomSeg.h"
+#include "ParaAlgoControle.h"
+#include "FrontSegLine.h"
+#include "Section.h"
+
+class ConstrucElementbiel;
+
+/// @addtogroup groupe_des_elements_finis
+/// @{
+///
+
+
+class BielletteThermi : public ElemThermi
+{
+
+ public :
+
+ // CONSTRUCTEURS :
+ // Constructeur par defaut
+ BielletteThermi ();
+
+ // Constructeur fonction d'une section et eventuellement d'un numero
+ // d'identification et de maillage
+ BielletteThermi (double sect,int num_maill=0,int num_id=-3);
+
+ // Constructeur fonction d'un numero de maillage et d'identification
+ BielletteThermi (int num_maill,int num_id);
+
+ // Constructeur fonction d'une section, d'un numero de maillage et d'identification,
+ // du tableau de connexite des noeuds
+ BielletteThermi (double sect,int num_maill,int num_id,const Tableau& tab);
+
+ // Constructeur de copie
+ BielletteThermi (const BielletteThermi& biel);
+
+
+ // DESTRUCTEUR :
+ ~BielletteThermi ();
+
+ // création d'un élément de copie: utilisation de l'opérateur new et du constructeur de copie
+ // méthode virtuelle
+ Element* Nevez_copie() const { Element * el= new BielletteThermi(*this); return el;};
+
+ // Surcharge de l'operateur = : realise l'egalite entre deux instances de BielletteThermi
+ BielletteThermi& operator= (BielletteThermi& biel);
+
+ // METHODES :
+// 1) derivant des virtuelles pures
+ // Lecture des donnees de la classe sur fichier
+ void LectureDonneesParticulieres (UtilLecture *,Tableau * );
+
+ // Calcul du residu local et de la raideur locale,
+ // pour le schema implicite
+ Element::ResRaid Calcul_implicit (const ParaAlgoControle & pa);
+
+ // Calcul du residu local a t
+ // pour le schema explicit par exemple
+ Vecteur* CalculResidu_t (const ParaAlgoControle & pa)
+ { return BielletteThermi::CalculResidu(false,pa);};
+
+ // Calcul du residu local a tdt
+ // pour le schema explicit par exemple
+ Vecteur* CalculResidu_tdt (const ParaAlgoControle & pa)
+ { return BielletteThermi::CalculResidu(true,pa);};
+
+ // Calcul de la matrice masse pour l'élément
+ Mat_pleine * CalculMatriceMasse (Enum_calcul_masse id_calcul_masse) ;
+
+ // --------- calcul dynamique ---------
+ // calcul de la longueur d'arrête de l'élément minimal
+ // divisé par la célérité la plus rapide dans le matériau
+ double Long_arrete_mini_sur_c(Enum_dure temps)
+ { return ElemThermi::Interne_Long_arrete_mini_sur_c(temps);};
+
+ //------- calcul d'erreur, remontée des contraintes -------------------
+ // 1)calcul du résidu et de la matrice de raideur pour le calcul d'erreur
+ Element::Er_ResRaid ContrainteAuNoeud_ResRaid();
+ // 2) remontée aux erreurs aux noeuds
+ Element::Er_ResRaid ErreurAuNoeud_ResRaid();
+
+ // retourne les tableaux de ddl associés aux noeuds, gere par l'element
+ // ce tableau et specifique a l'element
+ const DdlElement & TableauDdl() const ;
+
+
+ // Libere la place occupee par le residu et eventuellement la raideur
+ // par l'appel de Libere de la classe mere et libere les differents tenseurs
+ // intermediaires cree pour le calcul et les grandeurs pointee
+ // de la raideur et du residu
+ void Libere ();
+
+ // acquisition d'une loi de comportement
+ void DefLoi (LoiAbstraiteGeneral * NouvelleLoi);
+
+ // test si l'element est complet
+ // = 1 tout est ok, =0 element incomplet
+ int TestComplet();
+
+ // procesure permettant de completer l'element apres
+ // sa creation avec les donnees du bloc transmis
+ // peut etre appeler plusieurs fois
+ Element* Complete(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD);
+ // Compléter pour la mise en place de la gestion de l'hourglass
+ Element* Complet_Hourglass(LoiAbstraiteGeneral * NouvelleLoi, const BlocGen & bloc) {return this;};
+
+ // ramene l'element geometrique
+ ElemGeomC0& ElementGeometrique() const { return doCo->segment;};
+ // ramene l'element geometrique en constant
+ const ElemGeomC0& ElementGeometrique_const() const { return doCo->segment;};
+
+ // calcul d'un point dans l'élément réel en fonction des coordonnées dans l'élément de référence associé
+ // temps: indique si l'on veut les coordonnées à t = 0, ou t ou tdt
+ // 1) cas où l'on utilise la place passée en argument
+ Coordonnee & Point_physique(const Coordonnee& c_int,Coordonnee & co,Enum_dure temps);
+ // 3) cas où l'on veut les coordonnées aux 1, 2 ou trois temps selon la taille du tableau t_co
+ void Point_physique(const Coordonnee& c_int,Tableau & t_co);
+
+ // -- connaissances particulières sur l'élément
+ // ramène l'épaisseur de l'élément
+ // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
+ virtual double Section(Enum_dure enu , const Coordonnee& ) {return S(enu);};
+ // ramène l'épaisseur moyenne de l'élément (indépendante du point)
+ // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
+ virtual double SectionMoyenne(Enum_dure enu ) {return S(enu);};
+
+ // affichage dans la sortie transmise, des variables duales "nom"
+ // dans le cas ou nom est vide, affichage de "toute" les variables
+ void AfficheVarDual(ofstream& sort, Tableau& nom);
+
+ // affichage d'info en fonction de ordre
+ // ordre = "commande" : affichage d'un exemple d'entree pour l'élément
+ void Info_com_Element(UtilLecture * entreePrinc,string& ordre,Tableau * tabMaillageNoeud)
+ { return Element::Info_com_El(2,entreePrinc,ordre,tabMaillageNoeud);};
+
+ // retourne un numero d'ordre d'un point le plus près ou est exprimé la grandeur enum
+ // par exemple un point d'intégration, mais n'est utilisable qu'avec des méthodes particulières
+ // par exemple CoordPtInteg, ou Valeur_a_diff_temps
+ // car le numéro d'ordre peut-être différent du numéro d'intégration au sens classique
+ // temps: dit si c'est à 0 ou t ou tdt
+ int PointLePlusPres(Enum_dure temps,Enum_ddl enu, const Coordonnee& M)
+ { return PtLePlusPres(temps,enu,M);};
+
+ // recuperation des coordonnées du point de numéro d'ordre iteg pour
+ // la grandeur enu
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee CoordPtInteg(Enum_dure temps,Enum_ddl enu,int iteg,bool& erreur)
+ { return CoordPtInt(temps,enu,iteg,erreur);};
+
+ // récupération des valeurs au numéro d'ordre = iteg pour
+ // les grandeur enu
+ Tableau Valeur_a_diff_temps(bool absolue,Enum_dure enu_t,const List_io& enu,int iteg) ;
+
+ // récupération des valeurs au numéro d'ordre = iteg pour les grandeurs enu
+ // ici il s'agit de grandeurs tensorielles, le retour s'effectue dans la liste
+ // de conteneurs quelconque associée
+ void ValTensorielle_a_diff_temps(bool absolue,Enum_dure enu_t,List_io& enu,int iteg);
+
+ // ramene vrai si la surface numéro ns existe pour l'élément
+ // dans le cas de la biellette il n'y a pas de surface
+ bool SurfExiste(int ) const
+ { return false;};
+
+ // ramene vrai si l'arête numéro na existe pour l'élément
+ bool AreteExiste(int na) const {if (na==1) return true; else return false;};
+
+
+ //============= lecture écriture dans base info ==========
+
+ // cas donne le niveau de la récupération
+ // = 1 : on récupère tout
+ // = 2 : on récupère uniquement les données variables (supposées comme telles)
+ void Lecture_base_info
+ (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas) ;
+ // cas donne le niveau de sauvegarde
+ // = 1 : on sauvegarde tout
+ // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
+ void Ecriture_base_info(ofstream& sort,const int cas) ;
+
+ // METHODES VIRTUELLES:
+ // --------- calculs utils dans le cadre de la recherche du flambement linéaire
+ // Calcul de la matrice géométrique et initiale
+ ElemThermi::MatGeomInit MatricesGeometrique_Et_Initiale (const ParaAlgoControle & pa) ;
+ // retourne la liste des données particulières actuellement utilisés
+ // par l'élément (actif ou non), sont exclu de cette liste les données particulières des noeuds
+ // reliés à l'élément
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ List_io Les_types_particuliers_internes(bool absolue) const;
+
+ // récupération de grandeurs particulières au numéro d'ordre = iteg
+ // celles-ci peuvent être quelconques
+ // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ void Grandeur_particuliere (bool absolue,List_io& liTQ,int iteg);
+
+ // inactive les ddl du problème primaire de mécanique
+ inline void Inactive_ddl_primaire()
+ {ElemThermi::Inact_ddl_primaire(doCo->tab_ddl);};
+ // active les ddl du problème primaire de mécanique
+ inline void Active_ddl_primaire()
+ {ElemThermi::Act_ddl_primaire(doCo->tab_ddl);};
+ // --------- calcul d'erreur, calculs du champs de Flux continu ---------
+
+ // ajout des ddl de flux pour les noeuds de l'élément
+ inline void Plus_ddl_Flux()
+ {ElemThermi::Ad_ddl_Flux(doCo->tab_ddlErr);};
+ // inactive les ddl du problème de recherche d'erreur : les flux
+ inline void Inactive_ddl_Flux()
+ {ElemThermi::Inact_ddl_Flux(doCo->tab_ddlErr);};
+ // active les ddl du problème de recherche d'erreur : les flux
+ inline void Active_ddl_Flux()
+ {ElemThermi::Act_ddl_Flux(doCo->tab_ddlErr);};
+ // active le premier ddl du problème de recherche d'erreur : SIGMA11
+ inline void Active_premier_ddl_Flux()
+ {ElemThermi::Act_premier_ddl_Flux();};
+
+ // lecture de données diverses sur le flot d'entrée
+ void LectureFlux(UtilLecture * entreePrinc)
+ {if (unefois.CalResPrem_t == 1)
+ ElemThermi::LectureDesFlux (false,entreePrinc,lesPtThermiInt.TabfluxH_t());
+ else
+ { ElemThermi::LectureDesFlux (true,entreePrinc,lesPtThermiInt.TabfluxH_t());
+ unefois.CalResPrem_t = 1;
+ };
+ };
+
+ // retour des flux en absolu retour true si elle existe sinon false
+ bool FluxAbsolues(Tableau & tabFlux)
+ { if (unefois.CalResPrem_t == 1)
+ ElemThermi::FluxEnAbsolues(false,lesPtThermiInt.TabfluxH_t(),tabFlux);
+ else
+ { unefois.CalResPrem_t = 1;
+ ElemThermi::FluxEnAbsolues(true,lesPtThermiInt.TabfluxH_t(),tabFlux);
+ };
+ return true;
+ };
+
+
+ // 2) derivant des virtuelles
+ // retourne un tableau de ddl element, correspondant à la
+ // composante de sigma -> SIG11, pour chaque noeud qui contiend
+ // des ddl de contrainte
+ // -> utilisé pour l'assemblage de la raideur d'erreur
+ inline DdlElement& Tableau_de_Flux1() const
+ {return doCo->tab_Err1FLUX;} ;
+
+ // actualisation des ddl et des grandeurs actives de t+dt vers t
+ void TdtversT();
+ // actualisation des ddl et des grandeurs actives de t vers tdt
+ void TversTdt();
+
+ // calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+ // qu'une fois la remontée aux contraintes effectuées sinon aucune
+ // action. En retour la valeur de l'erreur sur l'élément
+ // type indique le type de calcul d'erreur :
+ void ErreurElement(int type,double& errElemRelative
+ ,double& numerateur, double& denominateur);
+
+ // mise à jour de la boite d'encombrement de l'élément, suivant les axes I_a globales
+ // en retour coordonnées du point mini dans retour.Premier() et du point maxi dans .Second()
+ // la méthode est différente de la méthode générale car il faut prendre en compte l'épaisseur de l'élément
+ virtual const DeuxCoordonnees& Boite_encombre_element(Enum_dure temps);
+
+ // calcul des seconds membres suivant les chargements
+ // cas d'un chargement volumique,
+ // force indique la force volumique appliquée
+ // retourne le second membre résultant
+ // ici on l'épaisseur de l'élément pour constituer le volume
+ // -> explicite à t
+ Vecteur SM_charge_volumique_E_t(const Coordonnee& force,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_volumique_E(force,false,pa);} ;
+ // -> explicite à tdt
+ Vecteur SM_charge_volumique_E_tdt(const Coordonnee& force,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_volumique_E(force,true,pa);} ;
+ // -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ ResRaid SMR_charge_volumique_I(const Coordonnee& force,const ParaAlgoControle & pa) ;
+
+ // cas d'un chargement lineique, sur les aretes frontières des éléments
+ // force indique la force lineique appliquée
+ // numarete indique le numéro de l'arete chargée
+ // retourne le second membre résultant
+ // -> explicite à t
+ Vecteur SM_charge_lineique_E_t(const Coordonnee& force,int numArete,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_lineique_E(force,numArete,false,pa);} ;
+ // -> explicite à tdt
+ Vecteur SM_charge_lineique_E_tdt(const Coordonnee& force,int numArete,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_lineique_E(force,numArete,true,pa);} ;
+ // -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ ResRaid SMR_charge_lineique_I(const Coordonnee& force,int numArete,const ParaAlgoControle & pa) ;
+
+ // cas d'un chargement lineique suiveuse, sur l'arrête frontière de
+ // la biellette (2D uniquement)
+ // force indique la force lineique appliquée
+ // numarete indique le numéro de l'arete chargée
+ // retourne le second membre résultant
+ // -> explicite à t
+ Vecteur SM_charge_lineique_Suiv_E_t(const Coordonnee& force,int numArete,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_lineique_Suiv_E(force,numArete,false,pa);} ;
+ // -> explicite à tdt
+ Vecteur SM_charge_lineique_Suiv_E_tdt(const Coordonnee& force,int numArete,const ParaAlgoControle & pa)
+ { return BielletteThermi::SM_charge_lineique_Suiv_E(force,numArete,true,pa);} ;
+ // -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ ResRaid SMR_charge_lineique_Suiv_I(const Coordonnee& force,int numArete,const ParaAlgoControle & pa) ;
+
+ // cas d'un chargement surfacique hydro-dynamique,
+ // Il y a trois forces: une suivant la direction de la vitesse: de type traînée aerodynamique
+ // Fn = poids_volu * fn(V) * S * (normale*u) * u, u étant le vecteur directeur de V (donc unitaire)
+ // une suivant la direction normale à la vitesse de type portance
+ // Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire, normal à V, et dans le plan n et V
+ // une suivant la vitesse tangente de type frottement visqueux
+ // T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
+ // coef_mul: est un coefficient multiplicateur global (de tout)
+ // retourne le second membre résultant
+ // -> explicite à t
+ Vecteur SM_charge_hydrodynamique_E_t( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int numFace,const double& coef_mul
+ , Courbe1D* coef_aero_t,const ParaAlgoControle & pa)
+ {return SM_charge_hydrodynamique_E(frot_fluid,poidvol,coef_aero_n,numFace,coef_mul,coef_aero_t,false,pa);};
+ // -> explicite à tdt
+ Vecteur SM_charge_hydrodynamique_E_tdt( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int numFace,const double& coef_mul
+ , Courbe1D* coef_aero_t,const ParaAlgoControle & pa)
+ {return SM_charge_hydrodynamique_E(frot_fluid,poidvol,coef_aero_n,numFace,coef_mul,coef_aero_t,true,pa);};
+ // -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ ResRaid SMR_charge_hydrodynamique_I( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int numFace,const double& coef_mul
+ , Courbe1D* coef_aero_t,const ParaAlgoControle & pa) ;
+
+
+ // ========= définition et/ou construction des frontières ===============
+
+ // 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
+ Tableau const & Frontiere(bool force = false);
+
+
+
+ // Retourne la section de l'element
+ inline double S(Enum_dure enu = TEMPS_tdt)
+ { switch (enu)
+ { case TEMPS_0: return donnee_specif.secti.section0; break;
+ case TEMPS_t: return donnee_specif.secti.section_t; break;
+ case TEMPS_tdt: return donnee_specif.secti.section_tdt; break;
+ };
+ return 0.; // cas n'arrivant normalement jamais
+ };
+
+
+
+ // ajout du tableau specific de ddl des noeuds de la biellette
+ // la procedure met a jour les ddl(relatif a l'element, c-a-d Xi)
+ // des noeuds constituants l'element
+ void ConstTabDdl();
+ protected:
+
+ // ==== >>>> methodes virtuelles dérivant d'ElemThermi ============
+ // ramene la dimension des vecteurs flux et gradient de température de l'élément
+ int Dim_flux_gradT() const {return 1;};
+
+ // -------------------- calcul de frontières en protected -------------------
+
+ // --- fonction nécessaire pour la construction des Frontières linéiques ou surfaciques particulière à l'élément
+ // adressage des frontières linéiques et surfacique
+ // définit dans les classes dérivées, et utilisées pour la construction des frontières
+ virtual ElFrontiere* new_frontiere_lin(int ,Tableau & tab, DdlElement& ddelem)
+ { return ((ElFrontiere*) (new FrontSegLine(tab,ddelem)));};
+ virtual ElFrontiere* new_frontiere_surf(int ,Tableau & tab, DdlElement& ddelem)
+ {return NULL;} // il n'y a pas de surface possible
+
+
+ private :
+
+ // VARIABLES PRIVEES :
+
+
+ class DonneeCommune
+ { public :
+ DonneeCommune (GeomSeg& seg,DdlElement& tab,DdlElement& tabErr,DdlElement& tab_Err1FLUX,
+ Met_biellette& met_bie,
+ Tableau & resEr,Mat_pleine& raidEr,
+ GeomSeg& seEr,Vecteur& residu_int,Mat_pleine& raideur_int,
+ Tableau & residus_extN,Tableau & raideurs_extN,
+ Tableau & residus_extA,Tableau & raideurs_extA,
+ Mat_pleine& mat_masse ,GeomSeg& seMa,int nbi
+ ) ;
+ DonneeCommune(DonneeCommune& a);
+ ~DonneeCommune();
+ // variables
+ GeomSeg segment ; // element geometrique correspondant
+ DdlElement tab_ddl; // tableau des degres
+ //de liberte des noeuds de l'element commun a tous les
+ // elements: ici de thermique
+ Met_biellette met_biellette;
+ Mat_pleine matGeom ; // matrice géométrique
+ Mat_pleine matInit ; // matrice initile
+ Tableau d_gradTB; // place pour la variation du gradient
+ Tableau d_fluxH; // place pour la variation du flux
+ Tableau < Tableau2 * > d2_gradTB; // variation seconde des déformations
+ // calcul d'erreur
+ DdlElement tab_ddlErr; // tableau des degres servant pour le calcul
+ // d'erreur : contraintes
+ DdlElement tab_Err1FLUX; // tableau du ddl FLUX pour chaque noeud,
+ //servant pour le calcul d'erreur : contraintes, en fait pour l'assemblage
+ Tableau resErr; // residu pour le calcul d'erreur
+ Mat_pleine raidErr; // raideur pour le calcul d'erreur
+ GeomSeg segmentEr; // contiend les fonctions d'interpolation et
+ // les derivees pour le calcul du hessien dans
+ //la résolution de la fonctionnelle d'erreur
+ // -------- calcul de résidus, de raideur : interne ou pour les efforts extérieurs ----------
+ // on utilise des pointeurs pour optimiser la place (même place pointé éventuellement)
+ Vecteur residu_interne;
+ Mat_pleine raideur_interne;
+ Tableau residus_externeN; // pour les noeuds
+ Tableau raideurs_externeN; // pour les noeuds
+ Tableau residus_externeA; // pour l' aretes
+ Tableau raideurs_externeA; // pour l' aretes
+ // ------ données concernant la dynamique --------
+ Mat_pleine matrice_masse;
+ GeomSeg segmentMas; // contiend les fonctions d'interpolation et les dérivées
+ // pour les calculs relatifs au calcul de la masse
+ };
+
+
+ // classe contenant tous les indicateurs statique qui sont modifiés une seule fois
+ // et un pointeur sur les données statiques communes
+ // la classe est interne, toutes les variables sont publique. Un pointeur sur une instance de la
+ // classe est défini. Son allocation est effectuée dans les classes dérivées
+ class UneFois
+ { public :
+ UneFois () ; // constructeur par défaut
+ ~UneFois () ; // destructeur
+
+ // VARIABLES :
+ public :
+ DonneeCommune * doCoMemb;
+
+ // incicateurs permettant de dimensionner seulement au premier passage
+ // utilise dans "CalculResidu" et "Calcul_implicit"
+ int CalResPrem_t; int CalResPrem_tdt; // à t ou à tdt
+ int CalimpPrem;
+ int dualSortbiel; // pour la sortie des valeurs au pt d'integ
+ int CalSMlin_t; // pour les seconds membres concernant les arretes
+ int CalSMlin_tdt; // pour les seconds membres concernant les arretes
+ int CalSMRlin; // pour les seconds membres concernant les arretes
+ int CalSMvol_t; // pour les seconds membres concernant les volumes
+ int CalSMvol_tdt; // pour les seconds membres concernant les volumes
+ int CalSMvol; // pour les seconds membres concernant les volumes
+ int CalDynamique; // pour le calcul de la matrice de masse
+ int CalPt_0_t_tdt; // pour le calcul de point à 0 t et tdt
+ // ---------- sauvegarde du nombre d'élément en cours --------
+ int nbelem_in_Prog;
+ };
+
+
+ // ------------------------------------------------------------------------------------
+
+ protected :
+ // VARIABLES PROTÉGÉES :
+ // les données spécifiques sont grouppées dans une structure pour sécuriser
+ // le passage de paramètre dans init par exemple
+ class Donnee_specif
+ { public :
+ Donnee_specif() : // défaut
+ secti(Element::section_defaut,Element::section_defaut,Element::section_defaut)
+ ,variation_section(true)
+ {};
+ Donnee_specif(double section) : // uniquement la section
+ secti(section,section,section),variation_section(true)
+ {};
+ Donnee_specif(double epai0,double epai_t,double epai_tdt,bool variation) : // tous
+ secti(epai0,epai_t,epai_tdt),variation_section(variation)
+ {};
+ Donnee_specif(const Donnee_specif& a) :
+ secti(a.secti ),variation_section(a.variation_section)
+ {}; // recopie via le constructeur de copie
+ ~Donnee_specif() {};
+ Donnee_specif & operator = ( const Donnee_specif& a)
+ { secti = a.secti;variation_section=a.variation_section;
+ return *this;};
+ // data
+ // sections de l'element
+ Sect secti; // épaisseur
+ bool variation_section; // permet éventuellement de ne pas prendre en compte la variation
+ };
+ Donnee_specif donnee_specif;
+
+ // grandeurs aux points d'intégration: contraintes, déformations, vitesses de def etc.
+ LesPtIntegThermiInterne lesPtThermiInt;
+
+ // place memoire commune a tous les elements biellettes
+ static DonneeCommune * doCo;
+ // idem mais pour les indicateurs qui servent pour l'initialisation
+ static UneFois unefois;
+
+ // type structuré pour construire les éléments
+ class NombresConstruire
+ { public:
+ NombresConstruire();
+ int nbne; // le nombre de noeud de l'élément
+ int nbneA ; // le nombre de noeud des aretes
+ int nbi; // le nombre de point d'intégration pour le calcul mécanique
+ int nbiEr; // le nombre de point d'intégration pour le calcul d'erreur
+ int nbiA; // le nombre de point d'intégration pour le calcul de second membre linéique
+ int nbiMas; // le nombre de point d'intégration pour le calcul de la matrice masse consistante
+ };
+ static NombresConstruire nombre_V; // les nombres propres à l'élément
+
+ // fonction privee
+ // fonction d'initialisation servant au niveau du constructeur
+ BielletteThermi::DonneeCommune * Init(Donnee_specif donnee_specif = Donnee_specif()
+ ,bool sans_init_noeud = false);
+ void Def_DonneeCommune();
+ // destructions de certaines grandeurs pointées, créées au niveau de l'initialisation
+ void Destruction();
+
+ // pour l'ajout d'element dans la liste : listTypeElemen, geree par la class Element
+ class ConstrucElementbiel : public ConstrucElement
+ { public : ConstrucElementbiel ()
+ { NouvelleTypeElement nouv(POUT,BIE1,THERMIQUE,this);
+ if (ParaGlob::NiveauImpression() >= 4)
+ cout << "\n initialisation BielletteThermi" << endl;
+ Element::listTypeElement.push_back(nouv);
+ };
+ Element * NouvelElement(int nb_mail,int num) // un nouvel élément sans rien
+ {Element * pt;
+ pt = new BielletteThermi (nb_mail,num) ;
+ return pt;};
+ // ramene true si la construction de l'element est possible en fonction
+ // des variables globales actuelles: ex en fonction de la dimension
+ bool Element_possible() {return true;};
+ };
+ static ConstrucElementbiel construcElementbiel;
+
+ // Calcul du residu local a t ou tdt en fonction du booleen
+ Vecteur* CalculResidu (bool atdt,const ParaAlgoControle & pa);
+ // calcul des seconds membres suivant les chargements
+ // cas d'un chargement volumique,
+ // force indique la force volumique appliquée
+ // retourne le second membre résultant
+ // ici on l'épaisseur de l'élément pour constituer le volume
+ // -> explicite à t ou tdt en fonction de la variable booleenne atdt
+ Vecteur SM_charge_volumique_E
+ (const Coordonnee& force,bool atdt,const ParaAlgoControle & pa);
+ // cas d'un chargement lineique, sur les aretes frontières des éléments
+ // force indique la force lineique appliquée
+ // numarete indique le numéro de l'arete chargée
+ // retourne le second membre résultant
+ // -> explicite à t ou tdt en fonction de la variable booleenne atdt
+ Vecteur SM_charge_lineique_E
+ (const Coordonnee& force,int numArete,bool atdt,const ParaAlgoControle & pa);
+ // cas d'un chargement lineique suiveuse, sur l'arete frontière
+ //de la biellette (2D uniquement)
+ // force indique la force lineique appliquée
+ // numarete indique le numéro de l'arete chargée
+ // retourne le second membre résultant
+ // -> explicite à t
+ Vecteur SM_charge_lineique_Suiv_E
+ (const Coordonnee& force,int numArete,bool atdt,const ParaAlgoControle & pa);
+ // cas d'un chargement surfacique hydro-dynamique,
+ // voir méthode explicite plus haut, pour les arguments
+ // retourne le second membre résultant
+ // bool atdt : permet de spécifier à t ou a t+dt
+ Vecteur SM_charge_hydrodynamique_E( Courbe1D* frot_fluid,const double& poidvol
+ , Courbe1D* coef_aero_n,int numFace,const double& coef_mul
+ , Courbe1D* coef_aero_t,bool atdt,const ParaAlgoControle & pa) ;
+ // calcul de la nouvelle section moyenne finale (sans raideur)
+ // mise à jour des volumes aux pti
+ // ramène la section moyenne calculée à atdt
+ const double& CalSectionMoyenne_et_vol_pti(const bool atdt);
+
+};
+/// @} // end of group
+
+#endif
+
+
+
+
diff --git a/Elements/Thermique/ElemThermi.cc b/Elements/Thermique/ElemThermi.cc
new file mode 100755
index 0000000..338524b
--- /dev/null
+++ b/Elements/Thermique/ElemThermi.cc
@@ -0,0 +1,1899 @@
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+//#include "Debug.h"
+#include
+#include "ElemThermi.h"
+#include
+#include "ConstMath.h"
+#include "Util.h"
+#include "Coordonnee2.h"
+#include "Coordonnee3.h"
+#include "ParaAlgoControle.h"
+#include "ExceptionsElemThermi.h"
+#include "Loi_Umat.h"
+
+// =========================== variables communes ===============================
+// a priori les pointeurs de fonction pointent sur rien au debut
+const Coordonnee & (Met_abstraite::*(ElemThermi::PointM))
+ (const Tableau& tab_noeud,const Vecteur& Phi) ;
+void (Met_abstraite::*(ElemThermi::BaseND))
+ (const Tableau& tab_noeud,const Mat_pleine& dphi,
+ const Vecteur& phi,BaseB& bB,BaseH& bH);
+int ElemThermi::bulk_viscosity = 0; // indique si oui ou non on utilise le bulk viscosity
+double ElemThermi::c_traceBulk = 0.; // coeff de la trace de D pour le bulk
+double ElemThermi::c_carreBulk = 0.; // coeff du carré de la trace de D pour le bulk
+TenseurHH* ElemThermi::sig_bulkHH = NULL; // variable de travail pour le bulk
+// ---------- pour le calcul de la masse pour la méthode de relaxation dynamique
+Ddl_enum_etendu ElemThermi::masse_relax_dyn; // au début rien, def à la première utilisation
+
+// =========================== fin variables communes ===========================
+
+ElemThermi::ElemThermi () :
+Element(),tabSaveDon(),tabSaveTP(),tabSaveDefDon(),defSurf(),defArete()
+,masse_volumique(masse_volumique_defaut),dilatation(false),tab_energ(),tab_energ_t(),energie_totale()
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,premier_calcul_thermi_impli_expli(true),lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+// Constructeur par defaut
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (int num_mail,int num_id) :
+Element(num_mail,num_id),tabSaveDon(),tabSaveTP(),tabSaveDefDon(),defSurf(),defArete()
+,masse_volumique(masse_volumique_defaut),dilatation(false),tab_energ(),tab_energ_t(),energie_totale()
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,premier_calcul_thermi_impli_expli(true)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+// Constructeur utile quand le numero d'identification de l'element est connu
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (int num_mail,int num_id,const Tableau& tab):
+// Constructeur utile quand le numero et le tableau des noeuds
+// de l'element sont connu
+Element(num_mail,num_id,tab)
+,tabSaveDon(),tabSaveTP(),tabSaveDefDon(),defSurf(),defArete()
+,masse_volumique(masse_volumique_defaut),dilatation(false),tab_energ(),tab_energ_t(),energie_totale()
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,premier_calcul_thermi_impli_expli(true)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+
+ElemThermi::ElemThermi (int num_mail,int num_id,Enum_interpol id_interp_elt,Enum_geom id_geom_elt,string info):
+// Constructeur utile quand le numero d'identification est connu,
+// ainsi que la geometrie et le type d'interpolation de l'element
+Element (num_mail,num_id,id_interp_elt,id_geom_elt,THERMIQUE,info)
+,tabSaveDon(),tabSaveTP(),tabSaveDefDon()
+,defSurf(),defArete(),masse_volumique(masse_volumique_defaut),dilatation(false)
+,tab_energ(),tab_energ_t(),energie_totale()
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,premier_calcul_thermi_impli_expli(true)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (int num_mail,int num_id,char* nom_interpol,char* nom_geom,string info):
+// Constructeur utile quand le numero d'identification est connu,
+// ainsi que la geometrie et le type d'interpolation de l'element
+Element(num_mail,num_id,nom_interpol,nom_geom,NomElemTypeProblem(THERMIQUE),info)
+,tabSaveDon()
+,tabSaveTP(),tabSaveDefDon(),defSurf(),defArete(),masse_volumique(masse_volumique_defaut),dilatation(false)
+,tab_energ(),tab_energ_t(),energie_totale(),premier_calcul_thermi_impli_expli(true)
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (int num_mail,int num_id,const Tableau& tab,Enum_interpol id_interp_elt,
+ Enum_geom id_geom_elt,string info):
+// Constructeur utile quand toutes les donnees sont connues
+Element (num_mail,num_id,tab,id_interp_elt,id_geom_elt,THERMIQUE,info)
+,tabSaveDon(),tabSaveTP()
+,tabSaveDefDon(),defSurf(),defArete(),masse_volumique(masse_volumique_defaut),dilatation(false)
+,tab_energ(),tab_energ_t(),energie_totale(),premier_calcul_thermi_impli_expli(true)
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (int num_mail,int num_id,const Tableau& tab,char* nom_interpol,
+ char* nom_geom,string info):
+// Constructeur utile quand toutes les donnees sont connues
+Element (num_mail,num_id,tab,nom_interpol,nom_geom,NomElemTypeProblem(THERMIQUE),info)
+,tabSaveDon()
+,tabSaveTP(),tabSaveDefDon(),defSurf(),defArete(),masse_volumique(masse_volumique_defaut),dilatation(false)
+,tab_energ(),tab_energ_t(),energie_totale(),premier_calcul_thermi_impli_expli(true)
+,E_elem_bulk_t(0.),E_elem_bulk_tdt(0.),P_elem_bulk(0.)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(STABHOURGLASS_NON_DEFINIE),tab_elHourglass()
+,coefStabHourglass(0.),raid_hourglass_transitoire(NULL)
+{ loiComp = NULL;loiTP=NULL;loiFrot=NULL;
+ met = NULL;
+ def = NULL;
+ defEr = NULL;
+ defMas = NULL;
+ fluxErreur = NULL;
+ id_problem = THERMIQUE;
+};
+
+ElemThermi::ElemThermi (const ElemThermi& elt):
+// Constructeur de copie
+Element (elt),defSurf(elt.defSurf),defArete(elt.defArete)
+,masse_volumique(elt.masse_volumique),dilatation(elt.dilatation)
+,tab_energ(elt.tab_energ),tab_energ_t(elt.tab_energ_t),energie_totale(elt.energie_totale)
+,E_elem_bulk_t(elt.E_elem_bulk_t),E_elem_bulk_tdt(elt.E_elem_bulk_tdt),P_elem_bulk(elt.P_elem_bulk)
+,premier_calcul_thermi_impli_expli(true)
+,lesPtIntegThermiInterne(NULL)
+,type_stabHourglass(elt.type_stabHourglass),tab_elHourglass()
+,coefStabHourglass(elt.coefStabHourglass),raid_hourglass_transitoire(NULL)
+{ // pour la loi on pointe sur la même que l'élément de référence, car de toute
+ // la loi ne contient pas les données spécifique
+ loiComp = (elt.loiComp);loiTP = (elt.loiTP);loiFrot = (elt.loiFrot);
+ // idem pour la métrique qui est a priori une métrique générique
+ met = (elt.met);
+ id_problem = THERMIQUE;
+ // la déformation est spécifique à l'élément
+ if (elt.def!=NULL) def = elt.def->Nevez_deformation(tab_noeud); // *def = *(elt.def);
+ if (elt.defEr!=NULL) defEr = elt.defEr->Nevez_deformation(tab_noeud); //*defEr = *(elt.defEr);
+ if (elt.defMas!=NULL) defMas = elt.defMas->Nevez_deformation(tab_noeud); //*defMas = *(elt.defMas);
+ // les données spécifiques à la déformation mécanique
+ int idefdtr = (elt.tabSaveDefDon).Taille();
+ tabSaveDefDon.Change_taille(idefdtr);
+ for (int i=1;i<= idefdtr; i++)
+ { tabSaveDefDon(i) = def->New_et_Initialise();
+ if (tabSaveDefDon(i)!= NULL) *tabSaveDefDon(i) = *(elt.tabSaveDefDon)(i);
+ }
+ // def: cas des arrêtes et des faces si besoin
+ int tailledefSurf = defSurf.Taille();
+ int itab = 1; // indice pour parcourir tabb
+ for (int idsu =1;idsu<=tailledefSurf;idsu++,itab++)
+ {if (defSurf(idsu) != NULL)
+ defSurf(idsu) = elt.defSurf(idsu)->Nevez_deformation(tabb(itab)->TabNoeud());}
+ int tailledefArete = defArete.Taille();
+ for (int idA =1;idA<=tailledefArete;idA++)
+ {if (defArete(idA) != NULL)
+ defArete(idA) = elt.defArete(idA)->Nevez_deformation(tabb(itab)->TabNoeud());}
+ // les donnees de la loi de comportement mécanique
+ int dtr = (elt.tabSaveDon).Taille();
+ tabSaveDon.Change_taille(dtr);
+ for (int i=1;i<= dtr; i++)
+ { tabSaveDon(i) = loiComp->New_et_Initialise();
+ if (tabSaveDon(i)!= NULL) *tabSaveDon(i) = *(elt.tabSaveDon)(i);
+ }
+ // les donnees de la loi de comportement thermo physique
+ int dtrTP = (elt.tabSaveTP).Taille();
+ tabSaveTP.Change_taille(dtrTP);
+ for (int i=1;i<= dtrTP; i++)
+ { tabSaveTP(i) = NULL; // init
+ if (loiTP != NULL ) tabSaveTP(i) = loiTP->New_et_Initialise();
+ if (tabSaveTP(i)!= NULL) *tabSaveTP(i) = *(elt.tabSaveTP)(i);
+ }
+ // et autre
+ if (elt.fluxErreur != NULL)
+ { fluxErreur = new double;
+ fluxErreur = elt.fluxErreur;
+ }
+ else
+ fluxErreur = NULL;
+
+};
+
+ElemThermi::~ElemThermi ()
+// Destructeur
+{ // les donnees pour la loi de comportement mécanique
+ int imaxi = tabSaveDon.Taille();
+ for (int i=1;i<=imaxi; i++)
+ if (tabSaveDon(i) != NULL) {delete tabSaveDon(i) ; tabSaveDon(i)=NULL;}
+ // les donnees pour la loi de comportement thermo physique
+ int imaxTP = tabSaveTP.Taille();
+ for (int i=1;i<=imaxTP; i++)
+ if (tabSaveTP(i) != NULL) {delete tabSaveTP(i) ; tabSaveTP(i)=NULL;}
+ // les donnees à la déformation mécanique
+ int idefmaxi = tabSaveDefDon.Taille();
+ for (int i=1;i<=idefmaxi; i++)
+ if (tabSaveDefDon(i) != NULL) {delete tabSaveDefDon(i) ; tabSaveDefDon(i)=NULL;}
+ // les déformations sont spécifiquent aux elements, on les detruits si necessaire
+ if (def != NULL) { delete def; def = NULL;}
+ if (defEr != NULL) {delete defEr; defEr = NULL;}
+ if (defMas != NULL) {delete defMas; defMas = NULL;}
+ int nbdefSurf = defSurf.Taille();
+ for (int i = 1; i<= nbdefSurf; i++)
+ if (defSurf(i) != NULL) {delete defSurf(i); defSurf(i) = NULL;}
+ int nbdefArete = defArete.Taille();
+ for (int i = 1; i<= nbdefArete; i++)
+ if (defArete(i) != NULL) {delete defArete(i);defArete(i) = NULL;}
+ // par contre la metrique et la loi de comportement sont communes a une classe d'element
+ // donc ici met et loicomp ne sont que des pointeurs dont il ne faut pas supprimer les objets
+ // pointes
+ if (fluxErreur!= NULL) {delete fluxErreur; fluxErreur = NULL;}
+ // cas des éléments de stabilisation d'hourglass
+ if (tab_elHourglass.Taille() != 0)
+ { int taillhour = tab_elHourglass.Taille();
+ for (int i=1;i<= taillhour;i++)
+ { if (tab_elHourglass(i) != NULL) delete tab_elHourglass(i);};
+ };
+ if (raid_hourglass_transitoire != NULL) delete raid_hourglass_transitoire;
+};
+
+// =========================== methodes publiques ===============================
+
+// calcul si un point est a l'interieur de l'element ou non
+// il faut que M est la dimension globale
+// les trois fonctions sont pour l'etude a t=0, t et tdt
+// retour : =0 le point est externe, =1 le point est interne ,
+// = 2 le point est sur la frontière à la précision près
+// coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées,
+// uniquement précises si le point est interne
+// dans le cas où l'on veut un fonctionnement différent, c'est surchargé dans les
+// éléments fils
+int ElemThermi::Interne_0(const Coordonnee& M,Coordonnee* coor_locales)
+ { PointM = &Met_abstraite::PointM_0;
+ BaseND = &Met_abstraite::BaseND_0;
+ return Interne(TEMPS_0,M,coor_locales);
+ };
+int ElemThermi::Interne_t(const Coordonnee& M,Coordonnee* coor_locales)
+ { PointM = &Met_abstraite::PointM_t;
+ BaseND = &Met_abstraite::BaseND_t;
+ return Interne(TEMPS_t,M,coor_locales);
+ };
+int ElemThermi::Interne_tdt(const Coordonnee& M,Coordonnee* coor_locales)
+ { PointM = &Met_abstraite::PointM_tdt;
+ BaseND = &Met_abstraite::BaseND_tdt;
+ return Interne(TEMPS_tdt,M,coor_locales);
+ };
+
+// test si l'element est complet
+int ElemThermi::TestComplet()
+ { int ret = Element::TestComplet(); // teste de la class mere
+ if (loiTP == NULL)
+ { cout << " \n la loi thermo physique n'est pas defini dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ else if (loiTP->TestComplet() != 1)
+ { cout << " \n la loi thermo physique n'est pas complete dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ // dans le cas d'une loi thermo physique avec une partie mécanique on vérifie qu'elle est complète
+ if (loiComp != NULL)
+ { if (loiComp->TestComplet() != 1)
+ { cout << " \n la loi thermo physique n'est pas complete dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ };
+ // dans le cas d'une loi de frottement on vérifie qu'elle est complète
+ if (loiFrot != NULL)
+ { if (loiFrot->TestComplet() != 1)
+ { cout << " \n la loi de frottement n'est pas complete dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ };
+ // suite des datas
+ if ( masse_volumique == masse_volumique_defaut)
+ { cout << "\n la masse volumique n'est pas defini dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ if (met == NULL)
+ { cout << " \n la metrique n'est pas defini dans l element " << num_elt << '\n';
+ ret = 0;
+ }
+ if (def == NULL)
+ { cout << " \n le type de deformation n'est pas defini dans l element "
+ << num_elt << '\n';
+ ret = 0;
+ }
+ return ret;
+ };
+
+// test pour savoir si le calcul de contrainte en absolu est possible
+bool ElemThermi::FluxAbsoluePossible()
+ { // il faut qu'il soit complet et il faut que les coordonnées a t =0 et t existe
+ bool retour = true;
+ if (TestComplet() !=0)
+ {// on regarde la définition des coordonnées
+ int nbmaxnoeud=tab_noeud.Taille();
+ for (int i=1;i<=nbmaxnoeud;i++)
+ if((!tab_noeud(i)->ExisteCoord0())||(!tab_noeud(i)->ExisteCoord1()))
+ { retour = false; break;}
+ }
+ else
+ retour = false;
+ return retour;
+ };
+
+
+ // --------- calculs utils dans le cadre de la recherche du flambement linéaire
+// dans un premier temps uniquement virtuelles, ensuite se sera virtuelle pure pour éviter
+// les oubli de définition ----> AMODIFIER !!!!!!!!
+ // Calcul de la matrice géométrique et initiale
+ElemThermi::MatGeomInit ElemThermi::MatricesGeometrique_Et_Initiale (const ParaAlgoControle & )
+ { cout << "\n attention le calcul de la matrice g\'eom\'etrique et de la matrice "
+ << " initiale ne sont pas implant\'ees \n" ;
+ this->Affiche(1);
+ cout << "\nvoid ElemThermi::MatricesGeometrique_Et_Initiale (Mat_pleine &,Mat_pleine &)"
+ << endl;
+ Sortie(1);
+ return MatGeomInit(NULL,NULL); // pour supprimer le warning
+ };
+
+// calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+// qu'une fois la remontée aux contraintes effectuées sinon aucune
+// action. En retour la valeur de l'erreur sur l'élément
+// = 1 : erreur = (int (delta flux).(delta flux) dv)/(int flux*flux dv)
+// le numerateur et le denominateur sont tel que :
+// errElemRelative = numerateur / denominateur , si denominateur different de 0
+// sinon denominateur = numerateur si numerateur est different de 0, sinon
+// tous sont nuls mais on n'effectue pas la division
+ //!!!!!!!!!!!!! pour l'instant en virtuelle il faudra après en
+ // virtuelle pure !!!!!!!!!!!!!!!!!!!!!!!!!!! donc le code est à virer
+void ElemThermi::ErreurElement(int ,double& ,double& , double& )
+ { cout << "\n attention le calcul de l'erreur sur l'element n'est pas implant\'e "
+ << " pour cet element \n" ;
+ this->Affiche(1);
+ cout << "\nElemThermi::ErreurElement(int....."
+ << endl;
+ Sortie(1);
+ };
+
+// ajout des ddl d'erreur pour les noeuds de l'élément
+void ElemThermi::Plus_ddl_Erreur()
+ {int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++) // pour chaque noeud
+ { Ddl ddl(ERREUR,0.,LIBRE);
+ tab_noeud(ne)->PlusDdl(ddl);
+ }
+ };
+// inactive les ddl d'erreur
+void ElemThermi::Inactive_ddl_Erreur()
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_hors_service(ERREUR);
+ };
+// active les ddl d'erreur
+void ElemThermi::Active_ddl_Erreur()
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_en_service(ERREUR);
+ };
+// retourne un tableau de ddl element, correspondant à la
+// composante d'erreur -> ERREUR, pour chaque noeud
+// -> utilisé pour l'assemblage de la raideur d'erreur
+//dans cette version tous les noeuds sont supposés avoi un ddl erreur
+// dans le cas contraire il faut redéfinir la fonction dans l'élément terminal
+DdlElement ElemThermi::Tableau_de_ERREUR() const
+ { return DdlElement(tab_noeud.Taille(), DdlNoeudElement(ERREUR) );
+ };
+
+// =========================== methodes protegees ===============================
+
+
+// calcul si un point est a l'interieur de l'element ou non
+// il faut que M est la dimension globale
+// retour : =0 le point est externe, =1 le point est interne ,
+// = 2 le point est sur la frontière à la précision près
+// coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées,
+
+int ElemThermi::Interne(Enum_dure temps,const Coordonnee& M,Coordonnee* coor_locales)
+ { int dim_glob = M.Dimension(); // dim de M = dim de l'espace géométrique
+ ElemGeomC0& elgeom = this->ElementGeometrique(); // la geometrie
+ int dim_loc = elgeom.Dimension(); // dim de l'élément de référence
+ #ifdef MISE_AU_POINT
+ if (ParaGlob::Dimension() != dim_glob)
+ { cout << "\n *** erreur, la dimension du point = (" << dim_glob
+ << ") et de l'espace geometrique (" << ParaGlob::Dimension() << ") sont differentes! ";
+ cout << "\nElemThermi::Interne(Coordonnee& M) " << endl;
+ this->Affiche();
+ Sortie(1);
+ }
+ #endif
+ // la methode consiste tout d'abord a calculer les coordonnees locales correspondants
+ // a M. Pour cela on utilise un processus iteratif
+ // ---- 1 :init de la recherche
+ const Coordonnee refL(dim_loc) ; // coordonnees locales du point de reference, initialisees a zero
+ // - construction du point local en fonction de l'existance ou non de coor_locales
+ Coordonnee* pt_ret=NULL; Coordonnee theta_local(refL);
+ if (coor_locales != NULL) {pt_ret = coor_locales;} else {pt_ret = &theta_local;};
+ Coordonnee& theta = *pt_ret; // init de AL qui representera les coordonnes locales de M
+ // - fin construction du point local
+ Vecteur ph_i = elgeom.Phi(refL); // fonctions d'interpolation en refL
+ Mat_pleine dph_i = elgeom.Dphi(refL); // derivees des fonctions d'interpolation en refL
+ // l'image de theta par l'interpolation, de dimension : espace géométrique
+ Coordonnee A = (met->*PointM) (tab_noeud,ph_i); //
+ // calcul de la base naturelle et duale en refL, en fonction des coord a t
+ BaseB bB(dim_glob,dim_loc);BaseH bH(dim_glob,dim_loc);
+ (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH);
+ // calcul des coordonnees locales du point M dans le repere en refl
+ Coordonnee AM = M - A; // en global
+ for (int i=1;i<=dim_loc;i++)
+ theta(i) = AM * bH(i).Coor(); // ok même si dim_loc < dim_glob -> projection sur le plan tangent
+ Coordonnee theta_repere(theta); // le point où l'on calcul le repère
+ Coordonnee theta_initial(theta); Coordonnee delta_theta(theta);
+ // dans le cas où le point est externe à l'élément, on limite le repère de calcul au point externe
+ // de l'élément dans la direction de theta
+ if (!(elgeom.Interieur(theta)))
+ { // calcul d'un point extreme de l'élément dans le sens de M
+ theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta);
+ }
+ // calcul du point correspondant à theta dans l'element, qui remplace A
+ ph_i = elgeom.Phi(theta_repere); // fonctions d'interpolation en A
+ Coordonnee A_sauve= A;
+ A = (met->*PointM) (tab_noeud,ph_i);
+ AM = M-A; // nouveau gap
+
+ // ---- 2 :iteration
+ // on boucle avec un test de stabilité des coordonnées locales
+ int compteur = 1; // contrôle du maxi d'itération
+ int nb_exterieur=0; // contrôle du maxi de fois que l'on trouve consécutivement le point à l'extérieur
+ // - récup des paramètres de controle
+ double delta_thetai_maxi = ParaGlob::param->ParaAlgoControleActifs().PointInterneDeltaThetaiMaxi();
+ int nb_boucle_sur_delta_thetai= ParaGlob::param->ParaAlgoControleActifs().PointInterneNbBoucleSurDeltaThetai();
+ int nb_max_a_l_exterieur= ParaGlob::param->ParaAlgoControleActifs().PointInterneNbExterne();
+ double prec_tehetai_interne= ParaGlob::param->ParaAlgoControleActifs().PointInternePrecThetaiInterne();
+ // - boucle de recherche des thetai
+ while (delta_theta.Norme() >= delta_thetai_maxi)
+
+ {dph_i = elgeom.Dphi(theta_repere); // derivees des fonctions d'interpolation en theta_repere
+ ph_i = elgeom.Phi(theta_repere); // fonctions d'interpolation en theta_repere (déjà calculé la première fois)
+ // calcul de la base naturelle et duale en fonction des coord a t
+ (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH);
+ // amelioration des coordonnees locales du point M dans le repere en theta
+ for (int i=1;i<=dim_loc;i++)
+ delta_theta(i)=AM * bH(i).Coor();
+// theta += delta_theta; erreur je pense: le 11 juin 2007
+ // le nouveau theta = la position du repère + le deltat theta
+ theta = theta_repere + delta_theta;
+
+ theta_repere=theta;
+ if (!(elgeom.Interieur(theta))) // si le point est à l'extérieur
+ { // calcul d'un point extreme de l'élément dans le sens de M
+ theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta);
+ nb_exterieur++;
+ }
+ else // si nb_exterieur est diff de zero, on le remet à zéro, car on est de nouveau à l'intérieur
+ { if (nb_exterieur != 0) nb_exterieur=0; };
+
+ // si cela fait nb_max_a_l_exterieur fois que l'on est à l'extérieur on arrête
+ if ( nb_exterieur >= nb_max_a_l_exterieur) break;
+ // calcul du point correspondant dans l'element, qui remplace theta
+ ph_i = elgeom.Phi(theta_repere); // fonctions d'interpolation en theta
+ A = (met->*PointM) (tab_noeud,ph_i);
+ AM = M-A; // nouveau gap
+ compteur++;
+ if (compteur > nb_boucle_sur_delta_thetai)
+ { // cela signifie que l'on n'arrive pas à converger, petit message si besoin
+ // et on choisit le point initial pour le teste
+ if (ParaGlob::NiveauImpression() >= 4)
+ cout << " \n ** warning, l'algorithme de recherche d'un point a l'interieur d'un "
+ << "element ne converge pas, utilisation du repere a l'origine"
+ << "\nElemThermi::Interne(Coordonnee& M)" << endl;
+ if (elgeom.Interieur(theta_initial)) {theta=theta_initial; }
+ else {theta=theta_initial; };
+ break;
+ };
+ };
+// // à la sortie de la boucle on calcul les thétas correspondants à M final
+// dph_i = elgeom.Dphi(theta_repere); // derivees des fonctions d'interpolation en theta
+// ph_i = elgeom.Phi(theta_repere); // fonctions d'interpolation en theta
+// // calcul de la base naturelle et duale en fonction des coord a t
+// (met->*BaseND)(tab_noeud,dph_i,ph_i,bB,bH);
+// // amelioration des coordonnees locales du point M dans le repere en theta
+// for (int i=1;i<=dim_glob;i++)
+// theta(i) += AM * bH(i).Vect();
+//
+ // -- maintenant on regarde si le point est interne ou pas a l'element
+ int retour=0;
+ if (elgeom.Interieur(theta))
+ { // on regarde si le point est intérieur d'une toute petite précision
+ // calcul d'un point extreme de l'élément dans le sens de M
+ theta_repere = elgeom.Maxi_Coor_dans_directionGM(theta);
+ double diff =(theta_repere-theta).Norme();
+ if (diff <= prec_tehetai_interne)
+ {retour = 2;} // !-! à l'erreur près, le point est sur la frontière
+ else {retour = 1;}; // !-! point à l'intérieur
+ }
+ else {return 0;}; // !-! point à l'extérieur -> retour directe
+ // --- cas particuliers ---
+ // -- dans le cas où "retour" est différent de 0, on regarde les cas particuliers
+ switch (dim_glob)
+ {case 3:
+ {switch (dim_loc)
+ { case 3: break; // cas pas de pb
+ case 2: // cas des "coques ou plaques" on regarde si le point est réellement à l'intérieur (+- 1/2 épaisseur)
+ { double epaisseur = Epaisseurs(temps,theta);
+ A = (met->*PointM) (tab_noeud,ph_i); // le point projeté sur la surface de l'élément
+ AM = M-A; double delta_hauteur = 0.5 * epaisseur - AM.Norme();
+ if (Dabs(delta_hauteur) <= prec_tehetai_interne)
+ {retour = 2;} // !-! à l'erreur près, le point est sur la frontière
+ else if (delta_hauteur < 0.)
+ {retour = 0;} // !-! point externe
+ else {retour = 1;}; // !-! point à l'intérieur
+ break;
+ }
+ default:
+ cout << " \n *** erreur : cas non implemente pour l'instant "
+ << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc
+ << "\n ElemThermi::Interne(... ";
+ Sortie(1);
+ };// -- fin du switch dim_loc pour dim_glob=3
+ break;
+ } // fin dim_glob=3
+ case 2:
+ {switch (dim_loc)
+ {
+ case 2: break; // pas de pb
+ case 1: case 3: // cas des poutres et volume (pb non consistance) pour l'instant non traité
+ // donc on laisse aller à la valeur par défaut
+ default:
+ cout << " \n *** erreur : cas non implemente pour l'instant "
+ << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc
+ << "\n ElemThermi::Interne(... ";
+ Sortie(1);
+ };// -- fin du switch dim_loc pour dim_glob=3
+ break;
+ } // fin dim_glob=2
+ default: // default pour le switch sur di_glob
+ cout << " \n *** erreur : cas non implemente pour l'instant "
+ << " dim_glob= " << dim_glob << " dim_loc= " << dim_loc
+ << "\n ElemThermi::Interne(... ";
+ Sortie(1);
+ break;
+ }; // -- fin du switch sur dim_glob
+ // retour
+ return retour;
+ };
+
+// Calcul du residu local et de la raideur locale,
+// pour le schema implicite
+// cald_Dvirtuelle = indique si l'on doit calculer la dérivée de la vitesse de déformation virtuelle
+void ElemThermi::Cal_implicit (DdlElement & tab_ddl
+ ,Tableau & d_gradTB,Tableau < Tableau2 * > d2_gradTB_
+ ,Tableau & d_fluxH,int nbint
+ ,const Vecteur& poids,const ParaAlgoControle & pa,bool cald_DGradTvirtuelle)
+ {
+ int nbddl = tab_ddl.NbDdl();
+ volume = 0. ; // init
+ Vecteur d_jacobien_tdt;
+ energie_totale.Inita(0.); // init de l'énergie totale sur l'élément
+ E_elem_bulk_tdt = E_elem_bulk_t; P_elem_bulk = 0.; // init pour l'énergie et la puissance associées au bulk
+ // init par défaut pour un cas où la pression ne bouge pas
+ const double P_t = 1.; // pour l'instant on considère une pression unitaire
+ const double P = 1.; // pour l'instant on considère une pression unitaire
+
+ for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+ {def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni));
+ PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni);
+ EnergieThermi& energ = tab_energ(ni);
+ EnergieThermi& energ_t = tab_energ_t(ni);
+ CompThermoPhysiqueAbstraite::SaveResul* saveTP=tabSaveTP(ni); // les données spécifique thermo physiques
+
+ if ((loiTP->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat
+ || (loiComp->Id_comport()==LOI_VIA_UMAT_CP))
+ ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni);
+ const Met_abstraite::Impli& ex = loiTP->Cal_implicit
+ (P_t,saveTP,P,*def,tab_ddl,ptIntegThermi,d_gradTB,d_fluxH,pa,loiTP
+ ,dilatation,energ,energ_t,premier_calcul_thermi_impli_expli);
+
+ // on calcul éventuellement la dérivée de la vitesse de gradient virtuelle
+ Tableau2 * d2_gradTB = d2_gradTB_(ni); // pour simplifier
+ if (cald_DGradTvirtuelle)
+ // si en retour le pointeur est null cela signifie qu'il ne faut pas considérer d2_gradTB
+ d2_gradTB =def->Der2GradDonneeInterpoleeScalaire(d2_gradTB,TEMP);
+
+// // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity
+// DeuxDoubles delta_ener_bulk_vol; // init
+// if (bulk_viscosity)
+// delta_ener_bulk_vol=ModifContrainteBulk(*ex.gijHH_tdt,sigHH,DepsBB_tdt,(*sig_bulkHH) );
+ double rap=1.; // pour le calcul éventuel du rapport de jacobien actuel
+ if (pa.MaxiVarJacobien() > 1.) // cas de la demande du calcul du rapport de jacobien
+ {if (Dabs(*(ex.jacobien_tdt)) > (*(ex.jacobien_0))) {rap = Dabs(*(ex.jacobien_tdt)) / (*(ex.jacobien_0));}
+ else {rap = (*(ex.jacobien_0)) / Dabs(*(ex.jacobien_tdt)) ;}
+ };
+
+ if ((*(ex.jacobien_tdt) <= 0.)|| (std::isinf(*(ex.jacobien_tdt)))||( std::isnan(*(ex.jacobien_tdt)))) // vérif du jacobien
+ { if ((std::isinf(*(ex.jacobien_tdt)))||( std::isnan(*(ex.jacobien_tdt))))
+ // on met un message quelque soit le niveau d'impression
+ { cout << "\n ********** attention on a trouve un jacobien infini ou nan !! = ("<<*(ex.jacobien_tdt)<<")********* " << endl; };
+ if (ParaGlob::NiveauImpression() >= 1)
+ { cout << "\n ********** attention on a trouve un jacobien negatif!! ("<<*(ex.jacobien_tdt)<<")********* " << endl; };
+ };
+ if ((*(ex.jacobien_tdt) <= 0.) && (pa.JabobienNegatif()!= 0)) // vérif du jacobien et traitement adéquate si besoin
+ { switch (pa.JabobienNegatif())
+ { case 1:
+ { cout << "\n on annulle sa contribution. Element nb: " << Num_elt() << " nb d'integ : " << ni;
+ break;
+ }
+ case 2:
+ { // on génère une exception
+ throw ErrJacobienNegatif_ElemThermi();break;
+ }
+ // dans les autres cas on ne fait rien
+ };
+ }
+ else if ((pa.MaxiVarJacobien() > 1.) && ( rap > pa.MaxiVarJacobien()))
+ { if (ParaGlob::NiveauImpression() >= 3)
+ { cout << "\n *** attention la variation maximal du jacobien est atteinte !! *** "
+ << "\n ele= "<< Num_elt() << " nbi= " << ni << " jacobien= " << *(ex.jacobien_tdt) << " jacobien_0= "
+ << (*(ex.jacobien_0)) << endl; };
+ // on génère une exception
+ throw ErrVarJacobienMini_ElemThermi();break;
+ }
+ else
+ { // on prend en compte toutes les variations
+ double poid_jacobien= poids(ni) * *(ex.jacobien_tdt);
+ energie_totale += energ * poid_jacobien;
+// E_elem_bulk_tdt += delta_ener_bulk_vol.un * poid_jacobien;
+// P_elem_bulk += delta_ener_bulk_vol.deux * poid_jacobien;
+ volume += *(ex.jacobien_tdt) * poids(ni);
+ if (d2_gradTB == NULL)
+ {for (int j =1; j<= nbddl; j++) // 1ere boucle sur les ddl
+ {(*residu)(j) -= d_gradTB(j) * ptIntegThermi.FluxH() * poid_jacobien;
+ for (int i =1; i<= nbddl; i++) // 2ere boucle sur les ddl
+ (*raideur)(j,i) += d_gradTB(j) * d_fluxH(i) * poid_jacobien;
+ // raideur->Affiche();
+ }
+ }
+ else
+ {for (int j =1; j<= nbddl; j++) // 1ere boucle sur les ddl
+ {(*residu)(j) -= d_gradTB(j) * ptIntegThermi.FluxH() * poid_jacobien;
+ for (int i =1; i<= nbddl; i++) // 2ere boucle sur les ddl
+ (*raideur)(j,i) += d_gradTB(j) * d_fluxH(i) * poid_jacobien
+ + (*d2_gradTB)(j,i) * ptIntegThermi.FluxH() * poid_jacobien;
+ // raideur->Affiche();
+ }
+ };
+
+ };// fin du if sur la valeur non négative du jacobien
+// if (bulk_viscosity) // dans le cas du bulk on retire la contrainte du bulk, qui est non physique
+// { sigHH -= (*sig_bulkHH); } // ceci pour la sauvegarde ou autre utilisation
+
+ } // fin boucle sur les points d'intégration
+ // --- intervention dans le cas d'une stabilisation d'hourglass
+ // stabilisation pour un calcul implicit
+ if (type_stabHourglass)
+ Cal_implicit_hourglass();
+
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ };
+
+// Calcul uniquement du residu local a l'instant t ou pas suivant la variable atdt
+// pour le schema explicit par exemple
+void ElemThermi::Cal_explicit (DdlElement & tab_ddl,Tableau & d_gradTB
+ ,int nbint,const Vecteur& poids,const ParaAlgoControle & pa,bool atdt)
+
+ { double jacobien; // def du jacobien
+// int nbddl = tab_ddl.NbDdl();
+// energie_totale.Inita(0.); // init de l'énergie totale sur l'élément
+// volume = 0. ; // init
+// E_elem_bulk_tdt = E_elem_bulk_t; P_elem_bulk = 0.; // init pour l'énergie et la puissance associées au bulk
+// // init éventuel de la contrainte de bulk viscosity
+// TenseurHH* sigHH_t_1 = (*lesPtIntegThermiInterne)(1).SigHH_t(); // simplification d'écriture
+// if (bulk_viscosity)
+// { if (sig_bulkHH == NULL) {sig_bulkHH = NevezTenseurHH(*sigHH_t_1);}
+// else if (sig_bulkHH->Dimension() != sigHH_t_1->Dimension())
+// {delete sig_bulkHH; sig_bulkHH = NevezTenseurHH(*sigHH_t_1);};
+// };
+// for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+// { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni));
+// PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni);
+// TenseurHH & sigHH_t = *(ptIntegThermi.SigHH_t());
+// TenseurHH & sigHH = *(ptIntegThermi.SigHH());
+// TenseurBB & epsBB = *(ptIntegThermi.EpsBB());
+// TenseurBB & DepsBB_ = *(ptIntegThermi.DepsBB());
+// EnergieThermi& energ = tab_energ(ni);
+// EnergieThermi& energ_t = tab_energ_t(ni);
+// CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques
+// if (loiTP != NULL) {sTP = tabSaveTP(ni);}; // au pt d'integ si elles existes
+// if (loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat
+// ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni);
+// DeuxDoubles delta_ener_bulk_vol; // init
+// if (atdt)
+// { //const Met_abstraite::Expli_t_tdt& ex = loiComp->Cal_explicit_tdt
+// // (tabSaveDon(ni), *def,tab_ddl,ptIntegThermi,d_epsBB,jacobien
+// // ,sTP,loiTP,dilatation,energ,energ_t,ppremier_calcul_Thermi_impli_expli;
+// const Met_abstraite::Expli_t_tdt ex;
+// // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity
+// if (bulk_viscosity)
+// delta_ener_bulk_vol=ModifContrainteBulk(*ex.gijHH_tdt,sigHH,DepsBB_,(*sig_bulkHH) );
+// }
+// else
+// { //const Met_abstraite::Expli& ex = loiComp->Cal_explicit_t
+// // (tabSaveDon(ni), *def,tab_ddl,ptIntegThermi,d_epsBB,jacobien
+// // ,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_Thermi_impli_expli);
+// const Met_abstraite::Expli_t_tdt ex;
+// // examen du cas où on désire utiliser la méthode d'atténuation des hautes fréquences avec le bulk viscosity
+// if (bulk_viscosity)
+// delta_ener_bulk_vol=ModifContrainteBulk(*ex.gijHH_t,sigHH,DepsBB_,(*sig_bulkHH) );
+// }
+// if ((jacobien <= 0.)|| (std::isinf(jacobien))||( std::isnan(jacobien))) // vérif du jacobien
+// { if ((std::isinf(jacobien))||( std::isnan(jacobien)))
+// // on met un message quelque soit le niveau d'impression
+// { cout << "\n ********** attention on a trouve un jacobien infini ou nan !! = ("<= 1)
+// { cout << "\n ********** attention on a trouve un jacobien negatif!! ("<& d_gradTB, Tableau < Tableau2 * > d2_gradTB_
+ ,Tableau & d_fluxH,int nbint,const Vecteur& poids
+ ,const ParaAlgoControle & pa,bool cald_Dvirtuelle)
+ { // le début du programme est semblable au calcul implicit
+ // seule la constitution des matrices finales est différente
+// int nbddl = tab_ddl.NbDdl();
+// double jacobien; // def du jacobien
+// Vecteur d_jacobien_tdt;
+// volume = 0. ; // init
+//
+// for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+// {def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni));
+// PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni);
+// TenseurHH & sigHH = *(ptIntegThermi.SigHH());
+// TenseurBB & DepsBB_tdt = *(ptIntegThermi.DepsBB());
+// EnergieThermi& energ = tab_energ(ni);
+// EnergieThermi& energ_t = tab_energ_t(ni);
+// CompThermoPhysiqueAbstraite::SaveResul* sTP=NULL; // les données spécifique thermo physiques
+// if (loiTP != NULL) {sTP = tabSaveTP(ni);}; // au pt d'integ si elles existes
+// if (loiComp->Id_comport()==LOI_VIA_UMAT) // cas de l'utilisation d'une loi umat
+// ((Loi_Umat*) loiComp)->Mise_a_jour_nbe_nbptinteg(this->Num_elt(),ni);
+//// loiComp->Cal_flamb_lin(tabSaveDon(ni), *def,tab_ddl,ptIntegThermi,d_epsBB,jacobien,d_jacobien_tdt,d_sigHH
+//// ,pa,sTP,loiTP,dilatation,energ,energ_t,premier_calcul_Thermi_impli_expli);
+// // on calcul éventuellement la dérivée de la vitesse de déformation virtuelle
+// Tableau2 & d2_gradTB = d2_gradTB_(ni); // pour simplifier
+// if (cald_Dvirtuelle)
+// def->Cal_var_def_virtuelle(false,d2_gradTB);
+// // calcul du volume
+// volume += jacobien * poids(ni);
+// for (int j =1; j<= nbddl; j++) // 1ere boucle sur les ddl
+// for (int i =1; i<= nbddl; i++) // 2ere boucle sur les ddl
+// {matInit(j,i) += ((*d_sigHH(i)) && (*(d_epsBB(j)))) * jacobien * poids(ni);
+// matGeom(j,i) += (sigHH && (*(d2_gradTB(j,i)))) * jacobien * poids(ni);
+// }
+// }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ };
+
+// Calcul de la matrice masse selon différent choix donné par type_matrice_masse,
+void ElemThermi::Cal_Mat_masse (DdlElement & tab_ddl,Enum_calcul_masse type_matrice_masse,
+ int nbint,const Tableau & taphi,int nbne
+ ,const Vecteur& poids)
+ {
+ int nbddl = tab_ddl.NbDdl();
+ double jacobien_0; // def du jacobien initial
+ // initialisation de la matrice masse
+ mat_masse->Initialise ();
+
+ // le calcul est fonction du type de matrice masse demandé
+ switch (type_matrice_masse)
+ {case MASSE_DIAG_COEF_EGAUX :
+ // même masse sur chaque noeud
+ { // calcul du volume totale
+ double vol_totale =0.;
+ for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+ { defMas->ChangeNumInteg(ni);
+ const Met_abstraite::Dynamiq& ex = defMas->Cal_matMass();
+ jacobien_0 = *ex.jacobien_0;
+ vol_totale += jacobien_0 * poids(ni);
+ }
+ // la masse élémentaire pour chaque noeud
+ double masse_elementaire = vol_totale * masse_volumique / tab_noeud.Taille();
+ // on initialise toutes les valeurs de la matrice masse à la valeur moyenne
+ mat_masse->Initialise (masse_elementaire );
+ break;
+ }
+ case MASSE_DIAG_COEF_VAR :
+ // masse diagonale répartie au prorata des fonctions d'interpolation
+ // (cf page 304, tome 2 Batoz)
+ { // définition d'un vecteur qui contiendra l'intégral de chaque
+ // fonction d'interpolation (ici la masse est considérée constante)
+ Vecteur fonc2(nbne);
+ // calcul de fonc2 et du volume totale
+ double vol_totale =0.;
+ for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+ { defMas->ChangeNumInteg(ni);
+ const Met_abstraite::Dynamiq& ex = defMas->Cal_matMass();
+ jacobien_0 = *ex.jacobien_0;
+ for (int ne =1;ne<=nbne;ne++)
+ fonc2(ne) += taphi(ni)(ne) * taphi(ni)(ne) * jacobien_0 * poids(ni);
+ vol_totale += jacobien_0 * poids(ni);
+ }
+ // calcul de la somme des composantes de fonc2
+ double somme_fonc2 = 0.;
+ for (int ne = 1;ne<=nbne;ne++) somme_fonc2 += fonc2(ne);
+ // calcul des termes diagonaux de la matrice de masse
+ int dimension = ParaGlob::Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
+ // dimension-1 coordonnées donc on décrémente
+ dimension--;
+ int ix=1;
+ for (int ne =1; ne<= nbne; ne++)
+ { double inter_toto = vol_totale * masse_volumique * fonc2(ne) / somme_fonc2;
+ for (int i=1;i<= dimension;i++,ix++)
+ (*mat_masse)(1,ix) = inter_toto;
+ }
+ break;
+ }
+ case MASSE_CONSISTANTE :
+ // matrice masse complète avec les mêmes fonctions d'interpolation
+ // que pour la raideur.
+ {
+ int dimension = ParaGlob::Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
+ // dimension-1 coordonnées donc on décrémente
+ dimension--;
+ for (int ni =1; ni<= nbint; ni++) // boucle sur les pt d'integ
+ {defMas->ChangeNumInteg(ni); // def du pt d'intégration
+ // récup des fonctions d'interpolation et du jacobien
+ const Met_abstraite::Dynamiq& ex = defMas->Cal_matMass();
+ double masse_i = (*ex.jacobien_0) * masse_volumique;
+ // calcul de la matrice
+ int ix=1;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int a=1;a<= dimension;a++,ix++)
+ { int jy=1;
+ for (int me =1; me<= nbne; me++)
+ for (int b=1;b<= dimension;b++,jy++)
+ if (a==b) // seule des termes de même indice sont non nulles
+ (*mat_masse)(ix,jy) += taphi(ni)(ne)* taphi(ni)(me) * masse_i * poids(ni);
+ }
+ }
+ break;
+ }
+ default :
+ cout << "\nErreur : valeur incorrecte du type Enum_calcul_masse !\n";
+ cout << "ElemThermi::Cal_Mat_masse (... \n";
+ Sortie(1);
+ };
+
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ };
+
+ // ------------ calcul de second membre ou de l'action des efforts extérieures -----------
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement surfacique de direction constante, sur les frontières des éléments
+// force indique la force surfacique appliquée
+// retourne le second membre résultant
+// nSurf : le numéro de la surface externe
+// calcul à tdt ou t suivant la variable atdt
+Vecteur& ElemThermi::SM_charge_surf_E (DdlElement & ,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & ,bool atdt)
+ { // définition du vecteur de retour
+ Vecteur& SM = *((*res_extS)(nSurf));
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ double jacobien;
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ if (atdt)
+ { const Met_abstraite::Expli_t_tdt& ex = defS.Cal_explicit_tdt(premier_calcul);
+ jacobien = (*ex.jacobien_tdt);
+ }
+ else
+ { const Met_abstraite::Expli& ex = defS.Cal_explicit_t(premier_calcul);
+ jacobien = (*ex.jacobien_t);
+ }
+ int ix=1; int dimf = force.Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force(i) * (poids(ni) * jacobien);
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement surfacique de direction constante, sur les frontières des éléments
+// force indique la force surfacique appliquée
+// retourne le second membre résultant
+// nSurf : le numéro de la surface externe
+// -> implicite,
+// pa : permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid ElemThermi::SMR_charge_surf_I (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa)
+ { bool avec_raid = pa.Var_charge_externe(); // récup indicateur
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ int nbddl = ddls.NbDdl();
+ Vecteur& SM = (*((*res_extS)(nSurf))); // " " "
+ Mat_pleine & KM = (*((*raid_extS)(nSurf))); // " " "
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul);
+ int ix=1; int dimf = force.Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) += taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ KM(ix,j) +=
+ taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j));
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = (*res_extS)(nSurf);
+ el.raid = (*raid_extS)(nSurf);
+ return el;
+ };
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement pression, sur les frontières des éléments
+// pression indique la pression appliquée
+// retourne le second membre résultant
+// nSurf : le numéro de la surface externe
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_pres_E (DdlElement & ,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,double pression
+ ,const ParaAlgoControle & ,bool atdt)
+ {
+ Deformation* definter=NULL; // variable de travail transitoire
+ Vecteur* SM_P = NULL;
+ if (!(ParaGlob::AxiSymetrie()))
+ { definter = defSurf(nSurf); // le cas normal est non axisymétrique
+ SM_P = ((*res_extS)(nSurf));
+ }
+ else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête
+ SM_P = ((*res_extA)(nSurf));
+ };
+ Deformation & defS = *definter; // pour simplifier l'écriture
+ Vecteur& SM = *SM_P; // " " "
+
+ // définition du vecteur de retour
+ int ni; // compteur globale de point d'integration
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ if (atdt)
+ ex = ((defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t());
+ else
+ ex.operator=( defS.Cal_explicit_t(premier_calcul));
+ // détermination de la normale à la surface
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on a réellement affaire à une surface
+ if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3))
+ { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3"
+ << " ElemThermi::SM_charge_pres (DdlElement & ...nbvec= " << ex.giB_t->NbVecteur()
+ << " dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2));
+ // calcul de la normale normée et pondérée de la pression
+ // la pression est positive qu'en elle appuis (diminution de volume)
+ normale.Normer(); normale *= -pression;
+ int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_t));
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement pression, sur les frontières des éléments
+// pression indique la pression appliquée
+// retourne le second membre résultant
+// nSurf : le numéro de la surface externe -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+Element::ResRaid ElemThermi::SMR_charge_pres_I(DdlElement & ddlS,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,double pression
+ ,const ParaAlgoControle & pa)
+ {
+ int ni; // compteur globale de point d'integration
+
+ Deformation* definter=NULL; // variable de travail transitoire
+ Vecteur* SM_P = NULL; Mat_pleine* KM_P = NULL;
+ if (!(ParaGlob::AxiSymetrie()))
+ { definter = defSurf(nSurf); // le cas normal est non axisymétrique
+ SM_P = ((*res_extS)(nSurf));
+ KM_P = ((*raid_extS)(nSurf));
+ }
+ else { definter = defArete(nSurf); // en axisymétrie, c'est une def d'arête
+ SM_P = ((*res_extA)(nSurf));
+ KM_P = ((*raid_extA)(nSurf));
+ };
+ Deformation & defS = *definter; // pour simplifier l'écriture
+ Vecteur& SM = *SM_P; // " " "
+ Mat_pleine & KM = *KM_P; // " " "
+
+ int nbddl = ddlS.NbDdl();
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul);
+ // détermination de la normale à la surface
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on a réellement affaire à une surface
+ if ((ex.giB_tdt->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3))
+ { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3"
+ << " ElemThermi::SM_charge_pres (DdlElement & ...nbvec= " << ex.giB_tdt->NbVecteur()
+ << " dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2));
+ // calcul de la variation de la normale
+ // 1) variation du produit vectoriel
+ Tableau D_pasnormale =
+ Util::VarProdVect_coorB( (*ex.giB_tdt)(1),(*ex.giB_tdt)(2),(*ex.d_giB_tdt));
+ // 2) de la normale
+ Tableau D_normale = Util::VarUnVect_coorB(normale,D_pasnormale,normale.Norme());
+ // calcul de la normale normée et pondérée de la pression
+ // la pression est positive qu'en elle appuis (diminution de volume)
+ normale.Normer(); normale *= -pression;
+ // également pondération de la variation de la
+ for (int ihi =1;ihi<= nbddl;ihi++)
+ D_normale(ihi) *= -pression;
+
+ int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ KM(ix,j) -=
+ taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j))
+ + taphi(ni)(ne)* D_normale(j)(i) * (poids(ni) * (*ex.jacobien_tdt)) ;
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = SM_P;
+ el.raid = KM_P;
+ return el;
+ };
+
+// calcul des seconds membres suivant les chargements
+// cas d'un chargement lineique, sur les aretes frontières des éléments
+// force indique la force lineique appliquée
+// retourne le second membre résultant
+// nArete : le numéro de la surface externe
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_line_E (DdlElement & ,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & ,bool atdt)
+ { // définition du vecteur de retour
+ Vecteur& SM = *((*res_extA)(nArete));
+ int ni; // compteur globale de point d'integration
+ Deformation & defA = *defArete(nArete); // pour simplifier l'écriture
+ for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ if (atdt)
+ ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t();
+ else
+ ex = defA.Cal_explicit_t(premier_calcul);
+ int ix=1; int dimf = force.Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.jacobien_t));
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// cas d'un chargement lineique, sur les arêtes frontières des éléments
+// force indique la force lineique appliquée
+// retourne le second membre résultant
+// nArete : le numéro de l'arête externe -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+Element::ResRaid ElemThermi::SMR_charge_line_I(DdlElement & ddlA,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa)
+ { int ni; // compteur globale de point d'integration
+ Deformation & defA = *defArete(nArete); // pour simplifier l'écriture
+ int nbddl = ddlA.NbDdl();
+ Vecteur& SM = (*((*res_extA)(nArete))); // " " "
+ Mat_pleine & KM = (*((*raid_extA)(nArete))); // " " "
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul);
+ int ix=1; int dimf = force.Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) +=
+ taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ KM(ix,j) -=
+ taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j));
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = (*res_extA)(nArete);
+ el.raid = (*raid_extA)(nArete);
+ return el;
+ };
+
+// cas d'un chargement lineique suiveur, sur les aretes frontières des éléments
+// force indique la force lineique appliquée
+// retourne le second membre résultant
+// nArete : le numéro de la surface externe
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_line_Suiv_E (DdlElement & ,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & ,bool atdt)
+ { // définition du vecteur de retour
+ Vecteur& SM = *((*res_extA)(nArete));
+ int ni; // compteur globale de point d'integration
+ Deformation & defA = *defArete(nArete); // pour simplifier l'écriture
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ if (atdt)
+ ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t();
+ else
+ ex = defA.Cal_explicit_t(premier_calcul);
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on est en dimension 2 ou en axy sinon pas possible
+ if ((ParaGlob::Dimension() != 2) & (!(ParaGlob::AxiSymetrie())))
+ { cout << "\n erreur, pour l'instant seul la dimension 2 est permise avec les forces suiveuses"
+ << "\n si pb contacter gerard Rio ! "
+ << " ElemThermi::SM_charge_line_Suiv_E ( ..."
+ << " \n dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // calcul du repère locale initiale orthonormée
+// Coordonnee2 v1((*ex.giB_0)(1).Vect()); v1.Normer();
+ // on récupère que les deux premières coordonnées mais on travaille en 3D pour intégrer le cas axi
+ Coordonnee v1((*ex.giB_0).Coordo(1)); v1.Normer();
+ int dim = v1.Dimension();
+ Coordonnee v2(dim); v2(1)=-v1(2); v2(2)=v1(1);
+ // composante du vecteur force linéique dans le repère initiale
+ Coordonnee force_0(v1*force,v2*force);
+ //repère locale actuel orthonormée
+ Coordonnee giB_t = (*ex.giB_t)(1).Coor();
+ Coordonnee vf1(giB_t);
+ Coordonnee vf2(dim);vf2(1)=-vf1(2);vf2(2)=vf1(1);
+ // composantes actuelles de la force
+ Coordonnee force_t = force_0(1)*vf1 + force_0(2)*vf2;
+ // calcul du résidu
+ int ix=1; int dimf = 2 ; // ici uniquement en dim 2 sinon pb
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force_t(i) * (poids(ni) * (*ex.jacobien_t));
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// cas d'un chargement lineique suiveur, sur les arêtes frontières des éléments
+// force indique la force lineique appliquée
+// retourne le second membre résultant
+// nArete : le numéro de l'arête externe -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+Element::ResRaid ElemThermi::SMR_charge_line_Suiv_I(DdlElement & ddlA,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa)
+ { int ni; // compteur globale de point d'integration
+ Deformation & defA = *defArete(nArete); // pour simplifier l'écriture
+ int nbddl = ddlA.NbDdl();
+ Vecteur& SM = (*((*res_extA)(nArete))); // " " "
+ Mat_pleine & KM = (*((*raid_extA)(nArete))); // " " "
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul);
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on est en dimension 2 ou en axy sinon pas possible
+ if ((ParaGlob::Dimension() != 2) & (!(ParaGlob::AxiSymetrie())))
+ { cout << "\n erreur, pour l'instant seul la dimension 2 est permise avec les forces suiveuses"
+ << "\n si pb contacter gerard Rio ! "
+ << " ElemThermi::SM_charge_line_Suiv_E ( ..."
+ << " \n dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // calcul du repère locale initiale orthonormée
+// Coordonnee2 v1((*ex.giB_0)(1).Vect()); v1.Normer();
+ // on récupère que les deux premières coordonnées mais on travaille en 3D pour intégrer le cas axi
+ Coordonnee v1((*ex.giB_0).Coordo(1)); v1.Normer();
+ int dim = v1.Dimension();
+ Coordonnee v2(dim); v2(1)=-v1(2); v2(2)=v1(1);
+ // composante du vecteur force linéique dans le repère initiale
+ Coordonnee force_0(v1*force,v2*force);
+ //repère locale actuel orthonormée
+ Coordonnee giB_tdt = (*ex.giB_tdt)(1).Coor();
+ Coordonnee vf1(giB_tdt);
+ double vf1Norme = vf1.Norme();vf1 /= vf1Norme;
+ Coordonnee vf2(dim);vf2(1)=-vf1(2);vf2(2)=vf1(1);
+ // composantes actuelles de la force
+ Coordonnee force_t = force_0(1)*vf1 + force_0(2)*vf2;
+
+ // calcul du résidu
+ int ix=1; int dimf = 2 ; // ici uniquement en dim 2 sinon pb
+ Coordonnee dvf1,dvf2,d_giB_tdt; // def de vecteurs intermediaires
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) += taphi(ni)(ne)* force_t(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ { // calcul des variations de la force
+ d_giB_tdt = ((((*ex.d_giB_tdt)(j))(1)).Coor());
+ dvf1 = Util::VarUnVect_coor // variation de vf1 par rapport au ddl j
+ (giB_tdt,d_giB_tdt,vf1Norme);
+ dvf2 = -(dvf1 * vf2) * vf1;
+ KM(ix,j) -= taphi(ni)(ne) * poids(ni)
+ * (force_t(i) *(*ex.d_jacobien_tdt)(j)
+ + (*ex.jacobien_tdt) * ((force_0(1) * dvf1 + force_0(2) * dvf2))(i)
+ );
+ }
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = (*res_extA)(nArete);
+ el.raid = (*raid_extA)(nArete);
+ return el;
+ };
+
+// cas d'un chargement surfacique suiveur, sur les surfaces de l'élément
+// la direction varie selon le système suivant: on définit les coordonnées matérielles
+// de la direction, ce qui sert ensuite à calculer les nouvelles directions. L'intensité
+// elle est constante.
+// force indique la force surfacique appliquée
+// retourne le second membre résultant
+// nSurf : le numéro de la surface externe
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_surf_Suiv_E (DdlElement & ,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& forc
+ ,const ParaAlgoControle & ,bool atdt)
+ { // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
+ // *** sinon c'est intractable et long
+ // définition du vecteur de retour
+ Vecteur& SM = *((*res_extS)(nSurf));
+ double module_f = forc.Norme();
+ // dans le cas ou la force est de module nul, on retourne sans calcul
+ if (module_f < ConstMath::trespetit)
+ return SM;
+ #ifdef MISE_AU_POINT
+ // test : a priori non valide pour les éléments axi et pour un pb autre que 3D
+ if (( ParaGlob::Dimension() != 3) || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
+ { cout << "\n erreur, ce type de chargement n'est valide sur pour la dimension 3 !! et non axi"
+ << " ElemThermi::SM_charge_line_Suiv_E ( ..."
+ << " \n dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ };
+ #endif
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ if (atdt)
+ ex = (defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t();
+ else
+ ex = defS.Cal_explicit_t(premier_calcul);
+ // détermination de la normale à la surface
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ Coordonnee normale_0 = Util::ProdVec_coorBN( (*ex.giB_0)(1), (*ex.giB_0)(2));
+ // on passe en BN pour dire que c'est du B en normal
+ const Coordonnee& giBN_t1 = (*ex.giB_t).Coordo(1); const Coordonnee& giBN_t2 = (*ex.giB_t).Coordo(2);
+ Coordonnee normale_t = Util::ProdVec_coor( giBN_t1, giBN_t2);
+
+ // calcul de la normale normée
+ normale_0.Normer(); normale_t.Normer();
+ // calcul des composantes de direction de la force dans le repère local initial
+ Coordonnee dir_forceH_0(3);
+ // ici le fait d'utiliser la méthode .Vect() supprime la variance, mais justement
+ // on ne veut pas de vérification de variance qui est ici incohérente
+ dir_forceH_0(1) = giBN_t1 * forc; dir_forceH_0(2) = giBN_t2 * forc;
+ dir_forceH_0(3) = normale_0 * forc;
+ // calcul de la direction finale
+ Coordonnee dir_force_t = dir_forceH_0(1) * giBN_t1 + dir_forceH_0(2) * giBN_t2
+ + dir_forceH_0(3) * normale_t;
+ dir_force_t.Normer();
+ // calcul de la force finale
+ Coordonnee force_t = (forc.Norme()) * dir_force_t;
+ // calcul du second membre
+ int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3
+ // sauf pour les éléments axisymétriques pour lesquelles on ne considère que les deux premières composantes
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force_t(i) * (poids(ni) * (*ex.jacobien_t));
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// idem SM_charge_surf_Suiv_E mais
+// -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid ElemThermi::SMR_charge_surf_Suiv_I (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& forc
+ ,const ParaAlgoControle & pa)
+ { // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
+ // *** sinon c'est intractable et long
+ double module_f = forc.Norme();
+ // dans le cas ou la force est de module nul, on retourne sans calcul
+ if (module_f < ConstMath::trespetit)
+ { Element::ResRaid el;
+ el.res = (*res_extS)(nSurf);
+ el.raid = (*raid_extS)(nSurf);
+ return el;
+ }
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ int nbddl = ddls.NbDdl();
+ Vecteur& SM = (*((*res_extS)(nSurf))); // " " "
+ Mat_pleine & KM = (*((*raid_extS)(nSurf))); // " " "
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul);
+ #ifdef MISE_AU_POINT
+ // test : a priori non valide pour les éléments axi et pour un pb autre que 3D
+ if (( ParaGlob::Dimension() != 3) || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
+ { cout << "\n erreur, ce type de chargement n'est valide pour pour la dimension 3 !! et non axi"
+ << " ElemThermi::SM_charge_line_Suiv_E ( ..."
+ << " \n dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ };
+ // test pour savoir si l'on a réellement affaire à une surface
+ if (ex.giB_t->NbVecteur() != 2)
+ { cout << "\n erreur, pb de nombre de vecteurs pour la surface !!"
+ << " ElemThermi::SM_charge_surf_Suiv_I (.... " << ex.giB_t->NbVecteur()
+ << " dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // détermination de la normale à la surface
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ Coordonnee normale_0 = Util::ProdVec_coorBN( (*ex.giB_0)(1), (*ex.giB_0)(2));
+ const Coordonnee& giB_tdt1 = (*ex.giB_tdt).Coordo(1); const Coordonnee& giB_tdt2 = (*ex.giB_tdt).Coordo(2);
+ Coordonnee normale_t = Util::ProdVec_coor( giB_tdt1, giB_tdt2);
+ // calcul des normales normées
+ normale_0.Normer();
+ double norme_normarle_t = normale_t.Norme();normale_t /= norme_normarle_t;
+ // calcul des composantes de direction de la force dans le repère local initial
+ Coordonnee dir_forceH_0(3);
+ // on ne veut pas de vérification de variance
+ dir_forceH_0(1) = giB_tdt1 * forc; dir_forceH_0(2) = giB_tdt2 * forc;
+ dir_forceH_0(3) = normale_0 * forc;
+ // calcul de la direction finale
+ Coordonnee dir_f_t = dir_forceH_0(1) * giB_tdt1 + dir_forceH_0(2) * giB_tdt2
+ + dir_forceH_0(3) * normale_t;
+ Coordonnee dir_f_t_normer = dir_f_t/(dir_f_t.Norme());
+ // calcul de la force finale
+ Coordonnee force_t = module_f * dir_f_t_normer;
+ // calcul du résidu et éventuellement de la raideur
+ int ix=1; int dimf = forc.Dimension(); // normalement ne fonctionne qu'en 3D
+ // sauf pour les éléments axisymétriques pour lesquelles on ne considère que les deux premières composantes
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force_t(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ Coordonnee d_giB_tdt1,d_giB_tdt2,d_dir_f_t; // def de vecteurs intermediaires
+ Coordonnee d_dir_f_t_normer; // " "
+ Coordonnee D_normale_pasnormer,D_normale_t;
+ if (avec_raid)
+ {for (int ne =1; ne<= nbne; ne++)
+ for (int j =1; j<= nbddl; j++)
+ { // calcul de la variation de la normale
+ // 1) variation du produit vectoriel pour la normale finale
+ D_normale_pasnormer = Util::ProdVec_coor(giB_tdt1,(*ex.d_giB_tdt)(j).Coordo(2))
+ + Util::ProdVec_coor((*ex.d_giB_tdt)(j).Coordo(1),giB_tdt2);
+ // 2) de la normale finale
+ D_normale_t = Util::VarUnVect_coor(normale_t,D_normale_pasnormer,norme_normarle_t);
+ // calcul des variations de la force
+ d_giB_tdt1 = ((((*ex.d_giB_tdt)(j))(1)).Coor());
+ d_giB_tdt2 = ((((*ex.d_giB_tdt)(j))(2)).Coor());
+ d_dir_f_t = dir_forceH_0(1) * d_giB_tdt1 + dir_forceH_0(2) * d_giB_tdt2
+ + dir_forceH_0(3) * D_normale_t;
+ d_dir_f_t_normer = Util::VarUnVect_coor( dir_f_t,d_dir_f_t,module_f);
+ for (int i=1;i<= dimf;i++)
+ { ix = i+ (ne-1)*dimf;
+ KM(ix,j) -= taphi(ni)(ne) * poids(ni)
+ * (force_t(i) *(*ex.d_jacobien_tdt)(j)
+ + (*ex.jacobien_tdt) * d_dir_f_t(i) );
+ }
+ }
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = (*res_extS)(nSurf);
+ el.raid = (*raid_extS)(nSurf);
+ return el;
+ };
+
+// cas d'un chargement volumique, sur l'élément
+// force indique la force volumique appliquée
+// retourne le second membre résultant
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_vol_E (DdlElement &
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & ,bool atdt )
+ {
+ #ifdef MISE_AU_POINT
+ // axisymétrie: pour l'instant non testé a priori avec les forces hydro
+ if(ParaGlob::AxiSymetrie())
+ { cout << "\n erreur, les charges volumique ne sont utilisable avec les elements axisymetriques"
+ << "\n utilisez à la place les charges surfaciques !! "
+ << " ElemThermi::SM_charge_vol_E ( ...";
+ Sortie(1);
+ };
+ #endif
+
+ // définition du vecteur de retour
+ Vecteur& SM = * residu;
+ int ni; // compteur globale de point d'integration
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ if (atdt)
+ ex = (def->Cal_explicit_tdt(premier_calcul)).Tdt_dans_t();
+ else
+ ex = def->Cal_explicit_t(premier_calcul);
+ int ix=1; int dimf = force.Dimension();
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.jacobien_t));
+ }
+ // retour du second membre
+ return SM;
+ };
+
+// cas d'un chargement volumique, sur l'élément
+// force indique la force volumique appliquée
+// retourne le second membre résultant -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+void ElemThermi::SMR_charge_vol_I(DdlElement & tab_ddl
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa)
+ {
+ #ifdef MISE_AU_POINT
+ // axisymétrie: pour l'instant non testé a priori avec les forces hydro
+ if(ParaGlob::AxiSymetrie())
+ { cout << "\n erreur, les charges volumique ne sont utilisable avec les elements axisymetriques"
+ << "\n utilisez à la place les charges surfaciques !! "
+ << " ElemThermi::SMR_charge_vol_I ( ...";
+ Sortie(1);
+ };
+ #endif
+ int ni; // compteur globale de point d'integration
+ int nbddl = tab_ddl.NbDdl();
+ Vecteur& SM = *residu;
+ Mat_pleine & KM = *raideur;
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+ {
+ // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = def->Cal_implicit(premier_calcul);
+ int ix=1; int dimf = force.Dimension();
+ if(ParaGlob::AxiSymetrie())
+ // cas d'un chargement axisymétrique, dans ce cas on ne prend en compte que les
+ // dimf-1 coordonnées donc on décrémente
+ dimf--;
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) +=
+ taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ KM(ix,j) -=
+ taphi(ni)(ne)* force(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j));
+ }
+ }
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ };
+
+// cas d'un chargement hydrostatique, sur les surfaces de l'élément
+// la charge dépend de la hauteur à la surface libre du liquide déterminée par un point
+// et une direction normale à la surface libre:
+// nSurf : le numéro de la surface externe
+// poidvol: indique le poids volumique du liquide
+// M_liquide : un point de la surface libre
+// dir_normal_liquide : direction normale à la surface libre
+// retourne le second membre résultant
+// calcul à l'instant tdt ou t en fonction de la variable atdt
+Vecteur& ElemThermi::SM_charge_hydro_E (DdlElement & ,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids
+ ,const Coordonnee& dir_normal_liquide,const double& poidvol
+ ,const Coordonnee& M_liquide
+ ,const ParaAlgoControle & ,bool atdt)
+ {
+ #ifdef MISE_AU_POINT
+ // axisymétrie: pour l'instant non testé a priori avec les forces hydro
+ if(ParaGlob::AxiSymetrie())
+ { cout << "\n erreur, les charges hydro ne sont pas testees avec les elements axisymetriques"
+ << " ElemThermi::SM_charge_hydro_E ( ...";
+ Sortie(1);
+ };
+ #endif
+
+ // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
+ // *** sinon c'est intractable et long
+ // définition du vecteur de retour
+ Vecteur& SM = *((*res_extS)(nSurf));
+ // dans le cas ou le poid volumique est nul, on retourne sans calcul
+ if (poidvol < ConstMath::trespetit)
+ return SM;
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul de la pression au niveau de la position du point d'intégration
+ // 1) on récupère la position dans I_a du point d'intégration
+ const Coordonnee & M = defS.Position_tdt();
+ // 2) calcul de la distance à la surface libre
+ Coordonnee MMp= M_liquide - M; double dis = dir_normal_liquide * MMp;
+ // 3) calcul de la pression effective uniquement si le point est dans l'eau
+ // en fait si le point est hors de l'eau il n'y a pas de pression hydrostatique
+ if (dis > 0.)
+ { double pression = -dis * poidvol;
+ // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ Met_abstraite::Expli ex;
+ if (atdt)
+ ex = (defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t();
+ else
+ ex = defS.Cal_explicit_t(premier_calcul);
+ // détermination de la normale à la surface
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on a réellement affaire à une surface
+ if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3))
+ { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3"
+ << " ElemThermi::SM_charge_hydro_E (DdlElement & ...nbvec= " << ex.giB_t->NbVecteur()
+ << " dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_t)(1), (*ex.giB_t)(2));
+ // calcul de la normale normée et pondérée de la pression
+ normale.Normer(); normale *= pression;
+ int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_t));
+ }// fin test : point dans le liquide ou pas
+ } // fin boucle sur les points d'intégrations
+ // retour du second membre
+ return SM;
+ };
+
+
+// idem SMR_charge_hydro_E mais
+// -> implicite,
+// pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+// retourne le second membre et la matrice de raideur correspondant
+Element::ResRaid ElemThermi::SMR_charge_hydro_I (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids
+ ,const Coordonnee& dir_normal_liquide,const double& poidvol
+ ,const Coordonnee& M_liquide
+ ,const ParaAlgoControle & pa)
+ {
+ #ifdef MISE_AU_POINT
+ // axisymétrie: pour l'instant non testé a priori avec les forces hydro
+ if(ParaGlob::AxiSymetrie())
+ { cout << "\n erreur, les charges hydro ne sont pas testees avec les elements axisymetriques"
+ << " ElemThermi::SM_charge_hydro_I ( ...";
+ Sortie(1);
+ };
+ #endif
+
+ // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
+ // *** sinon c'est intractable et long
+ // dans le cas ou le poid volumique est nul, on retourne sans calcul
+ if (poidvol < ConstMath::trespetit)
+ { Element::ResRaid el;
+ el.res = (*res_extS)(nSurf);
+ el.raid = (*raid_extS)(nSurf);
+ return el;
+ }
+ // controle
+ bool avec_raid = pa.Var_charge_externe();
+ int ni; // compteur globale de point d'integration
+ Deformation & defS = *defSurf(nSurf); // pour simplifier l'écriture
+ int nbddl = ddls.NbDdl();
+ Vecteur& SM = (*((*res_extS)(nSurf))); // " " "
+ Mat_pleine & KM = (*((*raid_extS)(nSurf))); // " " "
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
+ {
+ // calcul de la pression au niveau de la position du point d'intégration
+ // 1) on récupère la position dans I_a du point d'intégration
+ const Coordonnee & M = defS.Position_tdt();
+ // 2) calcul de la distance à la surface libre
+ Coordonnee MMp= M_liquide - M; double dis = dir_normal_liquide * MMp;
+ // 3) calcul de la pression effective uniquement si le point est dans l'eau
+ // en fait si le point est hors de l'eau il n'y a pas de pression hydrostatique
+ if (dis > 0.)
+ { double pression = -dis * poidvol;
+ // dans le cas avec raideur on calcul la variation de la pression
+ const Tableau * d_M_pointe = NULL;
+ if (avec_raid)
+ d_M_pointe=&(defS.Der_Posi_tdt());
+ // --- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+ // que pour un calcul primaire en implicit
+ const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul);
+ #ifdef MISE_AU_POINT
+ // test pour savoir si l'on a réellement affaire à une surface
+ if ((ex.giB_t->NbVecteur() != 2) || ( ParaGlob::Dimension() != 3))
+ { cout << "\n erreur, il doit y avoir deux vecteurs pour la surface de dimension 3"
+ << " ElemThermi::SMR_charge_hydro_I (.... " << ex.giB_t->NbVecteur()
+ << " dim = " << ParaGlob::Dimension();
+ Sortie(1);
+ }
+ #endif
+ // la normale vaut le produit vectoriel des 2 premiers vecteurs
+ CoordonneeB normale = Util::ProdVec_coorB( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2));
+ // calcul de la variation de la normale
+ // 1) variation du produit vectoriel
+ Tableau D_pasnormale =
+ Util::VarProdVect_coorB( (*ex.giB_tdt)(1),(*ex.giB_tdt)(2),(*ex.d_giB_tdt));
+ // 2) de la normale
+ Tableau D_normale = Util::VarUnVect_coorB(normale,D_pasnormale,normale.Norme());
+ // calcul de la normale normée et pondérée de la pression
+ normale.Normer(); normale *= pression;
+ // également pondération de la variation de la
+ if (avec_raid)
+ { for (int ihi =1;ihi<= nbddl;ihi++)
+ { double d_pression = poidvol * (dir_normal_liquide * (*d_M_pointe)(ihi));
+ // le - devant dis disparait avec le - devant M
+ D_normale(ihi) = pression * D_normale(ihi) + d_pression * normale ;
+ }
+ }
+ int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3
+ for (int ne =1; ne<= nbne; ne++)
+ for (int i=1;i<= dimf;i++,ix++)
+ { SM(ix) += taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.jacobien_tdt));
+ // dans le cas avec_raideur on calcul la contribution à la raideur
+ if (avec_raid)
+ for (int j =1; j<= nbddl; j++)
+ KM(ix,j) -=
+ taphi(ni)(ne)* normale(i) * (poids(ni) * (*ex.d_jacobien_tdt)(j))
+ + taphi(ni)(ne)* D_normale(j)(i) * (poids(ni) * (*ex.jacobien_tdt)) ;
+ }
+ }// fin test : point dans le liquide ou pas
+ } // fin boucle sur les points d'intégrations
+
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ Element::ResRaid el;
+ el.res = (*res_extS)(nSurf);
+ el.raid = (*raid_extS)(nSurf);
+ return el;
+ };
+
+
diff --git a/Elements/Thermique/ElemThermi.h b/Elements/Thermique/ElemThermi.h
new file mode 100755
index 0000000..28e5466
--- /dev/null
+++ b/Elements/Thermique/ElemThermi.h
@@ -0,0 +1,893 @@
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+/************************************************************************
+ * DATE: 06/03/2023 *
+ * $ *
+ * AUTEUR: G RIO (mailto:gerardrio56@free.fr) *
+ * $ *
+ * PROJET: Herezh++ *
+ * $ *
+ ************************************************************************
+ * BUT: Defini l'element generique de thermique. *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * *
+ * VERIFICATION: *
+ * *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * ! ! ! ! *
+ * $ *
+ * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' *
+ * MODIFICATIONS: *
+ * ! date ! auteur ! but ! *
+ * ------------------------------------------------------------ *
+ * $ *
+ ************************************************************************/
+#ifndef ELEMTHERMI_H
+#define ELEMTHERMI_H
+
+#include "Element.h"
+#include "Tenseur.h"
+#include "NevezTenseur.h"
+#include "Deformation.h"
+#include "Loi_comp_abstraite.h"
+#include "Enum_calcul_masse.h"
+#include "Basiques.h"
+#include "Enum_dure.h"
+#include "CompThermoPhysiqueAbstraite.h"
+#include "CompFrotAbstraite.h"
+#include "LesPtIntegThermiInterne.h"
+#include "Enum_StabHourglass.h"
+#include "EnergieThermi.h"
+
+
+/// @addtogroup groupe_des_elements_finis
+/// @{
+///
+
+class ElemThermi : public Element
+{
+ public :
+ // VARIABLES PUBLIQUES :
+
+ // CONSTRUCTEURS :
+ ElemThermi ();
+ // Constructeur utile quand le numero de maillage et d'identification de l'element est connu
+ ElemThermi (int num_maill,int num_id) ;
+ // Constructeur utile quand le numero de maillage et d'identification et le tableau des noeuds
+ // de l'element sont connu
+ ElemThermi (int num_maill,int num_id,const Tableau& tab);
+ // Constructeur utile quand le numero de maillage et d'identification est connu,
+ // ainsi que la geometrie et le type d'interpolation de l'element
+ ElemThermi (int num_maill,int num_id,Enum_interpol id_interp_elt,Enum_geom id_geom_elt,string info="");
+ // Constructeur utile quand le numero de maillage et d'identification est connu,
+ // ainsi que la geometrie et le type d'interpolation de l'element
+ ElemThermi (int num_maill,int num_id,char* nom_interpol,char* nom_geom,string info="");
+ // Constructeur utile quand toutes les donnees de la classe Element sont connues
+ ElemThermi (int num_maill,int num_id,const Tableau& tab,Enum_interpol id_interp_elt,
+ Enum_geom id_geom_elt,string info="");
+ // Constructeur utile quand toutes les donnees de la classe Element sont connues
+ ElemThermi (int num_maill,int num_id,const Tableau& tab,char* nom_interpol,
+ char* nom_geom,string info="");
+ // Constructeur de copie
+ ElemThermi (const ElemThermi& elt);
+
+ // DESTRUCTEUR :
+ ~ElemThermi ();
+
+ // METHODES PUBLIQUES :
+ // test si l'element est complet
+ // = 1 tout est ok, =0 element incomplet
+ int TestComplet();
+
+ // calcul si un point est a l'interieur de l'element ou non
+ // il faut que M est la dimension globale
+ // les trois fonctions sont pour l'etude a t=0, t et tdt
+ // retour : =0 le point est externe, =1 le point est interne ,
+ // = 2 le point est sur la frontière à la précision près
+ // coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées,
+ // uniquement précises si le point est interne
+ int Interne_0(const Coordonnee& M,Coordonnee* coor_locales=NULL);
+ int Interne_t(const Coordonnee& M,Coordonnee* coor_locales=NULL);
+ int Interne_tdt(const Coordonnee& M,Coordonnee* coor_locales=NULL);
+
+ // récupération des énergies intégrées sur l'éléments, résultants d'un précédent calcul
+ // explicite, ou implicite
+ const EnergieThermi& EnergieTotaleElement() const {return energie_totale;};
+
+ // test pour savoir si le calcul de Flux en absolu est possible
+ bool FluxAbsoluePossible();
+
+ // METHODES VIRTUELLES:
+
+ // retourne la liste de tous les types de ddl interne actuellement utilisés
+ // par l'élément (actif ou non), sont exclu de cette liste les ddl des noeuds
+ // reliés à l'élément (ddl implique grandeur uniquement scalaire !)
+ virtual List_io Les_type_de_ddl_internes(bool absolue) const ;
+ // idem pour les grandeurs évoluées c'est-à-dire directement sous forme de vecteur, tenseurs ....
+ virtual List_io Les_type_evolues_internes(bool absolue) const ;
+ // idem pour les données particulières
+ virtual List_io Les_types_particuliers_internes(bool absolue) const;
+
+ // retourne la liste de toutes les grandeurs quelconques relatives aux faces de
+ // l'élément (actif ou non),
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ virtual List_io Les_type_quelconque_de_face(bool absolue) const ;
+
+ // retourne la liste de toutes les grandeurs quelconques relatives aux arêtes de
+ // l'élément (actif ou non),
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ virtual List_io Les_type_quelconque_de_arete(bool absolue) const;
+
+ // --------- calculs utils dans le cadre de la recherche du flambement linéaire
+ // dans un premier temps uniquement virtuelles, ensuite se sera virtuelle pure pour éviter
+ // les oubli de définition ----> AMODIFIER !!!!!!!!
+ // Calcul de la matrice géométrique et initiale
+ class MatGeomInit // pour le retour des pointeurs sur des matrices stockées
+ // une paire par classe d'éléments
+ { public : MatGeomInit(Mat_pleine * matG,Mat_pleine * matI) :
+ matGeom(matG),matInit(matI) {};
+ Mat_pleine * matGeom ;Mat_pleine * matInit ;
+ };
+ virtual MatGeomInit MatricesGeometrique_Et_Initiale (const ParaAlgoControle & pa) ;
+
+// --------- calcul d'erreur, calculs du champs de Flux continu ---------
+ // ajout des ddl de Flux pour les noeuds de l'élément
+ virtual void Plus_ddl_Flux() = 0;
+ // inactive les ddl du problème de recherche d'erreur : les Flux
+ virtual void Inactive_ddl_Flux() = 0;
+ // active les ddl du problème de recherche d'erreur : les Flux
+ virtual void Active_ddl_Flux() = 0 ;
+ // active le premier ddl du problème de recherche d'erreur : FLUX
+ virtual void Active_premier_ddl_Flux() = 0 ;
+ // retourne un tableau de ddl element, correspondant à la
+ // composante de flux -> FLUX, pour chaque noeud qui contiend
+ // des ddl de flux
+ // -> utilisé pour l'assemblage de la raideur d'erreur
+ //!!!!!!!!!!!!! pour l'instant en virtuelle il faudra après en
+ // virtuelle pure !!!!!!!!!!!!!!!!!!!!!!!!!!!
+ virtual DdlElement& Tableau_de_Flux1() const ;
+ // retourne un tableau de ddl element, correspondant à la
+ // composante d'erreur -> ERREUR, pour chaque noeud
+ // -> utilisé pour l'assemblage de la raideur d'erreur
+ //dans cette version tous les noeuds sont supposés avoi un ddl erreur
+ // dans le cas contraire il faut redéfinir la fonction dans l'élément terminal
+ virtual DdlElement Tableau_de_ERREUR() const ;
+ // calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+ // qu'une fois la remontée aux Flux effectuées sinon aucune
+ // action. En retour la valeur de l'erreur sur l'élément
+ // type indique le type de calcul d'erreur :
+ // = 1 : erreur = (int (delta sigma):(delta sigma) dv)/(int sigma:sigma dv)
+ // le numerateur et le denominateur sont tel que :
+ // errElemRelative = numerateur / denominateur , si denominateur different de 0
+ // sinon denominateur = numerateur si numerateur est different de 0, sinon
+ // tous sont nuls mais on n'effectue pas la division
+ //!!!!!!!!!!!!! pour l'instant en virtuelle il faudra après en
+ // virtuelle pure !!!!!!!!!!!!!!!!!!!!!!!!!!!
+ virtual void ErreurElement(int type,double& errElemRelative
+ ,double& numerateur, double& denominateur);
+ // les 3 routines qui suivent sont virtuelles, car la définition
+ //qui est faite dans ElemThermi.cp considère qu'il y a un ddl erreur
+ // par noeud de l'élément de manière systématique,
+ // avec le status virtuel on peut définir dans la classe dérivée
+ // un cas particulier
+ // ajout des ddl d'erreur pour les noeuds de l'élément
+ virtual void Plus_ddl_Erreur() ;
+ // inactive les ddl d'erreur
+ virtual void Inactive_ddl_Erreur() ;
+ // active les ddl d'erreur
+ virtual void Active_ddl_Erreur() ;
+ // test pour savoir si l'erreur a été calculée
+ bool ErreurDejaCalculee()
+ { if (fluxErreur == NULL)
+ return false;
+ else return true;};
+ // sortie de l'erreur à l'élément
+ double Erreur( )
+ { return (*fluxErreur);};
+
+ // lecture de données diverses sur le flot d'entrée
+ // l'implantation est faite dans les classe dérivées
+ virtual void LectureFlux(UtilLecture * entreePrinc) =0 ;
+
+ // retour des Flux en absolu retour true si elle existe sinon false
+ virtual bool FluxAbsolues(Tableau & tabFlux) = 0;
+
+// --------- calcul dynamique ---------
+
+ // calcul de la longueur d'arrête de l'élément minimal
+ // divisé par la célérité dans le matériau
+ virtual double Long_arrete_mini_sur_c(Enum_dure temps) = 0;
+ // cas du bulk viscosity
+ double E_elem_bulk_t,E_elem_bulk_tdt,P_elem_bulk;
+ static void ActiveBulkViscosity(int choix) {bulk_viscosity=choix;};
+ static void InactiveBulkViscosity() {bulk_viscosity=false;};
+ static void ChangeCoefsBulkViscosity(const DeuxDoubles & coef)
+ { c_traceBulk=coef.un;c_carreBulk=coef.deux;};
+
+ // initialisation pour le calcul de la matrice masse dans le cas de l'algorithme
+ // de relaxation dynamique avec optimisation en continu de la matrice masse
+ // casMass_relax: permet de choisir entre différentes méthodes de calcul de la masse
+ void InitCalculMatriceMassePourRelaxationDynamique(int casMass_relax);
+ // phase de calcul de la matrice masse dans le cas de l'algo de relaxation dynamique
+ // mi=fonction de (alpha*K+beta*mu+gamma*Isig/3+theta/2*Sig_mises
+ // ep: epaisseur, K module de compressibilite, mu: module de cisaillement, Isig trace de sigma,
+ // Sig_mises la contrainte de mises
+ // casMass_relax: permet de choisir entre différentes méthodes de calcul de la masse
+ void CalculMatriceMassePourRelaxationDynamique
+ (const double& alph, const double& beta, const double & lambda
+ ,const double & gamma,const double & theta, int casMass_relax);
+
+// ---------- informations annexes ----------------
+
+ // récupération de la base locales au noeud noe, pour le temps: temps
+ const BaseB & Gib_elemeca(Enum_dure temps, const Noeud * noe);
+
+ // récupération de grandeurs particulières au numéro d'ordre = iteg
+ // celles-ci peuvent être quelconques
+ // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ void Grandeur_particuliere (bool absolue,List_io& liTQ,int iteg);
+
+ // récupération de grandeurs particulières pour une face au numéro d'ordre = iteg
+ // celles-ci peuvent être quelconques
+ // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ void Grandeur_particuliere_face (bool absolue,List_io& liTQ,int face, int iteg);
+
+ // récupération de grandeurs particulières pour une arête au numéro d'ordre = iteg
+ // celles-ci peuvent être quelconques
+ // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ void Grandeur_particuliere_arete (bool absolue,List_io& liTQ,int arete, int iteg);
+
+
+ // récupération de la loi de frottement, dans le cas où elle n'existe pas
+ // retour d'un pointeur nul
+ CompFrotAbstraite* LoiDeFrottement() const {return loiFrot;};
+
+ // --- transfert des grandeurs des points d'intégration aux noeuds
+ // transfert de ddl des points d'intégrations (de tous) d'un éléments (on ajoute aux noeuds, on ne remplace pas)
+ // les ddl doivent déjà exister aux noeuds sinon erreur
+ // il doit s'agir du même type de répartition de pt d'integ pour toutes les grandeurs
+ // tab_val(i)(j) : valeur associée au i ième pt d'integ et au j ième ddl_enum_etendu
+ void TransfertAjoutAuNoeuds(const List_io < Ddl_enum_etendu >& lietendu
+ ,const Tableau > & tab_val,int cas);
+ // transfert de type quelconque des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds,
+ // on ne remplace pas). Les types quelconques doivent déjà exister
+ // un tableau dans tab_liQ correspondent aux grandeurs quelconque pour tous les pt integ,
+ // tab_liQ(i) pour le pt d'integ i
+ // liQ_travail: est une liste de travail qui sera utilisée dans le transfert
+ void TransfertAjoutAuNoeuds(const Tableau >& tab_liQ
+ ,List_io < TypeQuelconque > & liQ_travail,int cas);
+
+ // accumulation aux noeuds de grandeurs venant de l'éléments vers ses noeuds (exemple la pression appliquée)
+ // autres que celles aux pti classiques, mais directements disponibles
+ // le contenu du conteneur stockées dans liQ est utilisé en variable intermédiaire
+ void Accumul_aux_noeuds(const List_io < Ddl_enum_etendu >& lietendu
+ ,List_io < TypeQuelconque > & liQ,int cas);
+
+
+ // modification de l'orientation de l'élément en fonction de cas_orientation
+ // =0: inversion simple (sans condition) de l'orientation
+ // si cas_orientation est diff de 0: on calcul le jacobien aux différents points d'intégration
+ // 1. si tous les jacobiens sont négatifs on change d'orientation
+ // 2. si tous les jacobiens sont positifs on ne fait rien
+ // 3. si certains jacobiens sont positifs et d'autres négatifs message
+ // d'erreur et on ne fait rien
+ // ramène true: s'il y a eu changement effectif, sinon false
+ bool Modif_orient_elem(int cas_orientation);
+
+ // 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
+ virtual int CalculNormale_noeud(Enum_dure temps, const Noeud& noe,Coordonnee& coor);
+
+ // calcul si un point est a l'interieur de l'element ou non
+ // il faut que M est la dimension globale
+ // retour : =0 le point est externe, =1 le point est interne ,
+ // = 2 le point est sur la frontière à la précision près
+ // coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées,
+ // uniquement précises si le point est interne
+ int Interne(Enum_dure temps,const Coordonnee& M,Coordonnee* coor_locales=NULL);
+ // -- connaissances particulières sur l'élément
+ // ramène l'épaisseur de l'élément
+ // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
+ virtual double Epaisseurs(Enum_dure , const Coordonnee& ) {return 0.;};
+ // ramène l'épaisseur moyenne de l'élément (indépendante du point)
+ // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
+ virtual double EpaisseurMoyenne(Enum_dure ) {return 0.;};
+ // ramène la section de l'élément
+ // =0. si la notion de section ne veut rien dire pour l'élément
+ virtual double Section(Enum_dure , const Coordonnee& ) {return 0.;};
+ // ramène la section moyenne de l'élément (indépendante du point)
+ // =0. si la notion de section ne veut rien dire pour l'élément
+ virtual double SectionMoyenne(Enum_dure ) {return 0.;};
+
+ // 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
+ virtual void Prise_en_compte_des_consequences_suppression_tous_frontieres();
+ // idem pour une frontière (avant qu'elle soit supprimée)
+ virtual void Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront);
+
+ // -------------------- calcul de frontières -------------------
+
+
+ // 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)
+ virtual ElFrontiere* const Frontiere_points(int num,bool force);
+
+ // 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)
+ virtual ElFrontiere* const Frontiere_lineique(int num,bool force);
+
+ // 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)
+ virtual ElFrontiere* const Frontiere_surfacique(int num,bool force);
+
+ // -------------------- init éventuelle avant le chargement -------------------
+ // initialisation éventuelle, nécessaire avant d'appliquer l'ensemble des charges
+ // par exemple des stockages intermédiaires
+ virtual void Initialisation_avant_chargement() {};
+
+//=====================================================================================
+ protected :
+//=====================================================================================
+ // METHODES PROTEGEES utilisables par les classes derivees :
+
+ // 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 const & Frontiere_elethermi(int cas, bool force = false);
+
+ // ---------------------------------------------------------------------
+ // cas où l'on intègre que selon une liste (un axe, un plan, un volume)
+ // ---------------------------------------------------------------------
+ // Calcul du residu local et de la raideur locale,
+ // pour le schema implicite d'ou a l'instant t + dt
+ // ddl represente les degres de liberte specifiques a l'element
+ // tabDepsBB = vitesse de déformation, tabDeltaEpsBB = incrément de def entre t et t+dt
+ // cald_Dvirtuelle = indique si l'on doit calculer la dérivée de la vitesse de déformation virtuelle
+ void Cal_implicit (DdlElement & tab_ddl,Tableau & d_gradTB
+ ,Tableau < Tableau2 * > d2_gradTB,Tableau & d_fluxH,int nbint
+ ,const Vecteur& poids,const ParaAlgoControle & pa,bool cald_DGradTvirtuelle);
+
+ // Calcul du residu local a l'instant t ou tdt
+ // atdt = true : calcul à tdt, valeur par défaut
+ // = false: calcul à t
+ // ddl represente les degres de liberte specifiques a l'element
+ // nbint = nb de pt d'integration , poids = poids d'integration
+ void Cal_explicit (DdlElement & ddl,Tableau & d_gradTB,int nbint
+ ,const Vecteur& poids,const ParaAlgoControle & pa,bool atdt=true);
+
+ // Calcul de la matrice géométrique et de la matrice initiale
+ // cette fonction est éventuellement appelée par les classes dérivées
+ // ddl represente les degres de liberte specifiques a l'element
+ // nbint = nb de pt d'integration , poids = poids d'integration
+ // cald_Dvirtuelle = indique si l'on doit calculer la dérivée de la vitesse de déformation virtuelle
+ void Cal_matGeom_Init (Mat_pleine & matGeom, Mat_pleine & matInit
+ ,DdlElement & ddl,Tableau & d_gradTB,Tableau < Tableau2 * > d2_gradTB
+ ,Tableau & d_fluxH,int nbint,const Vecteur& poids
+ ,const ParaAlgoControle & pa,bool cald_Dvirtuelle);
+
+ // Calcul de la matrice masse selon différent choix donné par type_matrice_masse,
+ // a l'instant initial.
+ void Cal_Mat_masse (DdlElement & tab_ddl,Enum_calcul_masse type_matrice_masse,
+ int nbint,const Tableau & taphi,int nbne
+ ,const Vecteur& poids);
+
+ // ---------------------------------------------------------------------
+ // cas où l'on intègre selon deux listes (ex un axe et un plan, etc.)
+ // ---------------------------------------------------------------------
+ // Calcul du residu local et de la raideur locale,
+ // pour le schema implicite d'ou a l'instant t + dt
+ // ddl represente les degres de liberte specifiques a l'element
+ void Cal_implicitap (DdlElement & tab_ddl,Tableau & d_epsBB
+ ,Tableau < Tableau2 * > d2_gradTB,Tableau & d_fluxH
+ ,int nbint1,Vecteur& poids1,int nbint2,const Vecteur& poids2
+ ,const ParaAlgoControle & pa);
+
+ // Calcul du residu local a l'instant t ou tdt
+ // atdt = true : calcul à tdt, valeur par défaut
+ // = false: calcul à t
+ // ddl represente les degres de liberte specifiques a l'element
+ // d_epsbb = variation des def
+ // nbint = nb de pt d'integration , poids = poids d'integration
+ void Cal_explicitap (DdlElement & ddl,Tableau & d_epsBB
+ ,int nbint,const Vecteur& poids,bool atdt=true);
+
+ // Calcul de la matrice géométrique et de la matrice initiale
+ // cette fonction est éventuellement appelée par les classes dérivées
+ // ddl represente les degres de liberte specifiques a l'element
+ // d_epsbb = variation des def
+ // nbint = nb de pt d'integration , poids = poids d'integration
+ void Cal_matGeom_Initap (Mat_pleine & matGeom, Mat_pleine & matInit
+ ,DdlElement & ddl,Tableau & d_epsBB,Tableau < Tableau2 * > d2_gradTB
+ ,Tableau & d_fluxH,int nbint,const Vecteur& poids);
+
+ // -------------------------- calcul de second membre ---------------------------
+ // calcul des seconds membres suivant les chargements
+ // cas d'un chargement surfacique, sur les frontières des éléments
+ // force indique la force surfacique appliquée
+ // retourne le second membre résultant
+ // nSurf : le numéro de la surface externe
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_surf_E (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_surf_E mais -> implicite,
+ // pa : permet de déterminer si l'on fait ou non le calcul de la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_surf_I (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa);
+ // calcul des seconds membres suivant les chargements
+ // cas d'un chargement pression, sur les frontières des éléments
+ // pression indique la pression appliquée
+ // retourne le second membre résultant
+ // nSurf : le numéro de la surface externe
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_pres_E (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,double pression
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_pres_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_pres_I (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,double pression
+ ,const ParaAlgoControle & pa);
+ // cas d'un chargement lineique, sur les arêtes frontières des éléments
+ // force indique la force lineique appliquée
+ // retourne le second membre résultant
+ // nArete : le numéro de l'arête externe
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_line_E (DdlElement & ddls,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_line_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_line_I (DdlElement & ddlA,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa);
+
+ // cas d'un chargement lineique suiveur, sur les arêtes frontières des éléments
+ // pas valable pour des éléments 3D !
+ // force indique la force lineique appliquée
+ // retourne le second membre résultant
+ // nArete : le numéro de l'arête externe
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_line_Suiv_E (DdlElement & ddls,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_line_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_line_Suiv_I (DdlElement & ddlA,int nArete
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa);
+
+
+ // cas d'un chargement surfacique suiveur, sur les surfaces de l'élément
+ // la direction varie selon le système suivant: on définit les coordonnées matérielles
+ // de la direction, ce qui sert ensuite à calculer les nouvelles directions. L'intensité
+ // elle est constante.
+ // force indique la force surfacique appliquée
+ // retourne le second membre résultant
+ // nSurf : le numéro de la surface externe
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_surf_Suiv_E (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_surf_Suiv_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_surf_Suiv_I (DdlElement & ddlA,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa);
+
+ // cas d'un chargement volumique, sur l'élément
+ // force indique la force volumique appliquée
+ // retourne le second membre résultant
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_vol_E (DdlElement & ddls
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa,bool atdt=true);
+
+ // idem SM_charge_vol_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ void SMR_charge_vol_I (DdlElement & ddls
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids,const Coordonnee& force
+ ,const ParaAlgoControle & pa);
+
+ // cas d'un chargement hydrostatique, sur les surfaces de l'élément
+ // la charge dépend de la hauteur à la surface libre du liquide déterminée par un point
+ // et une direction normale à la surface libre:
+ // nSurf : le numéro de la surface externe
+ // poidvol: indique le poids volumique du liquide
+ // M_liquide : un point de la surface libre
+ // dir_normal_liquide : direction normale à la surface libre
+ // retourne le second membre résultant
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ Vecteur& SM_charge_hydro_E (DdlElement & ddls,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids
+ ,const Coordonnee& dir_normal_liquide,const double& poidvol
+ ,const Coordonnee& M_liquide
+ ,const ParaAlgoControle & pa,bool atdt=true);
+ // idem SM_charge_hydro_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SMR_charge_hydro_I (DdlElement & ddlA,int nSurf
+ ,const Tableau & taphi,int nbne
+ ,const Vecteur& poids
+ ,const Coordonnee& dir_normal_liquide,const double& poidvol
+ ,const Coordonnee& M_liquide
+ ,const ParaAlgoControle & pa);
+
+ // cas d'un chargement aero-hydrodynamique, sur les frontières de l'élément
+ // Il y a trois forces: une suivant la direction de la vitesse: de type traînée aerodynamique
+ // Fn = poids_volu * fn(V) * S * (normale*u) * u, u étant le vecteur directeur de V (donc unitaire)
+ // une suivant la direction normale à la vitesse de type portance
+ // Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire, normal à V, et dans le plan n et V
+ // une suivant la vitesse tangente de type frottement visqueux
+ // T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
+ // retourne le second membre résultant
+ // calcul à l'instant tdt ou t en fonction de la variable atdt
+ // coef_mul: est un coefficient multiplicateur global (de tout)
+ Vecteur& SM_charge_hydrodyn_E (const double& poidvol,const Tableau & taphi,int nbne
+ ,Courbe1D* frot_fluid,const Vecteur& poids
+ ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul
+ ,Courbe1D* coef_aero_t,const ParaAlgoControle & ,bool atdt=true);
+ // idem SM_charge_hydrodyn_E mais -> implicite,
+ // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur
+ // retourne le second membre et la matrice de raideur correspondant
+ Element::ResRaid SM_charge_hydrodyn_I (const double& poidvol,const Tableau & taphi,int nbne
+ ,Courbe1D* frot_fluid,const Vecteur& poids,DdlElement & ddls
+ ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul
+ ,Courbe1D* coef_aero_t,const ParaAlgoControle & pa);
+
+ // -------------------- calcul de frontières en protected -------------------
+
+ // --- fonction nécessaire pour la construction des Frontières linéiques ou surfaciques particulière à l'élément
+ // adressage des frontières linéiques et surfacique
+ // définit dans les classes dérivées, et utilisées pour la construction des frontières
+ virtual ElFrontiere* new_frontiere_lin(int num,Tableau & tab, DdlElement& ddelem) = 0;
+ virtual ElFrontiere* new_frontiere_surf(int num,Tableau & tab, DdlElement& ddelem) = 0;
+
+ // -------------------- stabilisation d'hourglass -------------------
+ // calcul d'élément de contrôle d'hourglass associée à un comportement
+ void Init_hourglass_comp(const ElemGeomC0& elgeHour, const string & str_precision
+ ,LoiAbstraiteGeneral * loiHourglass,const BlocGen & bloc);
+
+ // stabilisation pour un calcul implicit
+ void Cal_implicit_hourglass();
+
+ // stabilisation pour un calcul explicit
+ void Cal_explicit_hourglass(bool atdt);
+
+ public :
+ // récupération de l'energie d'hourglass éventuelle
+ double Energie_Hourglass();
+ // idem pour l'énergie et la puissance de bulk viscosity
+ double Energie_Bulk() const {return E_elem_bulk_tdt;};
+ double Puissance_Bulk() const {return P_elem_bulk;};
+ protected :
+ // -------------------- calcul d'erreur, remontée des Flux -------------------
+
+ // calcul du résidu et de la matrice de raideur pour le calcul d'erreur
+ // cas d'une intégration suivant une seule liste
+ void FluxAuNoeud_ResRaid(const int nbne,const Tableau & taphi
+ ,const Vecteur& poids,Tableau & resErr,Mat_pleine& raidErr
+ ,const Tableau & taphiEr,const Vecteur& poidsEr );
+
+ // calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+ // qu'une fois la remontée aux Flux effectuées sinon aucune
+ // action. pour les autres arguments de retour, idem ErreurElement
+ // qui est la fonction generique, les autres variables sont spécifiques
+ // a l'element.
+ void Cal_ErrElem(int type,double& errElemRelative
+ ,double& numerateur, double& denominateur,const int nbne,const Tableau & taphi
+ ,const Vecteur& poids,const Tableau & taphiEr,const Vecteur& poidsEr);
+
+ // calcul de l'erreur aux noeuds. Contrairement au cas des Flux
+ // seul le résidu est calculé. Cas d'une intégration suivant une liste
+ void Cal_ErrAuxNoeuds(const int nbne, const Tableau & taphi,
+ const Vecteur& poids,Tableau & resErr );
+
+
+ // ---------------------------------------------------------------------
+ // affichage dans la sortie transmise, des variables duales "nom"
+ // aux differents points d'integration
+ // dans le cas ou nom est vide, affichage de "toute" les variables
+ // cas =1 -> premier passage pour de l'implicit
+ // cas = 2 -> premier passage pour de l'explicit
+ // cas = 11 -> passage autre que le premier pour de l'implicit
+ // cas = 12 -> passage autre que le premier pour de l'explicit
+ void VarDualSort(ofstream& sort, Tableau& nom,int nbint,int cas);
+ // utilitaires de VarDualSort
+ // affiche en fonction d'indic les differentes variables et appel
+ // AffDefContiD en fonction de la dimension i
+ //
+ void AffDefCont( ofstream& sort,CompThermoPhysiqueAbstraite::SaveResul * saveDon,
+ CoordonneeB& gradTB,Coordonnee& gradT,double& norme_gradT,
+ CoordonneeB& DgradTB,Coordonnee& DgradT,double& norme_dGradT,
+ CoordonneeH& fluxDH,Coordonnee & fluxD,double& norme_flux,
+ double& temperature, int indic);
+ // cas 1D
+ void AffDefCont1D( ofstream& sort,CompThermoPhysiqueAbstraite::SaveResul * saveDon,
+ CoordonneeB& gradTB,Coordonnee& gradT,double& norme_gradT,
+ CoordonneeB& DgradTB,Coordonnee& DgradT,double& norme_dGradT,
+ CoordonneeH& fluxDH,Coordonnee & fluxD,double& norme_flux,
+ double& temperature, int indic);
+ // cas 2D
+ void AffDefCont2D( ofstream& sort,CompThermoPhysiqueAbstraite::SaveResul * saveDon,
+ CoordonneeB& gradTB,Coordonnee& gradT,double& norme_gradT,
+ CoordonneeB& DgradTB,Coordonnee& DgradT,double& norme_dGradT,
+ CoordonneeH& fluxDH,Coordonnee & fluxD,double& norme_flux,
+ double& temperature, int indic);
+ // cas 3D
+ void AffDefCont3D( ofstream& sort,CompThermoPhysiqueAbstraite::SaveResul * saveDon,
+ CoordonneeB& gradTB,Coordonnee& gradT,double& norme_gradT,
+ CoordonneeB& DgradTB,Coordonnee& DgradT,double& norme_dGradT,
+ CoordonneeH& fluxDH,Coordonnee & fluxD,double& norme_flux,
+ double& temperature, int indic);
+
+
+ // ---------------------------------------------------------------------
+
+ // --- méthodes relatives aux calculs d'erreurs -----------
+ // ---- utilisées par les classes dérivées ---------
+ // ajout des ddl relatif aux Flux pour les noeuds de l'élément
+ void Ad_ddl_Flux(const DdlElement& tab_ddlErr);
+ // inactive les ddl du problème primaire de mécanique
+ void Inact_ddl_primaire(DdlElement& tab_ddl);
+ // active les ddl du problème primaire de mécanique
+ void Act_ddl_primaire(DdlElement& tab_ddl);
+ // inactive les ddl du problème de recherche d'erreur : les Flux
+ void Inact_ddl_Flux(DdlElement& tab_ddlErr);
+ // active les ddl du problème de recherche d'erreur : les Flux
+ void Act_ddl_Flux(DdlElement& tab_ddlErr);
+ // active le premier ddl du problème de recherche d'erreur : FLUX
+ void Act_premier_ddl_Flux();
+
+ // ---------------------------------------------------------------------
+ // lecture des Flux sur le flot d'entrée
+ void LectureDesFlux
+ (bool cas,UtilLecture * entreePrinc,Tableau & tabfluxH);
+
+ // retour des Flux en absolu retour true si ils existent sinon false
+ void FluxEnAbsolues
+ (bool cas,Tableau & tabfluxH,Tableau & tabflux);
+
+
+ // ---------------- lecture écriture dans base info ----------------
+ // programmes utilisés par les classes dérivées
+
+ // cas donne le niveau de la récupération
+ // = 1 : on récupère tout
+ // = 2 : on récupère uniquement les données variables (supposées comme telles)
+ void Lecture_bas_inf
+ (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas) ;
+ // cas donne le niveau de sauvegarde
+ // = 1 : on sauvegarde tout
+ // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
+ void Ecriture_bas_inf(ofstream& sort,const int cas) ;
+
+ // --------- utilitaires pour la dynamique
+ // calcul de la longueur d'arrête de l'élément minimal
+ // divisé par la célérité la plus rapide dans le matériau
+ // appelé par les classes dérivées
+ // nb_noeud : =0 indique que l'on utilise tous les noeuds du tableau de noeuds
+ // = un nombre > 0, indique le nombre de noeuds à utiliser au début du tableau
+ double Interne_Long_arrete_mini_sur_c(Enum_dure temps,int nb_noeud=0);
+
+ // recuperation des coordonnées du point d'intégration numéro = iteg pour
+ // la grandeur enu
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee CoordPtInt(Enum_dure temps,Enum_ddl enu,int iteg,bool& erreur);
+
+ // recuperation des coordonnées du point d'intégration numéro = iteg pour
+ // la face : face
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee CoordPtIntFace(int face, Enum_dure temps,int iteg,bool& erreur);
+ // recuperation des coordonnées du point d'intégration numéro = iteg pour
+ // la face : face
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee CoordPtIntArete(int arete, Enum_dure temps,int iteg,bool& erreur);
+
+
+ // procesure permettant de completer l'element, en ce qui concerne les variables gérés
+ // par ElemThermi, apres sa creation avec les donnees du bloc transmis
+ // peut etre appeler plusieurs fois
+ Element* Complete_ElemThermi(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD);
+
+ // retourne le numero du pt d'ing le plus près ou est exprimé la grandeur enum
+ // temps: dit si c'est à 0 ou t ou tdt
+ int PtLePlusPres(Enum_dure temps,Enum_ddl enu, const Coordonnee& M);
+
+ // récupération des valeurs au numéro d'ordre = iteg pour
+ // les grandeur enu
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ Tableau Valeur_multi(bool absolue,Enum_dure enu_t,const List_io& enu
+ ,int iteg,int cas ) ;
+
+ // récupération des valeurs Tensorielles (et non scalaire comme avec Valeur_multi)
+ // au numéro d'ordre = iteg pour les grandeur enu
+ // enu contiend les grandeurs de retour
+ // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+ void Valeurs_Tensorielles(bool absolue,Enum_dure enu_t,List_io& enu
+ ,int iteg,int cas ) ;
+
+ // ==== >>>> methodes virtuelles definis dans les classes mères ============
+ // ramene l'element geometrique correspondant au ddl passé en paramètre
+ virtual ElemGeomC0& ElementGeometrie(Enum_ddl ddl) const ;
+ // ramène le nombre de grandeurs génératrices pour un pt d'integ, correspondant à un type enuméré
+ // peut-être surchargé pour des éléments particuliers
+ virtual int NbGrandeurGene(Enum_ddl enu) const;
+
+ // ==== >>>> methodes virtuelles definis dans les classes dérivées ============
+ // ramene la dimension des vecteurs flux et gradient de température de l'élément
+ virtual int Dim_flux_gradT() const = 0;
+
+ // VARIABLES PROTEGEES :
+
+ //---- variables: Flux, déformations etc.. aux points d'intégrations -------
+ // lesPtIntegThermiInterne pointe vers une entitée entièrement gérés par les classes dérivées
+ // contenant les grandeurs mécaniques (Flux, déformations etc.) stockées aux points d'intégration
+ LesPtIntegThermiInterne * lesPtIntegThermiInterne;
+
+ Loi_comp_abstraite * loiComp; // loi de comportement mécanique defini dans les classes derivees
+ CompThermoPhysiqueAbstraite * loiTP; // éventuellement une loi de comportement thermo physique
+ // defini dans les classes derivees
+ CompFrotAbstraite * loiFrot; // éventuellement une loi de comportement au frottement pour ses frontières
+
+ bool dilatation; // indique si oui ou non on tiend compte de la dilatation thermique
+ Met_abstraite * met; // definition specifique dans les classes derivees
+ Deformation * def; // definition specifique dans les classes derivees
+ // mais relative à la déformation mécanique
+ Deformation * defEr; // idem que def mais pour la remonte aux Flux
+ Tableau defSurf; // idem mais pour les déformations des surfaces
+ // externes (frontières) si cela est nécessaire
+ Tableau defArete; // idem mais pour les déformations des arretes
+ // externes (frontières) si cela est nécessaire
+ Deformation * defMas; // idem que def mais pour le calcul de la matrice masse
+ double* fluxErreur; // erreur sur l'élément dans le calcul des densités de flux;
+ Tableau tabSaveDon; // donnée particulière à la loi mécanique
+ Tableau tabSaveTP; // donnée parti à la loi thermo physique
+ Tableau tabSaveDefDon; // donnée particulière pour la déf
+ Tableau tab_energ,tab_energ_t; //les différentes énergies mécaniques mises en jeux
+ // dimensionné dans les classes dérivées, a t+dt, et a t
+ EnergieThermi energie_totale; // le bilan sur l'élément de l'énergie
+ bool premier_calcul_thermi_impli_expli; // au premier calcul soit en implicite, explicite, mat geom
+ // toutes les grandeurs à t=0 de la métrique sont calculées et stockées dans la déformation
+ // ensuite elles ne sont plus calculées -> premier_calcul_thermi_impli_expli sert pour l'indiquer
+ double masse_volumique; // masse volumique de l'élément
+ //--- stabilisation d'hourglass éventuelle
+ Enum_StabHourglass type_stabHourglass; // méthode de stabilisation
+ double E_Hourglass;
+
+ private:
+ Tableau tab_elHourglass; // tableau de pointeurs éventuels sur des éléments servant à la stabilisation
+ // les éléments sont définies au travers de l'appel à la méthode Cal_hourglass_comp, par une classe dérivée,
+ double coefStabHourglass ; // coef de stabilisation
+ Mat_pleine* raid_hourglass_transitoire; // raideur transitoire d'hourglass, éventuellement définie
+
+ // -------- pour faciliter les routines Interne_t _0 et _tdt + paramètres de contrôle ----
+ static const Coordonnee & (Met_abstraite::*PointM)
+ (const Tableau& tab_noeud,const Vecteur& phi);
+ static void (Met_abstraite::*BaseND)
+ (const Tableau& tab_noeud,
+ const Mat_pleine& dphi,const Vecteur& phi,BaseB& bB,BaseH& bH);
+ // ---------- cas du bulk viscosity -------------
+ private: // pour éviter les modifications par les classes dérivées
+ static int bulk_viscosity; // indique si oui ou non on utilise le bulk viscosity
+ // en plus = 1: fonctionnement normal, =2 fonctionnement quelque soit
+ // le signe de IDeps
+ static double c_traceBulk; // coeff de la trace de D pour le bulk
+ static double c_carreBulk; // coeff du carré de la trace de D pour le bulk
+ static TenseurHH * sig_bulkHH; // variable de travail pour le bulk
+ // ---------- pour le calcul de la masse pour la méthode de relaxation dynamique
+ static Ddl_enum_etendu masse_relax_dyn; // simplement pour le définir une fois pour toute
+
+ protected:
+ // pour une utilisation par les classes dérivées
+ inline bool Bulk_visco_actif() {return bulk_viscosity;};
+ inline double& C_traceBulk() {return c_traceBulk;};
+ inline double& C_carreBulk() {return c_carreBulk;};
+// // calcul du Flux modifiée en fonction du bulk viscosity
+// // ramène l'énergie et la puissance par unité de volume, dépensée par le bulk
+// DeuxDoubles ModifContrainteBulk(const TenseurHH& gijHH_tdt,TenseurHH & sigHH,const TenseurBB & DepsBB_tdt
+// ,TenseurHH & sigbulkHH);
+ // actualisation des ddl et des grandeurs actives de t+dt vers t
+ void TdtversT_();
+ // actualisation des ddl et des grandeurs actives de t vers tdt
+ void TversTdt_();
+
+ // ---- utilitaires interne
+ private:
+ // calcul du mini du module d'young équivalent pour tous les points d'intégrations
+ double Calcul_mini_E_qui(Enum_dure temps);
+ // calcul du maxi du module d'young équivalent pour tous les points d'intégrations
+ double Calcul_maxi_E_qui(Enum_dure temps);
+ };
+/// @} // end of group
+
+
+
+#endif
diff --git a/Elements/Thermique/ElemThermi2.cc b/Elements/Thermique/ElemThermi2.cc
new file mode 100755
index 0000000..567663b
--- /dev/null
+++ b/Elements/Thermique/ElemThermi2.cc
@@ -0,0 +1,957 @@
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+//#include "Debug.h"
+#include "ElemThermi.h"
+#include
+#include "ConstMath.h"
+#include "Util.h"
+#include "Coordonnee2.h"
+#include "Coordonnee3.h"
+#include "CharUtil.h"
+
+
+// actualisation des ddl et des grandeurs actives de t+dt vers t
+// appelé par les classes dérivées
+void ElemThermi::TdtversT_()
+ {// on met à jour l'indicateur de premier calcul
+ // s'il y a des sauvegardes de grandeur aux déformations
+ // on ne regarde que le premier élément de tableau, a priori
+ // il y a toujours un pt d'integ et l'organisation est identique pour tous les pt d'integ
+ if (tabSaveDefDon(1) != NULL)
+ premier_calcul_thermi_impli_expli=false;
+ // cas des énergies
+ int nbi= tab_energ.Taille();
+ for (int ni=1;ni<= nbi; ni++)
+ tab_energ_t(ni) = tab_energ(ni);
+ E_elem_bulk_t = E_elem_bulk_tdt; // énergie due au bulk viscosity
+ };
+// actualisation des ddl et des grandeurs actives de t vers tdt
+// appelé par les classes dérivées
+void ElemThermi::TversTdt_()
+ {// on met à jour l'indicateur de premier calcul
+ // on considère que si l'on revient en arrière, il vaut mieux re-initialiser les
+ // grandeurs correspondantes au premier_calcul
+ // s'il y a des sauvegardes de grandeur aux déformations
+ if (tabSaveDefDon(1) != NULL)
+ premier_calcul_thermi_impli_expli=true;
+ // cas des énergies
+ int nbi= tab_energ.Taille();
+ for (int ni=1;ni<= nbi; ni++)
+ tab_energ(ni) = tab_energ_t(ni);
+ E_elem_bulk_tdt = E_elem_bulk_t; // énergie due au bulk viscosity
+ };
+
+// calcul du résidu et de la matrice de raideur pour le calcul d'erreur
+// cas d'une intégration suivant une seule liste
+void ElemThermi::FluxAuNoeud_ResRaid(const int nbne,const Tableau & taphi
+ ,const Vecteur& poids,Tableau & resErr,Mat_pleine& raidErr
+ ,const Tableau & taphiEr,const Vecteur& poidsEr)
+ { int dimAbsolue = ParaGlob::Dimension(); // dimension absolue
+// // dimension des tenseurs
+// int dim = lesPtIntegThermiInterne->DimTens();
+// // inialisation du second membre et de la raideur
+// int nbSM = resErr.Taille(); // nombre de second membre
+// for (int j =1; j<= nbSM; j++) // boucle sur les seconds membres
+// (*resErr(j)).Zero();
+// raidErr.Zero();
+// // Il faut déterminer l'ordre dans lequel on parcours les contraintes qui doit
+// // être compatible avec l'ordre des ddl
+// Tableau2 ordre = OrdreContrainte(nbSM);
+// // création d'un tenseur au dimension absolu pour le calcul des contraintes
+// // dans la base absolue
+// TenseurHH& sigHH = *(NevezTenseurHH(dimAbsolue)) ;
+// // ====== calcul du second membre =======
+// int ni; // compteur globale de point d'integration
+// bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+// // donc il faut calculer tous les éléments de la métrique
+// for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+// {PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni);
+// // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+// // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+// const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
+// // passage dans le repère absolu du tenseur contrainte final
+// sigHH = (*(ptIntegThermi.SigHH_t())).BaseAbsolue(sigHH,*ex.giB_t);
+// for (int ne =1; ne<= nbne; ne++) // 1ere boucle sur les noeuds
+// { // les résidus : mais il faut suivre l'ordre de l'enregistrement des ddl
+// for (int itot = 1; itot<= nbSM; itot++)
+// { int ix = (int) (ordre(itot,1)); int iy = (int) (ordre(itot,2));
+// (*resErr(itot))(ne) += taphi(ni)(ne)*sigHH(ix,iy) * (poids(ni) * (*ex.jacobien_t));
+// }
+// }
+// }
+// // ====== calcul de la raideur c'est à dire du hessien ========
+// // boucle sur les pt d'integ spécifiques à l'erreur
+// for (defEr->PremierPtInteg(), ni = 1;defEr->DernierPtInteg();defEr->NevezPtInteg(),ni++)
+// {
+// // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+// // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+// const Met_abstraite::Expli& ex = defEr->Cal_explicit_t(premier_calcul);
+// for (int ne =1; ne<= nbne; ne++) // 1ere boucle sur les noeuds
+// for (int me =1; me<= nbne; me++) // 2ere boucle sur les noeuds
+// raidErr(ne,me) += taphiEr(ni)(ne) * taphiEr(ni)(me) * poidsEr(ni) * (*ex.jacobien_t);
+// }
+// // liberation des tenseurs intermediaires
+// TenseurHH * ptsigHH = &sigHH; delete ptsigHH;
+// LibereTenseur();
+// // calcul de l'erreur relative
+
+ };
+
+// calcul de l'erreur sur l'élément. Ce calcul n'est disponible
+// qu'une fois la remontée aux contraintes effectuées sinon aucune
+// action. En retour la valeur de l'erreur sur l'élément
+// = 1 : erreur = (int (delta sigma):(delta sigma) dv)/(int sigma:sigma dv)
+// le numerateur et le denominateur sont tel que :
+// errElemRelative = numerateur / denominateur , si denominateur different de 0
+// sinon denominateur = numerateur si numerateur est different de 0, sinon
+// tous sont nuls mais on n'effectue pas la division , les autres variables sont spécifiques
+ // a l'element.
+void ElemThermi::Cal_ErrElem(int type,double& errElemRelative,double& numerateur
+ , double& denominateur,const int nbne,const Tableau & taphi
+ ,const Vecteur& poids,const Tableau & taphiEr,const Vecteur& poidsEr)
+ { int dimAbsolue = ParaGlob::Dimension(); // dimension absolue
+// // dimension des tenseurs
+// int dim = lesPtIntegThermiInterne->DimTens();
+// bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+// // donc il faut calculer tous les éléments de la métrique
+// switch (type)
+// {case 1 : // cas du calcul aux moindres carrés
+//
+// {// création d'un tenseur au dimension absolu pour le calcul des contraintes
+// // dans la base absolue, on le choisit HB pour le double produit contracté
+// // mais en absolu la variance n'a pas d'importance
+// TenseurHB& sigHB = *(NevezTenseurHB(dimAbsolue)) ;
+// // idem au point d'intégration et un tenseur nul pour l'initialisation
+// TenseurHB& signiHB = *(NevezTenseurHB(dimAbsolue)) ;
+// TenseurHB& sigiHB = *(NevezTenseurHB(dimAbsolue)) ; // tenseur de travail
+// TenseurHB& nulHB = *(NevezTenseurHB(dimAbsolue)) ;
+// // ====== calcul des termes de l'erreur =======
+// // ---- tout d'abord on parcourt les points d'intégration de la mécanique
+// numerateur = 0.; denominateur = 0.; // initialisation
+// int ni; // compteur globale de point d'integration
+// for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+// {PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni);
+// // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+// // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+// const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
+// // passage dans le repère absolu du tenseur contrainte initiale
+// sigHB = (*(ptIntegThermi.SigHH_t())).BaseAbsolue(sigHB,*ex.giB_t);
+// // calcul du denominateur
+// denominateur += (sigHB && sigHB) * (poids(ni) * (*ex.jacobien_t));
+// // calcul de la premiere partie du numerateur, celle qui dépend des points d'intégration
+// // mécanique.
+// // 1) calcul au point d'intégration du tenseur des contraintes défini aux noeuds,
+// signiHB = nulHB; // initialisation
+// for (int ne =1; ne<= nbne; ne++) // boucle sur les noeuds
+// signiHB += taphi(ni)(ne) * ((tab_noeud(ne))->Contrainte(sigiHB));
+// // 2) intégrale de la partie dépendant de ni
+// numerateur += denominateur - 2 * (signiHB && sigHB) * (poids(ni) * (*ex.jacobien_t)) ;
+// }
+// // ---- on parcourt maintenant les points d'intégration pour le calcul d'erreur
+// // ---- ce qui permet de calculer la deuxième partie du numérateur
+// // boucle sur les pt d'integ spécifiques à l'erreur
+// for (defEr->PremierPtInteg(), ni = 1;defEr->DernierPtInteg();defEr->NevezPtInteg(),ni++)
+// {
+// // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+// // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+// const Met_abstraite::Expli& ex = defEr->Cal_explicit_t(premier_calcul);
+// // 1) calcul au point d'intégration du tenseur des contraintes défini aux noeuds,
+// signiHB = nulHB; // initialisation
+// for (int ne =1; ne<= nbne; ne++) // boucle sur les noeuds
+// signiHB += taphiEr(ni)(ne)*(tab_noeud(ne))->Contrainte(sigiHB);
+// // 2) intégrale de la partie dépendant de ni
+// numerateur += (signiHB && signiHB) * poidsEr(ni) * (*ex.jacobien_t);
+// }
+// // liberation des tenseurs intermediaires
+// TenseurHB * ptsigHB = &sigHB; delete ptsigHB;
+// ptsigHB = &signiHB; delete ptsigHB;ptsigHB = &sigiHB; delete ptsigHB;
+// ptsigHB = &nulHB; delete ptsigHB;
+// LibereTenseur();
+// // enregistrement de l'erreur pour l'élément
+// if (sigErreur == NULL) sigErreur = new double;
+// *sigErreur = numerateur;
+// break;
+// }
+// default :
+// { cout << "\nErreur : valeur incorrecte du type de calcul d'erreur !\n";
+// cout << "ElemThermi::ErreurElement(int type , type = \n" << type;
+// Sortie(1);
+// }
+// };
+// // --- calcul de l'erreur relative
+// if (denominateur <= ConstMath::trespetit)
+// // cas d'un champ de contraintes nulles initialement
+// if (numerateur <= ConstMath::trespetit)
+// // cas également du numérateur nul
+// errElemRelative = 0.;
+// else
+// // on fait denominateur = numérateur -> erreur relative = 1
+// errElemRelative = 1.;
+// else
+// // cas du dénominateur non nul
+// errElemRelative = numerateur / denominateur;
+ };
+
+
+// calcul de l'erreur aux noeuds. Contrairement au cas des contraintes
+// seul le résidu est calculé. Cas d'une intégration suivant une liste
+void ElemThermi::Cal_ErrAuxNoeuds(const int nbne, const Tableau & taphi,
+ const Vecteur& poids,Tableau & resErr )
+ { int dimAbsolue = ParaGlob::Dimension(); // dimension absolue
+// // inialisation du second membre, on utilise le premier vecteur uniquement
+// (*resErr(1)).Zero();
+// // ====== calcul du second membre =======
+// int ni; // compteur globale de point d'integration
+// double volume = 0.; // le volume de l'élément
+// bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+// // donc il faut calculer tous les éléments de la métrique
+// for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+// {
+// // calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
+// // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+// const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
+// for (int ne =1; ne<= nbne; ne++) // 1ere boucle sur les noeuds
+// (*resErr(1))(ne) += taphi(ni)(ne)*(*sigErreur) * (poids(ni) * (*ex.jacobien_t));
+// // calcul du volume
+// volume += (poids(ni) * (*ex.jacobien_t));
+// }
+// // on relativise par rapport au volume, car initialement sigErreur représente l'erreur
+// // totale sur tout l'élément. Donc on divise par le volume pour retrouver après résolution
+// // une valeur au noeud qui représente une valeur ponctuelle et non une valeur qui
+// // qui est relative à un volume
+// *resErr(1) /= volume;
+//// *resErr(1) = -sigErreur;
+// LibereTenseur();
+// // calcul de l'erreur relative
+
+ };
+
+
+// ajout des ddl relatif aux contraintes pour les noeuds de l'élément
+void ElemThermi::Ad_ddl_Flux(const DdlElement& tab_ddlErr)
+ { int nbne = tab_noeud.Taille();
+// for (int ne=1; ne<= nbne; ne++) // pour chaque noeud
+// { // création du tableau de ddl
+// int tab_ddlErr_Taille = tab_ddlErr(ne).tb.Taille(); // nb de ddl du noeud Thermi
+// Tableau ta(tab_ddlErr_Taille);
+// for (int i =1; i<= tab_ddlErr_Taille; i++)
+// ta(i) = Ddl (tab_ddlErr(ne).tb(i),0.,LIBRE);
+// // ajout du tableau dans le noeud
+// tab_noeud(ne)->PlusTabDdl(ta);
+// }
+ };
+
+// inactive les ddl du problème primaire de mécanique
+void ElemThermi::Inact_ddl_primaire(DdlElement& tab_ddl)
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_hors_service(tab_ddl(ne).tb);
+ };
+// active les ddl du problème primaire de mécanique
+void ElemThermi::Act_ddl_primaire(DdlElement& tab_ddl)
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_en_service(tab_ddl(ne).tb);
+ };
+// inactive les ddl du problème de recherche d'erreur : les contraintes
+void ElemThermi::Inact_ddl_Flux(DdlElement& tab_ddlErr)
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_hors_service(tab_ddlErr(ne).tb);
+ };
+// active les ddl du problème de recherche d'erreur : les contraintes
+void ElemThermi::Act_ddl_Flux(DdlElement& tab_ddlErr)
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_en_service(tab_ddlErr(ne).tb);
+ };
+// active le premier ddl du problème de recherche d'erreur : FLUX1
+void ElemThermi::Act_premier_ddl_Flux()
+ { int nbne = tab_noeud.Taille();
+ for (int ne=1; ne<= nbne; ne++)
+ tab_noeud(ne)->Met_en_service(FLUXD1);
+ };
+
+// retourne un tableau de ddl element, correspondant à la
+// composante de densité de flux -> FLUXD1, pour chaque noeud qui contiend
+// des ddl de contrainte
+// -> utilisé pour l'assemblage de la raideur d'erreur
+DdlElement& ElemThermi::Tableau_de_Flux1() const
+ { cout << "\n erreur, fonction non defini pour cette element "
+ << "\n ElemThermi::Tableau_de_Flux1()" << endl;
+ Sortie(1);
+ DdlElement * toto = new DdlElement();
+ return *toto;
+ };
+
+// lecture des flux sur le flot d'entrée
+void ElemThermi::LectureDesFlux(bool cas,UtilLecture * entreePrinc,Tableau & tabfluxH)
+ { // dimensionnement de la metrique identique au cas d'un calcul explicite
+ if( cas)
+ { Tableau tab(7);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ met->PlusInitVariables(tab) ;
+ };
+ int dimAbsolue = ParaGlob::Dimension(); // dimension absolue
+ // dimension des flux
+ int dim = (*(tabfluxH(1))).Dimension();
+ // création d'un Coordonnee au dimension absolu pour récupérer les flux
+ // dans la base absolue
+ Coordonnee flux(dimAbsolue) ;
+ int ni; // compteur globale de point d'integration
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+ { // calcul des éléments de la métrique, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
+ for (int i=1;i<= dimAbsolue;i++)
+ // récupération des coordonnées du flux en absolu
+ *(entreePrinc->entree) >> flux(i);
+ // passage dans le repère local du flux final
+ CoordonneeH & fluxH = *tabfluxH(ni); // pour simplifier
+ fluxH.Change_dim(dim);
+ for (int i = 1;i<=dim;i++)
+ fluxH(i) = ex.giH_t->Coordo(i) * flux;
+ }
+ };
+
+
+// retour des flux en absolu retour true si ils existes sinon false
+void ElemThermi::FluxEnAbsolues
+ (bool cas,Tableau & tabfluxH,Tableau & tabflux)
+ { // dimensionnement de la metrique identique au cas d'un calcul explicite
+ if( cas)
+ { Tableau tab(7);
+ tab(1) = igiB_0; tab(2) = igiB_t; tab(3) = igijBB_0;tab(4) = igijBB_t;
+ tab(5) = igijHH_t; tab(6) = id_giB_t; tab(7) = id_gijBB_t ;
+ met->PlusInitVariables(tab) ;
+ };
+ int dimAbsolue = ParaGlob::Dimension(); // dimension absolue
+ // dimension des tenseurs
+ int dim = (*(tabfluxH(1))).Dimension();
+ // redimensionnement éventuel du tableau de sortie
+ int nbi = tabfluxH.Taille();
+ if (tabflux.Taille() != nbi)
+ tabflux.Change_taille(nbi);
+ for (int ni=1;ni<= nbi;ni++)
+ if ( tabflux(ni).Taille() != dimAbsolue)
+ tabflux(ni).Change_taille(dimAbsolue);
+ int ni; // compteur globale de point d'integration
+ bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
+ // donc il faut calculer tous les éléments de la métrique
+ for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
+ { // calcul des éléments de la métrique, on utilise le même calcul
+ // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
+ const Met_abstraite::Expli& ex = def->Cal_explicit_t(premier_calcul);
+ // passage dans le repère global du flux local
+ Coordonnee flux; // init à 0
+ for (int i=1;i<= dim;i++)
+ flux += (*tabfluxH(ni))(i) * (ex.giB_t->Coordo(i));
+ };
+ };
+
+// ---------------- lecture écriture dans base info ----------------
+ // programmes utilisés par les classes dérivées
+
+ // cas donne le niveau de la récupération
+ // = 1 : on récupère tout
+ // = 2 : on récupère uniquement les données variables (supposées comme telles)
+void ElemThermi::Lecture_bas_inf
+ (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas)
+ { // appel de la routine d'élément
+ Element::Lect_bas_inf_element(ent,tabMaillageNoeud,cas);switch (cas)
+ { case 1 : // ------- on récupère tout -------------------------
+ { string toto,nom;
+ // récup de la masse volumique
+ ent >> toto >> masse_volumique ;
+ // données thermique
+ ent >> toto >> dilatation;
+ // blocage éventuelle d'hourglass
+ ent >> toto >> nom;
+ type_stabHourglass=Id_Nom_StabHourglass(nom.c_str());
+ break;
+ }
+ case 2 : // ----------- lecture uniquement de se qui varie --------------------
+ { break;
+ }
+ default :
+ { cout << "\nErreur : valeur incorrecte du type de lecture !\n";
+ cout << "ElemThermi::Lecture_bas_inf (ifstream& ent,const int cas)"
+ << " cas= " << cas << endl;
+ Sortie(1);
+ }
+ }
+ // ------ lecture dans tous les cas -------
+ // résultat d'erreur
+ string toto;
+ ent >> toto;
+ if (toto == "erreur_de_densite_flux")
+ { if (fluxErreur == NULL)
+ fluxErreur = new double;
+ ent >> (*fluxErreur) ;
+ }
+ // données particulière pour les lois de comportement mécanique
+ int tabSaveDonTaille = tabSaveDon.Taille();
+ if ((tabSaveDonTaille != 0) && (tabSaveDon(1) != NULL)) ent >> toto;
+ int num ; // numéro du pt d'integ, n'est pas vraiment utilisé mais c'est mieux que de lire un string
+ for (int i=1; i<= tabSaveDonTaille; i++)
+ if (tabSaveDon(i) != NULL)
+ { ent >> toto >> num;
+ tabSaveDon(i)->Lecture_base_info(ent,cas);}
+ // données particulière pour les lois de comportement thermo physique
+ int tabSaveTPTaille = tabSaveTP.Taille();
+ if ((tabSaveTPTaille != 0) && (tabSaveTP(1) != NULL)) ent >> toto;
+ for (int i=1; i<= tabSaveTPTaille; i++)
+ if (tabSaveTP(i) != NULL)
+ { ent >> toto >> num;
+ tabSaveTP(i)->Lecture_base_info(ent,cas);}
+ // données particulière pour la déformation mécanique
+ int tabSaveDefDonTaille = tabSaveDefDon.Taille();
+ if ((tabSaveDefDonTaille != 0) && (tabSaveDefDon(1) != NULL)) ent >> toto;
+ for (int i=1; i<= tabSaveDefDonTaille; i++)
+ if (tabSaveDefDon(i) != NULL)
+ { ent >> toto >> num;
+ tabSaveDefDon(i)->Lecture_base_info(ent,cas);}
+ // lecture des énergies
+ int energ_taille = tab_energ_t.Taille();
+ for (int i=1;i<= energ_taille;i++) ent >> tab_energ_t(i) ;
+// // énergie et puissance éventuelle de la partie bulk viscosity
+// ent >> toto >> E_elem_bulk_t >> toto >> P_elem_bulk;
+// E_elem_bulk_tdt = E_elem_bulk_t;
+ };
+ // cas donne le niveau de sauvegarde
+ // = 1 : on sauvegarde tout
+ // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
+void ElemThermi::Ecriture_bas_inf(ofstream& sort,const int cas)
+ { // appel de la routine d'élément
+ Element::Ecri_bas_inf_element(sort,cas);
+ // en fait ici on sauvegarde la même chose dans tous les cas, par contre la sortie
+ // totale est documentée.
+ switch (cas)
+ { case 1 : // ------- on sauvegarde tout -------------------------
+ { // écriture de la masse volumique,
+ sort << "masse_volumique " << masse_volumique <<" " << "\n";
+ // données thermique
+ sort << "dilatation_thermique " << dilatation << " ";
+ // blocage éventuelle d'hourglass
+ sort << "\n hourglass: " << Nom_StabHourglass(type_stabHourglass) << " ";
+ break;
+ }
+ case 2 : // ----------- sauvegarde uniquement de se qui varie --------------------
+ { break;
+ }
+ default :
+ { cout << "\nErreur : valeur incorrecte du type d'écriture !\n";
+ cout << "ElemThermi::Ecriture_bas_inf(ofstream& sort,const int cas)"
+ << " cas= " << cas << endl;
+ Sortie(1);
+ }
+ }
+ // --- informations à sortir dans tous les cas ----
+ // résultat d'erreur
+ if (fluxErreur != NULL)
+ sort << "erreur_de_densite_de_flux " << (*fluxErreur) <<" " << "\n";
+ else
+ sort << "pas_d'erreur_de_densite_de_flux \n";
+ // données particulière pour les lois de comportement mécaniques
+ int tabSaveDonTaille = tabSaveDon.Taille();
+ if ((tabSaveDonTaille != 0) && (tabSaveDon(1) != NULL)) sort << " data_spec_loi_comp_meca ";
+ for (int i=1; i<= tabSaveDonTaille; i++)
+ if (tabSaveDon(i) != NULL)
+ { if (i==1) {sort << "pt_int= " <Ecriture_base_info(sort,cas);}
+ // données particulière pour les lois de comportement thermo physiques
+ int tabSaveTPTaille = tabSaveTP.Taille();
+ if ((tabSaveTPTaille != 0) && (tabSaveTP(1) != NULL)) sort << " data_spec_loi_comp_ThemoPhysique ";
+ for (int i=1; i<= tabSaveTPTaille; i++)
+ if (tabSaveTP(i) != NULL)
+ { if (i==1) {sort << "pt_int= " <Ecriture_base_info(sort,cas);}
+ // données particulière pour la déformation mécanique
+ int tabSaveDefDonTaille = tabSaveDefDon.Taille();
+ if ((tabSaveDefDonTaille != 0) && (tabSaveDefDon(1) != NULL)) sort << " data_spec_def ";
+ for (int i=1; i<= tabSaveDefDonTaille; i++)
+ if (tabSaveDefDon(i) != NULL)
+ { if (i==1) {sort << "pt_int= " <Ecriture_base_info(sort,cas);}
+ // sortie des énergies
+ int energ_taille = tab_energ_t.Taille();
+ sort << "\n ";
+ for (int i=1;i<= energ_taille;i++) sort << tab_energ_t(i) << " " ;
+// // énergie et puissance éventuelle de la partie bulk viscosity
+// sort << "\n E_el_bulk= " << E_elem_bulk_t << " P_el_bulk= " << P_elem_bulk;
+ };
+
+// calcul de la longueur d'arrête de l'élément minimal
+// divisé par la célérité la plus rapide dans le matériau
+// appelé par les classes dérivées
+// nb_noeud : =0 indique que l'on utilise tous les noeuds du tableau de noeuds
+// = un nombre > 0, indique le nombre de noeuds à utiliser au début du tableau
+double ElemThermi::Interne_Long_arrete_mini_sur_c(Enum_dure temps,int nb_noeud)
+ { int nbne = tab_noeud.Taille(); // récup du nombre de noeud
+ if (nb_noeud != 0)
+ nbne = nb_noeud;
+ // tout d'abord l'objectif est de déterminer la distance minimum
+ // entre les différents noeuds
+ // initialisation de la distance entre les deux noeuds
+ double dist = ConstMath::tresgrand;
+ for (int i=1;i<= nbne;i++)
+ // on itère sur les noeuds restants
+ switch (temps)
+ { case TEMPS_0:
+ for (int j=i+1;j<= nbne;j++)
+ { double dist_new = (tab_noeud(i)->Coord0() - tab_noeud(j)->Coord0()).Norme();
+ if (dist_new < dist) dist = dist_new;
+ }
+ break;
+ case TEMPS_t:
+ for (int j=i+1;j<= nbne;j++)
+ { double dist_new = (tab_noeud(i)->Coord1() - tab_noeud(j)->Coord1()).Norme();
+ if (dist_new < dist) dist = dist_new;
+ }
+ break;
+ case TEMPS_tdt:
+ for (int j=i+1;j<= nbne;j++)
+ { double dist_new = (tab_noeud(i)->Coord2() - tab_noeud(j)->Coord2()).Norme();
+ if (dist_new < dist) dist = dist_new;
+ }
+ break;
+ default :
+ cout << "\n cas du temps non implante temps= " << Nom_dure(temps)
+ << "\n ElemThermi::Interne_Long_arrete_mini_sur_c(Enum_dure temps)";
+ Sortie(1);
+ }
+ // traitement d'une erreur éventuelle
+ if (dist <= ConstMath::petit)
+ { cout << "\n **** ERREUR une longueur d'arrete de l'element est nulle"
+ << "\n ElemThermi::Interne_Long_arrete_mini_sur_c(..."
+ << "\n element: "; this->Affiche(1);
+ #ifdef MISE_AU_POINT
+ cout << "\n *** version mise au point: on continue neanmoins avec une longueur "
+ << " arbitrairement tres petite (" <NbPti();
+
+ // on définit le ddl étendu correspondant, s'il n'existe pas
+ // on définit le Ddl_enum_etendu correspondant à la masse au noeud pour la méthode
+ if (masse_relax_dyn.Nom_vide() )
+ masse_relax_dyn = (Ddl_enum_etendu("masse_relax_dyn"));
+};
+
+// phase de calcul de la matrice masse dans le cas de l'algo de relaxation dynamique
+// mi= lambda * delta_t**2 / 2 * (alpha*K+beta*mu+gamma*Isig/3+theta/2*Sig_mises)
+// avec delta_t=1 par défaut a priori, donc n'intervient pas ici
+// ep: epaisseur, K module de compressibilite, mu: module de cisaillement, Isig trace de sigma,
+// Sig_mises la contrainte de mises
+// casMass_relax: permet de choisir entre différentes méthodes de calcul de la masse
+void ElemThermi::CalculMatriceMassePourRelaxationDynamique
+ (const double& alph, const double& beta, const double & lambda
+ ,const double & gamma,const double & theta, int casMass_relax)
+ { // 1)
+ // on calcule la moyenne des grandeurs qui servent pour le calcul de la pseudo-masse que l'on distribue
+ // également sur les noeuds
+ double trace_moyenne= 0.; double mises_moyen= 0.;
+ double compress_moy=0.; double cisaille_moy = 0.;
+ int taille = lesPtIntegThermiInterne->NbPti();
+
+cout << "\n stop *** pour l'instant la methode : ElemThermi::CalculMatriceMassePourRelaxationDynamique"
+ << " n'est pas encore operationnelle " << endl;
+Sortie(1);
+
+// // on boucle sur les points d'intégrations
+// for (int i= 1; i<= taille; i++)
+// {PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(i);
+// const Vecteur & invariant = ptIntegThermi.SigInvar();
+// trace_moyenne += invariant(1) ; // le premier invariant c'est la trace
+// if (invariant.Taille() > 1)
+// mises_moyen += sqrt((3.*invariant(2)-invariant(1)*invariant(1))/2.);
+// compress_moy += ptIntegThermi.ModuleCompressibilite();
+// cisaille_moy += ptIntegThermi.ModuleCisaillement();
+// };
+
+ // --- tout d'abord la partie contrainte
+// double ensemble = (val_propre_sup + val_propre_inf + val_cisaillement) / taille;
+ // on divise par taille, ce qui conduit à la moyenne sur les points d'intégration
+ double ensemble = (gamma*trace_moyenne /3.+ 0.5*theta*mises_moyen ) / taille;
+ // --- maintenant la partie raideur
+ ensemble += (alph * compress_moy + beta * cisaille_moy) / taille;
+ // --- pour avoir l'intégration totale on utilise le volume
+// ensemble *= volume;
+ // --- et maintenant on distribue sur tous les noeuds de manière identique
+ // ne fonctionne que si tous les noeuds sont actifs !!! (ce qui est un cas particulier courant)
+ // la masse élémentaire pour chaque noeud
+// double masse_elementaire = ensemble * lambda * 0.5 / tab_noeud.Taille();
+ // pour des membrannes on a:
+ // mi= lambda * delta_t**2 / 2 * epaisseur/4 * (alpha*K+beta*mu+gamma*Isig/3+theta/2*Sig_mises)
+ // avec delta_t=1 par défaut a priori, donc n'intervient pas ici
+ // d'où le facteur 0.125, que l'on garde également pour le volume
+ double masse_elementaire = ensemble * lambda * 0.125 ;
+
+ // prise en compte du type d'élément:
+ double ParNoeud = 1.; // n'est utilisé que par la méthode de Barnes classique
+ int nbn=tab_noeud.Taille();
+ switch (Type_geom_generique(ElementGeometrique_const().TypeGeometrie()))
+ { case VOLUME : // par rapport à la surface, on utilise la racine cubique du volume
+ { double long_caracteristique = pow(Volume(),1./3.);
+ masse_elementaire *= long_caracteristique;
+ // ParNoeud = volume / nombre de noeuds, donc c'est la partie du volume
+ // attribuée à chaque noeud
+ ParNoeud = Volume() / nbn;
+ break;
+ }
+ case SURFACE : // l'algorithme historique
+ { double epaisseur_moyenne = EpaisseurMoyenne(TEMPS_tdt);
+ masse_elementaire *= epaisseur_moyenne;
+ // ParNoeud = section / nombre de noeuds, donc c'est la partie de la section
+ // attribuée à chaque noeud
+ ParNoeud = Volume() / epaisseur_moyenne/ nbn;
+ break;
+ }
+ case LIGNE :
+ { double section_moyenne = SectionMoyenne(TEMPS_tdt);
+ double long_caracteristique = Volume()/section_moyenne;
+ masse_elementaire *= long_caracteristique;
+ // ParNoeud = longueur / nombre de noeuds, donc c'est la partie de la longueur
+ // attribuée à chaque noeud
+ ParNoeud = Volume() / section_moyenne/ nbn;
+ break;
+ }
+ default :
+ cout << "\nErreur : pour l'instant les types autres que volume, surface, ligne ne sont pas pris en compte dans la relaxation "
+ << " dynamique selon barnes !\n";
+ cout << "\n ElemThermi::CalculMatriceMassePourRelaxationDynamique(.. \n";
+ Sortie(1);
+ };
+ // on parcours les noeuds de l'élément et on remplace le cas échéent, la valeur de la masse au noeud.
+ switch (casMass_relax)
+ { case 1: case 3: // cas 1 : on cumule aux noeuds, cas 3 on fait la moyenne (pas effectué ici, on ne fait
+ // que préparer le travail pour le cas 3)
+ {for (int inoe=1;inoe<=nbn;inoe++)
+ {Noeud& noe = *tab_noeud(inoe);
+ // on cumule
+ noe.ModifDdl_etendu(masse_relax_dyn).Valeur() += masse_elementaire;
+ };
+ break;
+ }
+ case 2: // cas 2 : on prend la masse maxi
+ {for (int inoe=1;inoe<=nbn;inoe++)
+ {Noeud& noe = *tab_noeud(inoe);
+ const Ddl_etendu& masse_actuel =noe.DdlEtendue(masse_relax_dyn);
+ // dans le cas où la masse actuelle est plus petite on la remplace
+ if (masse_actuel.ConstValeur() <= masse_elementaire)
+ noe.ModifDdl_etendu(masse_relax_dyn).Valeur() = masse_elementaire;
+ };
+ break;
+ }
+ case 4: case 5: // on cumule (puis on moyennera pour le cas 4, autre part) et on divise par la section comme dans la formule de barnes
+ {for (int inoe=1;inoe<=nbn;inoe++)
+ {Noeud& noe = *tab_noeud(inoe);
+ const Ddl_etendu& masse_actuel =noe.DdlEtendue(masse_relax_dyn);
+ // on cumule
+ if (masse_actuel.ConstValeur() <= masse_elementaire)
+ // !!!! je pense que ce cas est très bizarre il faudra revoir ce que cela signifie.... !!
+ noe.ModifDdl_etendu(masse_relax_dyn).Valeur() += (masse_elementaire/ParNoeud);
+ };
+ break;
+ }
+ }; //-- fin du switch
+ };
+
+ // METHODES VIRTUELLES:
+
+
+// recuperation des coordonnées du point de numéro d'ordre = iteg pour
+// la grandeur enu
+// temps: dit si c'est à 0 ou t ou tdt
+// si erreur retourne erreur à true
+// utilisé par les classes dérivées
+Coordonnee ElemThermi::CoordPtInt(Enum_dure temps,Enum_ddl enu,int iteg,bool& err)
+ { Coordonnee ptret;err = false;
+ // récupération de l'élément géométrique correspondant à Enu
+ ElemGeomC0& ele = this->ElementGeometrie(enu);
+ // récupération du tableau des fonctions d'interpolations
+ const Tableau & tabphi = ele.TaPhi();
+ if ((iteg < 0) || (iteg > tabphi.Taille()))
+ { err = true;}
+ else
+ { switch (temps)
+ { case TEMPS_0 : ptret = met->PointM_0(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_t : ptret = met->PointM_t(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_tdt : ptret = met->PointM_tdt(tab_noeud,tabphi(iteg)); break;
+ }
+ };
+ return ptret; // retour
+ };
+
+
+ // recuperation des coordonnées du point d'intégration numéro = iteg pour
+ // la face : face
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee ElemThermi::CoordPtIntFace(int face, Enum_dure temps,int iteg,bool& err)
+ { Coordonnee ptret;err = false;
+ if (SurfExiste(face))
+ {// récupération de l'élément géométrique correspondant à la face
+ const ElFrontiere* elf = this->Frontiere_surfacique(face,false);
+ if (elf != NULL) // cas où la frontière existe déjà
+ { const ElemGeomC0 & elegeom = elf->ElementGeometrique();
+ // récupération du tableau des fonctions d'interpolations
+ const Tableau & tabphi = elegeom.TaPhi();
+ if ((iteg < 0) || (iteg > tabphi.Taille()))
+ { err = true;}
+ else
+ { switch (temps)
+ { case TEMPS_0 : ptret = met->PointM_0(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_t : ptret = met->PointM_t(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_tdt : ptret = met->PointM_tdt(tab_noeud,tabphi(iteg)); break;
+ };
+ };
+ }
+ }
+ else // cas où la frontière n'existe pas, on renvoie une erreur
+ // et on laisse la valeur par défaut pour ptret
+ {err = true;
+ };
+ return ptret; // retour
+ };
+
+ // recuperation des coordonnées du point d'intégration numéro = iteg pour
+ // la face : face
+ // temps: dit si c'est à 0 ou t ou tdt
+ // si erreur retourne erreur à true
+ Coordonnee ElemThermi::CoordPtIntArete(int arete, Enum_dure temps,int iteg,bool& err)
+ { Coordonnee ptret;err = false;
+ if (AreteExiste(arete))
+ {// récupération de l'élément géométrique correspondant à l'arête
+ const ElFrontiere* elf = this->Frontiere_lineique(arete,false);
+ if (elf != NULL) // cas où la frontière existe déjà
+ { const ElemGeomC0 & elegeom = elf->ElementGeometrique();
+ // récupération du tableau des fonctions d'interpolations
+ const Tableau & tabphi = elegeom.TaPhi();
+ if ((iteg < 0) || (iteg > tabphi.Taille()))
+ { err = true;}
+ else
+ { switch (temps)
+ { case TEMPS_0 : ptret = met->PointM_0(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_t : ptret = met->PointM_t(tab_noeud,tabphi(iteg)); break;
+ case TEMPS_tdt : ptret = met->PointM_tdt(tab_noeud,tabphi(iteg)); break;
+ };
+ };
+ }
+ }
+ else // cas où la frontière n'existe pas, on renvoie une erreur
+ // et on laisse la valeur par défaut pour ptret
+ {err = true;
+ };
+ return ptret; // retour
+ };
+
+// retourne le numero du pt d'ing le plus près ou est exprimé la grandeur enum
+// temps: dit si c'est à 0 ou t ou tdt
+// utilisé par les classes dérivées
+int ElemThermi::PtLePlusPres(Enum_dure temps,Enum_ddl enu, const Coordonnee& M)
+ { int iret;
+ // récupération de l'élément géométrique correspondant à Enu
+ ElemGeomC0& ele = this->ElementGeometrie(enu);
+ // récupération du tableau des fonctions d'interpolations
+ const Tableau & tabphi = ele.TaPhi();
+ // on boucle sur les pt d'integ pour avoir le point le plus près
+ int tabphitaille = tabphi.Taille();
+ Coordonnee P; iret=1; double dist= ConstMath::tresgrand;
+ for (int ipt = 1;ipt<=tabphitaille;ipt++)
+ { switch (temps)
+ { case TEMPS_0 : P = met->PointM_0(tab_noeud,tabphi(ipt)); break;
+ case TEMPS_t : P = met->PointM_t(tab_noeud,tabphi(ipt)); break;
+ case TEMPS_tdt : P = met->PointM_tdt(tab_noeud,tabphi(ipt)); break;
+ }
+ double di=(M-P).Norme();
+ if (di < dist) { dist = di; iret = ipt;};
+ }
+ return iret; // retour
+ };
+
+// ==== >>>> methodes virtuelles redéfini éventuellement dans les classes dérivées ============
+
+// ramene l'element geometrique correspondant au ddl passé en paramètre
+ElemGeomC0& ElemThermi::ElementGeometrie(Enum_ddl ddl) const
+ { Enum_ddl enu = PremierDdlFamille(ddl);
+ switch (enu)
+ { case X1 : return ElementGeometrique(); break;
+ case TEMP : return ElementGeometrique(); break;
+ case FLUXD1 : return ElementGeometrique(); break;
+ case GRADT1 : return ElementGeometrique(); break;
+ case DGRADT1 : return ElementGeometrique(); break;
+ case ERREUR : return ElementGeometrique(); break;
+ default :
+ {cout << "\n cas non prevu ou non encore implante: ddl= " << Nom_ddl(ddl)
+ << "\n ElemThermi::ElementGeometrie(Enum_ddl ddl) " ;
+ Sortie(1);}
+ }
+ return ElementGeometrique(); // pour taire le compilo
+ };
+
+// ramène le nombre de grandeurs génératrices pour un pt d'integ, correspondant à un type enuméré
+// peut-être surchargé pour des éléments particuliers
+int ElemThermi::NbGrandeurGene(Enum_ddl ddl) const
+ { Enum_ddl enu = PremierDdlFamille(ddl);
+ int nbGG = 0.; // par défaut
+ switch (enu)
+ { case TEMP : case FLUXD1 :case GRADT1 :case DGRADT1 :
+ { // cas d'un calcul de thermique classique
+ switch (Type_geom_generique(id_geom))
+ { case LIGNE : case POINT_G : nbGG = 1; break; // FLUXD1
+ case SURFACE : nbGG = 2; break; // FLUXD1, FLUXD2
+ case VOLUME : nbGG = 3; break; // FLUXD1 FLUXD2 FLUXD3
+ default :
+ cout << "\nErreur : cas non traite, id_geom= :" << Nom_type_geom(Type_geom_generique(id_geom))
+ << "ElemThermi::NbGrandeurGene(.. \n";
+ Sortie(1);
+ };
+ break;
+ }
+ default :
+ {cout << "\n cas non prevu ou non encore implante: ddl= " << Nom_ddl(ddl)
+ << "\n ElemThermi::NbGrandeurGene(Enum_ddl ddl) " ;
+ Sortie(1);}
+ };
+ return nbGG;
+ };
+
+// modification de l'orientation de l'élément en fonction de cas_orientation
+// =0: inversion simple (sans condition) de l'orientation
+// si cas_orientation est diff de 0: on calcul le jacobien aux différents points d'intégration
+// 1. si tous les jacobiens sont négatifs on change d'orientation
+// 2. si tous les jacobiens sont positifs on ne fait rien
+// 3. si certains jacobiens sont positifs et d'autres négatifs message
+// d'erreur et on ne fait rien
+// ramène true: s'il y a eu changement effectif, sinon false
+bool ElemThermi::Modif_orient_elem(int cas_orientation)
+ { // retour:
+ bool retour=false; // par défaut pas de changement
+ if (cas_orientation == 0) // cas où on inverse l'orientation sans condition particulière
+ { // on change l'orientation de l'élément
+ retour = true;
+ int nbnoe = tab_noeud.Taille();
+ Tableau tab_inter(tab_noeud); // on crée un tableau intermédiaire
+ // on récupère la numérotation locale inverse
+ const Tableau tabi = ElementGeometrique().InvConnec();
+ // on met à jour le tableau actuel
+ for (int n=1;n<=nbnoe;n++)
+ tab_noeud(n)=tab_inter(tabi(n));
+ }
+ else
+ { // si cas_orientation est diff de 0: on calcul le jacobien aux différents points d'intégration
+ // 1. si tous les jacobiens sont négatifs on change d'orientation
+ // 2. si tous les jacobiens sont positifs on ne fait rien
+ // 3. si certains jacobiens sont positifs et d'autres négatifs message
+ // d'erreur et on ne fait rien
+ int cas=1; // a priori tout est ok
+ // boucle sur les pt d'integ
+ for (def->PremierPtInteg();def->DernierPtInteg();def->NevezPtInteg())
+ { double jacobien_0 = def->JacobienInitial();
+
+ if (jacobien_0 < 0)
+ {if (cas ==1) // on a trouvé un jacobien négatif
+ {cas =0; }
+ }// si c'était positif --> négatif
+ else // cas positif
+ {if (cas == 0) // on a déjà changé
+ { cas = 2; break;} // on sort de la boucle
+ };
+ };
+ // gestion de pb
+ if (cas == 2)
+ { cout << "\n **** Attention **** element nb= "<< this->Num_elt() << " peut-etre trop distordu ?"
+ << " pt d'integ Thermi positif et negatif !! ";
+ if (ParaGlob::NiveauImpression() > 7)
+ {// on va essayer de sortir plus d'info
+ int pti=1;cout << "\n les jacobiens initiaux \n";
+ // on sort les valeurs des jacobiens
+ for (def->PremierPtInteg();def->DernierPtInteg();def->NevezPtInteg(),pti++)
+ { cout << " pti= "<Coord0();
+ };
+
+ };
+ }
+ else if (cas == 0)
+ { switch (cas_orientation)
+ { case 1: // on change l'orientation de l'élément
+ {retour = true;
+ int nbnoe = tab_noeud.Taille();
+ Tableau tab_inter(tab_noeud); // on crée un tableau intermédiaire
+ // on récupère la numérotation locale inverse
+ const Tableau tabi = ElementGeometrique().InvConnec();
+ for (int n=1;n<=nbnoe;n++)
+ tab_noeud(n)=tab_inter(tabi(n));
+ break;
+ }
+ case -1: // on sort une information à l'écran
+ { cout << "\n element nb= "<< this->Num_elt() << "jacobien negatif " ;
+ break;;
+ }
+ default:
+ cout << "\n erreur le cas : " << cas_orientation
+ << " n'est pas actuellement pris en compte"
+ << "\n ElemThermi::Modif_orient_elem(...";
+ Sortie(1);
+ };
+ };
+ };
+ // retour
+ return retour;
+ };
+
+
+
+
+
diff --git a/Elements/Thermique/ElemThermi3.cc b/Elements/Thermique/ElemThermi3.cc
new file mode 100755
index 0000000..57de24b
--- /dev/null
+++ b/Elements/Thermique/ElemThermi3.cc
@@ -0,0 +1,1143 @@
+// This file is part of the Herezh++ application.
+//
+// The finite element software Herezh++ is dedicated to the field
+// of mechanics for large transformations of solid structures.
+// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
+// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
+//
+// Herezh++ is distributed under GPL 3 license ou ultérieure.
+//
+// Copyright (C) 1997-2021 Université Bretagne Sud (France)
+// AUTHOR : Gérard Rio
+// E-MAIL : gerardrio56@free.fr
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License,
+// or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty
+// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+//
+// For more information, please consult: .
+
+//#include "Debug.h"
+#include "ElemThermi.h"
+#include
+#include "ConstMath.h"
+#include "Util.h"
+#include "Coordonnee2.h"
+#include "Coordonnee3.h"
+#include "TypeConsTens.h"
+#include "TypeQuelconqueParticulier.h"
+
+
+// retourne la liste de tous les types de ddl interne actuellement utilisés
+// par l'élément (actif ou non), sont exclu de cette liste les ddl des noeuds
+// reliés à l'élément (ddl implique grandeur uniquement scalaire !)
+List_io ElemThermi::Les_type_de_ddl_internes(bool) const
+ { List_io ret;
+ switch (ParaGlob::Dimension())
+ { case 1 :
+ {ret.push_back(TEMP); ret.push_back(FLUXD1);
+ ret.push_back(GRADT1); ret.push_back(DGRADT1);
+// ret.push_back(string("Green-Lagrange11"));ret.push_back(string("Almansi11"));ret.push_back(string("logarithmique11"));
+ break;
+ }
+ case 2 :
+ {ret.push_back(TEMP); ret.push_back(FLUXD1);ret.push_back(FLUXD2);
+ ret.push_back(GRADT1); ret.push_back(GRADT2);
+ ret.push_back(DGRADT1); ret.push_back(DGRADT2);
+// ret.push_back(EPS22); ret.push_back(EPS12);
+ break;
+ }
+ case 3 :
+ {ret.push_back(TEMP);
+ ret.push_back(FLUXD1);ret.push_back(FLUXD2);ret.push_back(FLUXD3);
+ ret.push_back(GRADT1); ret.push_back(GRADT2); ret.push_back(GRADT3);
+ ret.push_back(DGRADT1); ret.push_back(DGRADT2);
+// ret.push_back(string("Green-Lagrange11")); ret.push_back(string("Green-Lagrange22"));
+ break;
+ }
+ };
+ // cas des invariants
+// tab_Dee(107).nom = "norme_gradT" ;tab_Dee(107).enu = GRADT1;tab_Dee(107).posi_nom = nbenumddl + 107;
+// tab_Dee(108).nom = "norme_DgradT" ;tab_Dee(108).enu = DGRADT1;tab_Dee(108).posi_nom = nbenumddl + 108;
+// tab_Dee(109).nom = "norme_dens_flux" ;tab_Dee(109).enu = FLUXD1;tab_Dee(109).posi_nom = nbenumddl + 109;
+
+ ret.push_back(string("norme_gradT"));
+ ret.push_back(string("norme_DgradT"));
+ ret.push_back(string("norme_dens_flux"));
+ // cas de l'existence de l'erreur
+ if (fluxErreur != NULL) ret.push_back(ERREUR);
+// // cas des énergies locales
+// ret.push_back(string("energie_elastique"));
+// ret.push_back(string("dissipation_plastique"));
+// ret.push_back(string("dissipation_visqueuse"));
+ // cas des coordonnées du points
+ switch (ParaGlob::Dimension())
+ {case 3: ret.push_back(X3);
+ case 2: ret.push_back(X2);
+ case 1: ret.push_back(X1);
+ };
+ // retour
+ return ret;
+ };
+
+// retourne la liste abondée de tous les données particulières interne actuellement utilisés
+// par l'élément (actif ou non), sont exclu de cette liste les données particulières des noeuds
+// reliés à l'élément
+List_io ElemThermi::Les_types_particuliers_internes(bool absolue) const
+ { List_io ret;
+ // on s'intéresse au information stockée au niveau des points d'intégration
+ // 1° récupéreration les grandeurs
+ // a) cas des grandeurs liées à la déformation
+ def->ListeGrandeurs_particulieres(absolue,ret);
+ // b) cas des grandeurs liées à la loi de comportement mécanique
+ loiTP->ListeGrandeurs_particulieres(absolue,ret);
+ // c) cas des grandeurs liées à la loi de comportement thermo-physique
+ if (loiComp != NULL) loiComp->ListeGrandeurs_particulieres(absolue,ret);
+ // d) cas des infos stockés aux points d'intégration, donc par l'élément
+ Grandeur_scalaire_double grand_courant; // def d'une grandeur courante
+ // def d'un type quelconque représentatif à chaque grandeur
+ // a priori ces grandeurs sont défini aux points d'intégration
+ // e) cas des infos stockés à l'élément
+ // $$$ cas du volume total :
+ TypeQuelconque typQ3(VOLUME_ELEMENT,SIG11,grand_courant);
+ ret.push_back(typQ3);
+
+ // f) cas des infos calculable à la demande sur l'élément
+ // $$$ cas des volumes entre les plans et l'élément dans le cas ou l'élément des de surface
+ // et que le calcul est 3D :
+ if ((ParaGlob::Dimension()==3)&&(Type_geom_generique(id_geom)==SURFACE))
+ {Grandeur_coordonnee grandCoordonnee(3); // un type courant
+ TypeQuelconque typQ4(VOL_ELEM_AVEC_PLAN_REF,SIG11,grandCoordonnee);
+ ret.push_back(typQ4);
+ };
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ return ret;
+ };
+
+// retourne la liste des grandeurs évoluées interne actuellement utilisés
+// par l'élément, c'est-à-dire directement sous forme de vecteur, tenseurs ....
+List_io ElemThermi::Les_type_evolues_internes(bool absolue) const
+ { List_io liTQ;
+ // def des grandeurs courantes de type coordonnee
+ {Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
+ // maintenant on définit une grandeur typique de type Grandeur_coordonnee
+ Grandeur_coordonnee gt(coor);
+ // def d'un type quelconque représentatif pour chaque grandeur
+ {TypeQuelconque typQ(FLUXD,FLUXD1,gt);liTQ.push_back(typQ);};
+ {TypeQuelconque typQ(GRADT,GRADT1,gt);liTQ.push_back(typQ);};
+ {TypeQuelconque typQ(DGRADT,DGRADT1,gt);liTQ.push_back(typQ);};
+ // pour la position il s'agit de la position du point d'intégration
+ {TypeQuelconque typQ(POSITION_GEOMETRIQUE,FLUXD1,gt);liTQ.push_back(typQ);};
+ };
+
+ // retour
+ return liTQ;
+ };
+
+// récupération de grandeurs particulières au numéro d'ordre = iteg
+// celles-ci peuvent être quelconques
+// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+void ElemThermi::Grandeur_particuliere (bool absolue,List_io& liTQ,int iteg)
+ { // on s'intéresse au information stockée au niveau des points d'intégration
+ // pour tenir compte du fait qu'il peut y avoir plusieurs fois la même information, ces dernières sont systématiquement
+ // stockées dans des tableaux, et on associe à ce tableau un indice qui indique aux méthodes appelées, à quel endroit
+ // elles doivent écrire les infos. les indices sont stockés dans une liste de même dim que liTQ
+ list decal(liTQ.size(),0.); // on initi tous les membres à 0
+
+ // 1° on commence par récupérer les grandeurs
+ // a) cas des grandeurs liées à la déformation
+ // met à jour les données spécifiques du point considéré
+ def->Mise_a_jour_data_specif(tabSaveDefDon(iteg));
+ def->Grandeur_particuliere(absolue,liTQ);
+ // b) cas des grandeurs liées à la loi de comportement thermo-physique
+ loiComp->Grandeur_particuliere(absolue,liTQ,tabSaveDon(iteg),decal);
+// pour le débug ----
+//cout << "\n debug ElemThermi::Grandeur_particuliere " << liTQ << endl; // débug
+// fin pour le débug ----
+ // c) cas des grandeurs liées à la loi de comportement thermo-physique
+ if (loiTP != NULL) loiTP->Grandeur_particuliere(absolue,liTQ,tabSaveTP(iteg),decal);
+ // 2° on change éventuellement de repère (local en global) si nécessaire
+ // a) définition des grandeurs qui sont indépendante de la boucle qui suit
+ def->ChangeNumInteg(iteg); // on change le numéro de point d'intégration courant
+ // dimension des vecteurs de base de la métrique
+ int dim = met->Dim_vec_base();
+ // calcul des matrices de passages
+ // calcul des matrices de passages
+ Mat_pleine* gamma0=NULL; Mat_pleine* gammat=NULL; Mat_pleine* gammatdt=NULL;
+ Mat_pleine* beta0=NULL; Mat_pleine* betat=NULL; Mat_pleine* betatdt=NULL;
+ List_io::iterator il,ilfin = liTQ.end();
+ for (il=liTQ.begin();il!=ilfin;il++)
+ { TypeQuelconque& tipParticu = (*il); // pour simplifier
+ // n'intervient que si la grandeur est active:
+ if ((*il).Activite())
+ { // on regarde si c'est une grandeur locale ou pas
+ if (tipParticu.TypeExpressionGrandeur()==0)
+ // cas d'une grandeur exprimée dans le repère locale, changement de repère
+ { // calcul des matrices de passages, au premier passage
+ if (gamma0 == NULL)
+ { gamma0 = new Mat_pleine(dim,dim); gammat = new Mat_pleine(dim,dim);gammatdt= new Mat_pleine(dim,dim);
+ const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(absolue,*gamma0,*gammat,*gammatdt);
+ beta0 = new Mat_pleine(gamma0->Inverse().Transpose());
+ betat = new Mat_pleine(gammat->Inverse().Transpose());
+ betatdt = new Mat_pleine(gammatdt->Inverse().Transpose());
+ };
+ tipParticu.Change_repere(*beta0,*betat,*betatdt,*gamma0,*gammat,*gammatdt);
+ };
+ // on utilise la boucle également pour mettre à jour les grandeurs particulières liés à l'élément
+
+ // 1) -----cas du module de compressibilité ou de cisaillement totale
+ switch (tipParticu.EnuTypeQuelconque().EnumTQ())
+ {// e) cas des infos stockés à l'élément
+ case VOLUME_ELEMENT:
+ { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=volume;break;}
+ // d) cas des infos calculable à la demande sur l'élément
+ case VOL_ELEM_AVEC_PLAN_REF:
+ { *((Grandeur_coordonnee*) tipParticu.Grandeur_pointee())=VolumePlan();break;}
+ default: break; // sinon rien
+ };
+ };
+
+ };
+ // suppression des bases de passages
+ if (gamma0 != NULL)
+ {delete gamma0; delete gammat; delete gammatdt; delete beta0; delete betat; delete betatdt;};
+ // liberation des tenseurs intermediaires
+ LibereTenseur();
+ };
+// retourne la liste de toutes les grandeurs quelconques relatives aux faces de
+// l'élément (actif ou non),
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+List_io ElemThermi::Les_type_quelconque_de_face(bool absolue) const
+ { cout << "\n **** méthode non implantée **** "
+ << "\n List_io ElemThermi::Les_type_quelconque_de_face(.... "
+ << flush;
+ Sortie(1);
+ };
+
+// retourne la liste de toutes les grandeurs quelconques relatives aux arêtes de
+// l'élément (actif ou non),
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+List_io ElemThermi::Les_type_quelconque_de_arete(bool absolue) const
+{ cout << "\n **** méthode non implantée **** "
+ << "\n List_io ElemThermi::Les_type_quelconque_de_arete(.... "
+ << flush;
+ Sortie(1);
+};
+
+// récupération de grandeurs particulières pour une face au numéro d'ordre = iteg
+// celles-ci peuvent être quelconques
+// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+void ElemThermi::Grandeur_particuliere_face(bool absolue,List_io& liTQ,int face, int iteg)
+{ cout << "\n **** méthode non implantée **** "
+ << "\n List_io ElemThermi::Grandeur_particuliere_face(.... "
+ << flush;
+ Sortie(1);
+};
+
+// récupération de grandeurs particulières pour une arête au numéro d'ordre = iteg
+// celles-ci peuvent être quelconques
+// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
+// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
+void ElemThermi::Grandeur_particuliere_arete(bool absolue,List_io& liTQ,int arete, int iteg)
+{ cout << "\n **** méthode non implantée **** "
+ << "\n List_io ElemThermi::Grandeur_particuliere_arete(.... "
+ << flush;
+ Sortie(1);
+};
+
+// --- transfert des grandeurs des points d'intégration aux noeuds
+// transfert de ddl des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, on ne remplace pas)
+// les ddl doivent déjà exister aux noeuds sinon erreur
+// il doit s'agir du même type de répartition de pt d'integ pour toutes les grandeurs
+// tab_val(i)(j) : valeur associée au i ième pt d'integ et au j ième ddl_enum_etendu
+void ElemThermi::TransfertAjoutAuNoeuds(const List_io < Ddl_enum_etendu >& lietendu
+ ,const Tableau > & tab_val,int cas)
+{List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end();
+ // on récupère l'élément géométrique associé au ddl pur du premier ddl étendu,
+ ili = lietendu.begin();
+ Enum_ddl enu = (*ili).Enum();
+ const ElemGeomC0& elemgeom = ElementGeometrie(enu);
+ // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément
+ // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers
+ // du tableau des noeuds
+ int nbn = elemgeom.Nbne();
+
+ int indice = 1;
+ for (ili = lietendu.begin();ili!=ilifin;ili++,indice++)
+ { // récupération des tableaux d'indiçage pour le calcul aux noeuds
+ const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas);
+ // calcul des valeurs aux noeuds
+ // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) }
+ for (int ine=1;ine<=nbn;ine++)
+ { Ddl_etendu& de = tab_noeud(ine)->ModifDdl_etendu(*ili);
+ Tableau & indir = contExtra.indir(ine); // pour simplifier
+ int nbindir = indir.Taille();
+ for (int j=1; j<= nbindir; j++)
+ de.Valeur() += contExtra.tab(ine)(indir(j)) * tab_val(indir(j))(indice);
+ };
+ };
+};
+
+// transfert de type quelconque des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds,
+// on ne remplace pas). Les types quelconques doivent déjà exister.
+// un tableau tab_liQ correspondent aux grandeurs quelconque pour tous les pt integ. tab_liQ(i) est associé au pt d'integ i
+// Toutes les listes sont identiques au niveau des descripteurs (types...) ce sont uniquement les valeurs numériques
+// c-a-dire les valeurs associées à TypeQuelconque::Grandeur qui sont différentes (elles sont associées à chaque pt d'integ)
+// liQ_travail: est une liste de travail qui sera utilisée dans le transfert
+void ElemThermi::TransfertAjoutAuNoeuds(const Tableau >& tab_liQ
+ ,List_io < TypeQuelconque > & liQ_travail,int cas)
+{int nb_pt_integ = lesPtIntegThermiInterne->NbPti();
+// ---- modif transitoire pour la sortie des coques !!!!
+ // on s'occupe uniquement de la première couche d'élément
+ if ((this->PoutrePlaqueCoque() == COQUE)||(this->PoutrePlaqueCoque() == PLAQUE))
+ nb_pt_integ = this->NbPtIntegSurface(FLUXD1); // SIG11 arbitraire car c'est les pt d'integ classique
+
+
+//------- fin modif transitoire --------
+ if (tab_liQ.Taille() == 0)
+ return; // cas où on n'a rien à faire
+ #ifdef MISE_AU_POINT
+ if (nb_pt_integ != tab_liQ.Taille())
+ { cout << "\n erreur de dimension, la taille de tab_liQ= " << tab_liQ.Taille() << " n'est pas egale "
+ << " au nombre de pt_d'integ de l'element : " << nb_pt_integ ;
+ cout << "\n ElemThermi::TransfertAjoutAuNoeuds(... " << endl;
+ Sortie(1);
+ }
+ #endif
+//---- pour le debug
+//cout << " \n debug ElemThermi::TransfertAjoutAuNoeuds " << tab_liQ << endl;
+//--- fin pour le debug
+ // sinon on a au moins un élément, on récupère la 1ère liste qui nous servira pour les descripteurs
+ List_io & liQ_ref = tab_liQ(1); // pour simplifier
+ List_io < TypeQuelconque >::const_iterator ili_ref,ilifin_ref=liQ_ref.end();
+ // la liste de travail
+ List_io < TypeQuelconque >::iterator ili_travail = liQ_travail.begin();
+ // on définit un tableau d'itérator de dimension = le nb de pt d'integ
+ static Tableau < List_io < TypeQuelconque >::const_iterator > tab_iterator;
+ // on le redimentionne si besoin est
+ tab_iterator.Change_taille(nb_pt_integ);
+ // on définit ses éléments
+ for (int ia=1;ia<=nb_pt_integ;ia++)
+ tab_iterator(ia) = tab_liQ(ia).begin();
+ // on boucle sur les éléments de la liste de référence
+ for (ili_ref = liQ_ref.begin();ili_ref != ilifin_ref;ili_ref++,ili_travail++)
+ { // on récupère l'élément géométrique associé au ddl pur dont les valeurs sont calculées aux mêmes
+ // endroits que la grandeur quelconque
+ Enum_ddl enu = (*ili_ref). Enum();
+ const ElemGeomC0& elemgeom = ElementGeometrie(enu);
+ // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément
+ // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers
+ // du tableau des noeuds
+ int nbn = elemgeom.Nbne();
+ // récupération des tableaux d'indiçage pour le calcul aux noeuds
+ const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas);
+ // on boucle sur les noeuds, ceci est due à la technique utilisée pour accumuler dans les conteneurs du noeud
+ for (int ine=1;ine<=nbn;ine++)
+ {TypeQuelconque& tq = tab_noeud(ine)->ModifGrandeur_quelconque((*ili_ref).EnuTypeQuelconque());
+ TypeQuelconque::Grandeur & grandeur_au_noeud = *(tq.Grandeur_pointee());
+ // on récupère une grandeur du même type que les grandeurs à manipuler, ceci pour accumuler
+ TypeQuelconque::Grandeur & stockage_inter = *((*ili_travail).Grandeur_pointee());
+ // calcul des valeurs aux noeuds
+ // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) }
+ Tableau & indir = contExtra.indir(ine); // pour simplifier
+ int nbindir = indir.Taille();
+ for (int j=1; j<= nbindir; j++)
+ { stockage_inter *= 0.; // met à 0 la grandeur inter
+ // tab_iterator(j) pointe sur la grandeur quelconque du point d'intégration voulu
+ stockage_inter = *((*(tab_iterator(indir(j)))).Const_Grandeur_pointee()); // récup de la grandeur pointée
+ stockage_inter *= contExtra.tab(ine)(indir(j)); // * par le coeff
+ grandeur_au_noeud += stockage_inter; // stockage dans le noeud
+ };
+ };
+ // on incrémente les itérators de points d'intégration
+ for (int ib=1;ib<=nb_pt_integ;ib++)
+ (tab_iterator(ib))++;
+ };
+};
+
+
+// accumulation aux noeuds de grandeurs venant des éléments vers leurs noeuds (exemple la pression appliquée)
+// autres que celles aux pti classiques, mais directements disponibles
+// le contenu du conteneur stockées dans liQ est utilisé en variable intermédiaire
+void ElemThermi::Accumul_aux_noeuds(const List_io < Ddl_enum_etendu >& lietendu
+ ,List_io < TypeQuelconque > & liQ,int cas)
+{// ... cas des ddl étendu ...
+ {List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end();
+ ili = lietendu.begin();
+// for (ili = lietendu.begin();ili!=ilifin;ili++)
+// {// on traite en fonctions des cas particuliers
+////debug
+////cout << "\n debug ElemMeca::Accumul_aux_noeuds"
+//// << " *ili = " << *ili << endl;
+//// fin debug
+//
+// switch ((*ili).Position()-NbEnum_ddl())
+// { case 94 : // cas des pressions externes
+// {if (lesChargeExtSurEle != NULL)
+// if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées
+// { Tableau >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes();
+// int nb_face = lesPressionsExternes.Taille();
+// for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces
+// if (lesPressionsExternes(n_face).Taille() != 0)
+// { Tableau