From f43e5da7ec0a502b0b995c009c6a05e95f5a17a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9rard=20Rio?= Date: Tue, 28 Sep 2021 17:51:09 +0200 Subject: [PATCH] =?UTF-8?q?int=C3=A9gration=20des=20=C3=A9l=C3=A9ments=20d?= =?UTF-8?q?e=20thermique=20(actuellement=20uniquement=20biel=201D)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Thermique/Biellette/BielletteThermi.cc | 1672 +++++++++++++++ .../Thermique/Biellette/BielletteThermi.h | 661 ++++++ Elements/Thermique/ElemThermi.cc | 1899 +++++++++++++++++ Elements/Thermique/ElemThermi.h | 893 ++++++++ Elements/Thermique/ElemThermi2.cc | 957 +++++++++ Elements/Thermique/ElemThermi3.cc | 1143 ++++++++++ Elements/Thermique/ElemThermi4.cc | 735 +++++++ Elements/Thermique/ElemThermi5.cc | 847 ++++++++ Elements/Thermique/ExceptionsElemThermi.h | 76 + Elements/Thermique/LesPtIntegThermiInterne.cc | 243 +++ Elements/Thermique/LesPtIntegThermiInterne.h | 134 ++ 11 files changed, 9260 insertions(+) create mode 100755 Elements/Thermique/Biellette/BielletteThermi.cc create mode 100755 Elements/Thermique/Biellette/BielletteThermi.h create mode 100755 Elements/Thermique/ElemThermi.cc create mode 100755 Elements/Thermique/ElemThermi.h create mode 100755 Elements/Thermique/ElemThermi2.cc create mode 100755 Elements/Thermique/ElemThermi3.cc create mode 100755 Elements/Thermique/ElemThermi4.cc create mode 100755 Elements/Thermique/ElemThermi5.cc create mode 100755 Elements/Thermique/ExceptionsElemThermi.h create mode 100755 Elements/Thermique/LesPtIntegThermiInterne.cc create mode 100755 Elements/Thermique/LesPtIntegThermiInterne.h 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 & tab_press_appliquee = (lesPressionsExternes(n_face)); // pour simplifier +// int t_tail = tab_press_appliquee.Taille(); +// if (t_tail != 0) // cas où on a une face chargée +// { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1) +// int num_face = n_face; // init par défaut +// if(ParaGlob::AxiSymetrie()) // dans le cas d'éléments axysymétriques, les faces +// {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes +// const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique(); +// int nbn = elemgeom.Nbne(); +// const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas); +// Tableau & tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière +// for (int ine=1;ine<=nbn;ine++) +// { Ddl_etendu& de = tab_noe(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_press_appliquee(indir(j)).press; +////debug +////cout << "\n debug ElemMeca::Accumul_aux_noeuds" +//// << " de.Valeur() = " << de.Valeur() << endl; +//// fin debug +//} }; +// }; +// }; +// }; +// break; +// } +// default : +// break; +// // sinon on ne fait rien, cela signifie que ce n'est pas un ddl géré par l'élément +// }; +// }; + }; + + // ... cas des grandeurs quelconque ... + // on traite d'abord le cas où on n'a rien à faire + if (liQ.size() == 0) + return; +//---- pour le debug +//cout << " \n debug ElemMeca::TransfertAjoutAuNoeuds " << tab_liQ << endl; +//--- fin pour le debug + {List_io < TypeQuelconque >::const_iterator ili,ilifin=liQ.end(); + + // on boucle sur les grandeurs de la liste + for (ili = liQ.begin();ili != ilifin;ili++) + { // on récupère l'énuméré + TypeQuelconque_enum_etendu enutq = (*ili).EnuTypeQuelconque(); + switch (enutq.EnumTQ()) + { // case VECT_REAC: +// // là on ne fait rien car la grandeur est directement à construire via les noeuds +// // et ceci est fait dans la routine: +// // lesMaillages->PassageInterneDansNoeud_composantes_vers_vectorielles() +// break; + + default: + // VECT_PRESSION pour l'instant il n'y a aucune grandeur a priori qui est disponible directement + // donc message d'erreur + cout << "\n cas de grandeur actuellement non traité " + << "\n pas de grandeur " << ((*ili).EnuTypeQuelconque().NomPlein()) << " dans l'element " + << "\n ou cas non implante pour l'instant" + << "\n ElemMeca::Accumul_aux_noeuds(...."; + }; + }; + }; +}; + + +// procedure 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* ElemThermi::Complete_ElemThermi(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD) + { // cas de la masse volumique + if (bloc.Nom(1) == "masse_volumique") + { masse_volumique = bloc.Val(1); + return this; + } + // cas de données thermique + else if (bloc.Nom(1) == "dilatation_thermique") + { if (bloc.Val(1) == 1.) {dilatation=true;} else {dilatation = false;}; + return this; + } + // cas de la définition d'une intégrale sur le volume + // on prévoit une intégrale via les pti, on utilise donc le ddl EPS11 pour la position + else if (bloc.Nom(1) == "integrale_sur_volume_") + { if (bloc.Nom(2) == "un_ddl_etendu_") + { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3) + Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc + Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc + TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant); + if (integ_vol_typeQuel == NULL) + {integ_vol_typeQuel = new Tableau (1); + (*integ_vol_typeQuel)(1) = typQ; + index_Integ_vol_typeQuel = new Tableau (1); + (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1); + } + else {int taille = integ_vol_typeQuel->Taille()+1; + integ_vol_typeQuel->Change_taille(taille); + (*integ_vol_typeQuel)(taille) = typQ; + index_Integ_vol_typeQuel->Change_taille(taille); + (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1); + }; + } + else if (bloc.Nom(2) == "une_fonction_nD_") + { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3) + // on récupère le pointeur de fonction correspondant: + Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3)); + Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),1,fct);// par défaut une taille de 1 + TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant); + if (integ_vol_typeQuel == NULL) + { integ_vol_typeQuel = new Tableau (1); + (*integ_vol_typeQuel)(1) = typQ; + index_Integ_vol_typeQuel = new Tableau (1); + (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1); + } + else {int taille = integ_vol_typeQuel->Taille()+1; + integ_vol_typeQuel->Change_taille(taille); + (*integ_vol_typeQuel)(taille) = typQ; + index_Integ_vol_typeQuel->Change_taille(taille); + (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1); + }; + }; + return this; + } + + // cas de la définition d'une intégrale sur le volume et le temps + else if (bloc.Nom(1) == "integrale_sur_vol_et_temps_") + { if (bloc.Nom(2) == "un_ddl_etendu_") + { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3) + Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc + Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc + TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant); + if (integ_vol_t_typeQuel == NULL) + {integ_vol_t_typeQuel = new Tableau (1); + (*integ_vol_t_typeQuel)(1) = typQ; + index_Integ_vol_t_typeQuel = new Tableau (1); + (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1); + } + else {int taille = integ_vol_t_typeQuel->Taille()+1; + integ_vol_t_typeQuel->Change_taille(taille); + (*integ_vol_t_typeQuel)(taille) = typQ; + index_Integ_vol_t_typeQuel->Change_taille(taille); + (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1); + }; + } + else if (bloc.Nom(2) == "une_fonction_nD_") + { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3) + // on récupère le pointeur de fonction correspondant: + Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3)); + Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),1,fct);// par défaut une taille de 1 + TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant); + if (integ_vol_t_typeQuel == NULL) + {integ_vol_t_typeQuel = new Tableau (1); + (*integ_vol_t_typeQuel)(1) = typQ; + index_Integ_vol_t_typeQuel = new Tableau (1); + (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1); + } + else {int taille = integ_vol_t_typeQuel->Taille()+1; + integ_vol_t_typeQuel->Change_taille(taille); + (*integ_vol_t_typeQuel)(taille) = typQ; + index_Integ_vol_t_typeQuel->Change_taille(taille); + (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1); + }; + }; + return this; + } + // sinon rien + else + { return NULL;}; + }; + + +// récupération de la base locales au noeud noe, pour le temps: temps +const BaseB & ElemThermi::Gib_elemeca(Enum_dure temps, const Noeud * noe) + { int nb_noeud = tab_noeud.Taille(); // nombre de noeud de l'élément local + // on fait une rotation sur les noeuds de l'élément + int num=1; + for (num=1;num<= nb_noeud;num++) + { if (noe == tab_noeud(num)) break; } + // récupération des coordonnées locales du noeud + ElemGeomC0& elem_geom = ElementGeometrique(); // recup de l'élément géométrique correspondant + // récup de la référence des coordonnées locales du noeud num + const Coordonnee & coo = elem_geom.PtelemRef()(num); + // calcul de la dérivée des fonctions au point + const Mat_pleine& ddphi = elem_geom.Dphi(coo); + const Vecteur& pphi = elem_geom.Phi(coo); + // en fonction du temps on calcul la base naturelle + switch (temps) + { case TEMPS_0: return (met->BaseNat_0(tab_noeud,ddphi,pphi)); break; + case TEMPS_t: return (met->BaseNat_t(tab_noeud,ddphi,pphi)); break; + case TEMPS_tdt: return (met->BaseNat_tdt(tab_noeud,ddphi,pphi)); break; + }; + // pour faire taire le compilateur + cout << "\n erreur, on ne devrait jamais passer ici" + << "\n ElemThermi::Gib_elemeca(..."; + Sortie(1); + BaseB *toto = new BaseB(0); + return (*toto); + }; + +// calcul du mini du module d'young équivalent pour tous les points d'intégrations +double ElemThermi::Calcul_mini_E_qui(Enum_dure temps) + { double mini = 0.; // init + int ni; + for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) + { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); + double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni)); + if (E_equi < mini) mini = E_equi; + } + return mini; + }; + +// calcul du maxi du module d'young équivalent pour tous les points d'intégrations +double ElemThermi::Calcul_maxi_E_qui(Enum_dure temps) + { double maxi = 0.; // init + int ni; + for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) + { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni)); + double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni)); + if (E_equi > maxi) maxi = E_equi; + } + return maxi; + }; + + + // 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& ElemThermi::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) + { +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** + + + + + // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance + // *** sinon c'est intractable et long + // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants + Vecteur* SM_r; + int dime = ParaGlob::Dimension(); + bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde + // donc il faut calculer tous les éléments de la métrique + switch (dime) + {case 3: // cas de la dimension 3 + { // définition du vecteur de retour + Vecteur& SM = *((*res_extS)(numfront));SM_r=&SM; + // 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(numfront); // 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 + 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 qui vaut le produit vectoriel des 2 premiers vecteurs + // conversion explicite en coordonnées sans variance + Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2)); + // cout << "\n normale avant normalisation"; + // normale.Affiche(); + normale.Normer(); // on norme la normale + // cout << "\n normale après normalisation"; + // normale.Affiche(); Sortie(1); + + // récupération de la vitesse + const Coordonnee* Vp; + if (atdt) {Vp = &(defS.VitesseM_tdt());} + else {Vp = &(defS.VitesseM_t());}; + const Coordonnee& V = *Vp; double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return SM; + Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente + double nVt = Vt.Norme(); // norme de la vitesse tangente + if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse + Coordonnee w(3); + if (coef_aero_t != NULL) + {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale)); + // si w est non nulle on le norme + double norme_w = w.Norme(); + if (norme_w > ConstMath::trespetit) {w /= norme_w;}; + }; + // calcul du résidu + int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + double coef_frot_fluid=0.; + if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t);}; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) + { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur;}; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + double coef_t=0.; + if (coef_aero_t != NULL) + { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur;}; + for (int ne =1; ne<= nbne; ne++) + for (int i=1;i<= dimf;i++,ix++) + { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));}; + } // fin boucle sur les points d'intégrations + break; + }; // fin du cas de la dimension 3 + case 2: // cas de la dimension 2 + { // définition du vecteur de retour + Vecteur& SM = *((*res_extA)(numfront));SM_r=&SM; + // 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 & defA = *defArete(numfront); // 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; + if (atdt) {ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); } + else {ex = defA.Cal_explicit_t(premier_calcul); }; + // détermination de la normale à la surface qui vaut le vecteur perpendiculaire au g1 + // dans le sens directe + Coordonnee normale; normale(1) = - (*ex.giB_t)(1)(2); normale(2) = (*ex.giB_t)(1)(1); + normale.Normer(); // on norme la normale + // récupération de la vitesse + const Coordonnee* Vp; + if (atdt) {Vp = &(defA.VitesseM_tdt());} + else {Vp = &(defA.VitesseM_t());}; + const Coordonnee& V = *Vp; double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return SM; + Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente + double nVt = Vt.Norme(); // norme de la vitesse tangente + if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse + Coordonnee w(dime); // comme on est en 2D w ce calcul directement avec les composantes de u + if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);}; + // calcul du résidu + int ix=1; + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + double coef_frot_fluid=0.; + if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t);}; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) + { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur;}; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + double coef_t=0.; + if (coef_aero_t != NULL) + { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_t) * cos_directeur;}; + for (int ne =1; ne<= nbne; ne++) + for (int i=1;i<= dime;i++,ix++) + { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));}; + } // fin boucle sur les points d'intégrations + } // fin boucle sur les points d'intégrations + break; + case 1: // cas de la dimension 1 + { // définition du vecteur de retour + Vecteur& SM = *((*res_extN)(numfront));SM_r=&SM; + // dans le cas ou le poid volumique est nul, on retourne sans calcul + if (poidvol < ConstMath::trespetit) return SM; + // il n'y a pas plusieurs point d'intégration + // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1 + Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;}; + // récupération de la vitesse + const Coordonnee* Vp; + Noeud* noe = (tabb(numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière + if (atdt) {Vp = &(def->VitesseM_tdt(noe));} // on utilise la déformation générale, qui convient pour un noeud + else {Vp = &(def->VitesseM_t(noe));}; + const Coordonnee& V = *Vp; double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return SM; + // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente) + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse + // calcul du résidu + int ix=1; int dimf = dime; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1 + { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(1) ;}; + for (int ne =1; ne<= nbne; ne++) // il n'y qu'un point d'intégration le noeud lui-même + for (int i=1;i<= dimf;i++,ix++) + { SM(ix) += taphi(1)(ne) * coef_mul * ( coef_n * u(i) );}; + break; + }; // fin du cas de la dimension 1 */ + + }; //-- fin du switch sur la dimension + // retour du second membre + return *SM_r; + }; + + // 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 + // coef_mul: est un coefficient multiplicateur global (de tout) +Element::ResRaid ElemThermi::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) + { + + +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** +//****************** attention voir w non normé pour les dimensions 2 et 1 **************** + + + // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance + // *** sinon c'est intractable et long + // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants + Element::ResRaid el; + int nbddl = ddls.NbDdl(); + bool avec_raid = pa.Var_charge_externe(); // controle + int dime = ParaGlob::Dimension(); + bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde + // donc il faut calculer tous les éléments de la métrique + switch (dime) + {case 3: // cas de la dimension 3 + { // dans le cas ou le poid volumique est nul, on retourne sans calcul + if (poidvol < ConstMath::trespetit) + { el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); + return el; + }; + Vecteur& SM = (*((*res_extS)(numfront))); // pour simplifier + Mat_pleine & KM = (*((*raid_extS)(numfront))); // " " " + el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); // pour le retour + int ni; // compteur globale de point d'integration + Deformation & defS = *defSurf(numfront); // 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 implicit 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 qui vaut le produit vectoriel des 2 premiers vecteurs + Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2)); + normale.Normer(); // on norme la normale + // récupération de la vitesse + const Coordonnee V = defS.VitesseM_tdt(); double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return el; + Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente + double nVt = Vt.Norme(); // norme de la vitesse tangente + if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse + Coordonnee w(3);double norme_w=0.; + Coordonnee vecNul(3); // un vecteur nul pour l'initialisation + if (coef_aero_t != NULL) + {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale)); + // si w est non nulle on le norme + norme_w = w.Norme(); + if (norme_w > ConstMath::trespetit) {w /= norme_w;}; + }; + // calcul éventuel des variations + static Tableau D_Vt,D_u,D_w,D_w_non_normer; + static Tableau D_coef_frot_fluid,D_coef_n,D_coef_t; + if (avec_raid) + { // calcul de la variation de la normale + // 1) variation du produit vectoriel + Tableau D_pasnormale = + Util::VarProdVect_coor((*ex.giB_tdt)(1).Coor(),(*ex.giB_tdt)(2).Coor(),(*ex.d_giB_tdt)); + // 2) de la normale + Tableau D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme()); + // récupération de la variation de vitesse + bool ddl_vitesse; + const Tableau D_V = defS.Der_VitesseM_tdt(ddl_vitesse); + D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente + for (int ii=1;ii<=nbddl;ii++) + {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale + - (V*normale) * D_normale(ii);}; + // variation de u + D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV); + // variation de la norme de V + Tableau D_nV = Util::VarNorme(D_V,V,nV); + // variation de w s'il a une norme différente de 0 + D_w.Change_taille(nbddl,vecNul); // !! init obligatoire car peut ne pas rentrer dans les if qui suivent + if (norme_w > ConstMath::trespetit) + {if (coef_aero_t != NULL) + { D_w_non_normer.Change_taille(nbddl); + // tout d'abord la variation du produit vectoriel + Coordonnee k = Util::ProdVec_coor( u, normale); + Tableau D_k = Util::VarProdVect_coor(u,normale,D_u,D_normale); + D_w_non_normer=Util::VarProdVect_coor(u,k,D_u,D_k); + D_w = Util::VarUnVect_coor(w,D_w_non_normer,norme_w); + } + }; + // variation des coefficients + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + D_coef_frot_fluid.Change_taille(nbddl); + if (frot_fluid != NULL) + { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt); + for (int i=1;i<=nbddl;i++) + D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt) + + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i); + }; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + D_coef_n.Change_taille(nbddl); + if (coef_aero_n != NULL) + { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); + for (int i=1;i<=nbddl;i++) + D_coef_n(i) = poidvol * poids(ni) * ( + valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) + ); + }; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + D_coef_t.Change_taille(nbddl); + if (coef_aero_t != NULL) + { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV); + for (int i=1;i<=nbddl;i++) + D_coef_t(i) = poidvol * poids(ni) * ( + valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) + ); + }; + }; //-- fin du if (avec_raid) + // calcul du résidu + int ix=1; int dimf = 3; // ne fonctionne qu'en dim 3 + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + double coef_frot_fluid=0.; + if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt);}; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) + { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + double coef_t=0.; + if (coef_aero_t != NULL) + { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; + for (int ne =1; ne<= nbne; ne++) + for (int i=1;i<= dimf;i++,ix++) + { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i)); + if (avec_raid) + {for (int j =1; j<= nbddl; j++) + { //cout << "\n taphi(ni)(ne)= " << taphi(ni)(ne) << endl; + //cout << "\n D_coef_frot_fluid(j) " << D_coef_frot_fluid(j) << endl; + //cout << "\n Vt(i) " << Vt(i) << endl; + //cout << "\n D_Vt(j)(i) " << D_Vt(j)(i) << endl; + //cout << "\n D_coef_n(j) " << D_coef_n(j) << endl; + //cout << "\n u(i) " << u(i) << endl; + //cout << "\n D_u(j)(i) " << D_u(j)(i) << endl; + //cout << "\n D_coef_t(j) " << D_coef_t(j) << endl; + //cout << "\n w(i) " << w(i) << endl; + //cout << "\n D_w(j)(i) " << D_w(j)(i) << endl; + + KM(ix,j) -= taphi(ni)(ne) * coef_mul *( + D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i) + + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) + + D_coef_t(j) * w(i) + coef_t * D_w(j)(i) + ); + }; + }; + }; + } // fin boucle sur les points d'intégrations + break; + }; // fin du cas de la dimension 3 + case 2: // cas de la dimension 2 + { // dans le cas ou le poid volumique est nul, on retourne sans calcul + if (poidvol < ConstMath::trespetit) + { el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); + return el; + }; + Vecteur& SM = (*((*res_extA)(numfront))); // pour simplifier + Mat_pleine & KM = (*((*raid_extA)(numfront))); // " " " + el.res = (*res_extA)(numfront); el.raid = (*raid_extA)(numfront); // pour le retour + int ni; // compteur globale de point d'integration + Deformation & defA = *defArete(numfront); // 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 + const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul); + // détermination de la normale à la surface qui vaut le vecteur perpendiculaire au g1 + // dans le sens directe + Coordonnee normale; normale(1) = -(*ex.giB_tdt)(1)(2); normale(2) = (*ex.giB_tdt)(1)(1); + normale.Normer(); // on norme la normale + // récupération de la vitesse + const Coordonnee V = defA.VitesseM_tdt(); double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return el; + Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente + double nVt = Vt.Norme(); // norme de la vitesse tangente + if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse + Coordonnee w(dime); // comme on est en 2D, w ce calcul directement avec les composantes de u + if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);}; + // calcul éventuel des variations + static Tableau D_Vt,D_u,D_w; + static Tableau D_coef_frot_fluid,D_coef_n,D_coef_t; + if (avec_raid) + { // calcul de la variation de la normale + // 1) variation du produit vectoriel + Tableau D_pasnormale(nbddl); + for (int i=1;i<=nbddl;i++) + {D_pasnormale(i)(1) = -(*ex.d_giB_tdt)(i)(1)(2); D_pasnormale(i)(2) = (*ex.d_giB_tdt)(i)(1)(1);}; + // 2) de la normale + Tableau D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme()); + // récupération de la variation de vitesse + bool ddl_vitesse; + const Tableau D_V = defA.Der_VitesseM_tdt(ddl_vitesse); + D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente + for (int ii=1;ii<=nbddl;ii++) + {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale + - (V*normale) * D_normale(ii);}; + // variation de u + D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV); + // variation de la norme de V + Tableau D_nV = Util::VarNorme(D_V,V,nV); + // variation de w + D_w.Change_taille(nbddl); + if (coef_aero_t != NULL) + { for (int i=1;i<=nbddl;i++) {D_w(i)(1)=-D_u(i)(2);D_w(i)(2)=D_u(i)(1);}; + } + // variation des coefficients + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + D_coef_frot_fluid.Change_taille(nbddl); + if (frot_fluid != NULL) + { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt); + for (int i=1;i<=nbddl;i++) + D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt) + + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i); + }; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + D_coef_n.Change_taille(nbddl); + if (coef_aero_n != NULL) + { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); + for (int i=1;i<=nbddl;i++) + D_coef_n(i) = poidvol * poids(ni) * ( + valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) + ); + }; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + D_coef_t.Change_taille(nbddl); + if (coef_aero_t != NULL) + { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV); + for (int i=1;i<=nbddl;i++) + D_coef_t(i) = poidvol * poids(ni) * ( + valder.derivee * D_nV(i) * (*ex.jacobien_tdt) * cos_directeur + + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur + + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i)) + ); + }; + }; //-- fin du if (avec_raid) + // calcul du résidu + int ix=1; + // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt + double coef_frot_fluid=0.; + if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt);}; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) + { coef_n += poidvol * coef_aero_n->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; + // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V + double coef_t=0.; + if (coef_aero_t != NULL) + { coef_t += poidvol * coef_aero_t->Valeur(nV) * poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; + for (int ne =1; ne<= nbne; ne++) + for (int i=1;i<= dime;i++,ix++) + { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i)); + if (avec_raid) + {for (int j =1; j<= nbddl; j++) + {KM(ix,j) -= taphi(ni)(ne) * coef_mul * ( + D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i) + + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) + + D_coef_t(j) * w(i) + coef_t * D_w(j)(i) + ); + }; + }; + }; + } // fin boucle sur les points d'intégrations + break; + }; + case 1: // cas de la dimension 1 + { // dans le cas ou le poid volumique est nul, on retourne sans calcul + if (poidvol < ConstMath::trespetit) + { Element::ResRaid el; + el.res = (*res_extN)(numfront); + el.raid = (*raid_extN)(numfront); + return el; + }; + Vecteur& SM = (*((*res_extN)(numfront))); // pour simplifier + Mat_pleine & KM = (*((*raid_extN)(numfront))); // " " " + el.res = (*res_extN)(numfront); el.raid = (*raid_extN)(numfront); // pour le retour + // il n'y a pas plusieurs point d'intégration + // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1 + Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;}; + // récupération de la vitesse + Noeud* noe = (tabb(numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière + const Coordonnee& V = def->VitesseM_tdt(noe); double nV = V.Norme(); + // dans le cas où la vitesse est trop faible, le résidu est nul + if (nV < ConstMath::trespetit) return el; + // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente) + Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse + // u en fait = 1 ou -1 d'où variation = 0 + // calcul éventuel des variations + static Tableau D_coef_n; + if (avec_raid) + { // calcul de la variation de la normale + // récupération de la variation de vitesse + bool ddl_vitesse; + const Tableau D_V = def->Der_VitesseM_tdt(ddl_vitesse,noe); + // variation de la norme de V + Tableau D_nV = Util::VarNorme(D_V,V,nV); + // variation des coefficients + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + D_coef_n.Change_taille(nbddl); + if (coef_aero_n != NULL) + { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV); + for (int i=1;i<=nbddl;i++) + D_coef_n(i) = poidvol * poids(1) * valder.derivee * D_nV(i); + }; + }; //-- fin du if (avec_raid) + // calcul du résidu + int ix=1; int dimf = dime; + // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V + double coef_n=0.; + if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1 + { coef_n += poidvol * coef_mul * coef_aero_n->Valeur(nV) * poids(1) ;}; + for (int ne =1; ne<= nbne; ne++) // il n'y qu'un point d'intégration le noeud lui-même + for (int i=1;i<= dimf;i++,ix++) + { SM(ix) += taphi(1)(ne) * ( coef_n * u(i) ); + if (avec_raid) + {for (int j =1; j<= nbddl; j++) + {KM(ix,j) -= taphi(1)(ne) * coef_mul * (D_coef_n(j) * u(i));}; + }; + }; + break; + }; // fin du cas de la dimension 1 */ + + }; //-- fin du switch sur la dimension + // retour + return el; + }; + diff --git a/Elements/Thermique/ElemThermi4.cc b/Elements/Thermique/ElemThermi4.cc new file mode 100755 index 0000000..cc987e4 --- /dev/null +++ b/Elements/Thermique/ElemThermi4.cc @@ -0,0 +1,735 @@ +// 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 "TypeQuelconqueParticulier.h" +#include "TypeConsTens.h" + + + + +// 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 +void ElemThermi::VarDualSort(ofstream& sort, Tableau& nom,int ,int cas) + { if ((cas == 1) || (cas == 2)) + { // cas d'une premiere initialisation + Tableau tab(5); + tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt; + tab(4) = igiH_0; tab(5) = igijHH_0; + met->PlusInitVariables(tab) ; + } + // def de la dimension des Coordonnées + int dim = ParaGlob::Dimension(); + // def de tenseurs pour la sortie + Coordonnee fluxD(dim); + CoordonneeH fluxDH(dim) ; + Coordonnee gradT(dim); + CoordonneeB gradTB(dim); + CoordonneeB DgradTB(dim); + Coordonnee DgradT(dim); + CoordonneeB DeltagradTB(dim) ; + Coordonnee DeltagradT(dim) ; + Enum_dure temps; + + // a priori ici on travaille en absolue + bool absolue = true; + + int ni; // compteur globale de point d'integration + for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++) + // for (int ni=1;ni<= nbi;ni++) + {// éléments de métrique et matrices de passage + TenseurHH* gijHH;TenseurBB* gijBB; + Coordonnee* Mpt0;Coordonnee* Mptfin; + BaseB * giB_0; BaseB * giB_tdt; + BaseH * giH_0; BaseH * giH_tdt; + Mat_pleine jB0(dim,dim),jBfin(dim,dim); + if ((cas==1) || (cas==11)) + // calcul d'une ortho interessance de visualisation des tenseurs + // cas de tenseur 3D -> Ia, cas 1D on prend un vecteur norme collineaire + // avec g1, dans le cas 2D + // la nouvelle base jB est calculee dans def par projection de "Ia" sur Galpha + // le resultat est une matrice de passage utilisable pour le changement de base + // jB0 a t=0, B pour les tenseurs BB, jH0 idem pour les tenseurs HH + // resultat a t+dt + {const Met_abstraite::InfoImp& ex = def->RemontImp(absolue,jB0,jBfin); + temps=TEMPS_tdt; + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + } + else if ((cas==2) || (cas==12)) + { // resultat a tdt + const Met_abstraite::InfoExp_tdt& ex= def->RemontExp_tdt(absolue,jB0,jBfin); + temps=TEMPS_tdt; + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + } + // calcul des grandeurs + PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(ni); + + fluxDH = (ptIntegThermi.FluxH()); + CoordonneeB interB(dim); // variable inter + for (int i=1;i<= dim; i++) + interB += (*giB_tdt)(i) * fluxDH(i); + fluxD = interB.Coor(); + + gradTB = (ptIntegThermi.GradTB()); + CoordonneeH interH(dim); // variable inter + for (int i=1;i<= dim; i++) + interH += gradTB(i) * (*giH_tdt)(i); + gradT = interH.Coor(); + + DgradTB = (ptIntegThermi.DgradTB()); + interH.Zero(); // variable inter + for (int i=1;i<= dim; i++) + interH += DgradTB(i) * (*giH_tdt)(i); + DgradT = interH.Coor(); + + DeltagradTB = (ptIntegThermi.DeltaGradTB()); + interH.Zero(); // variable inter + for (int i=1;i<= dim; i++) + interH += DeltagradTB(i) * (*giH_tdt)(i); + DeltagradT = interH.Coor(); + + // donnees propre a la loi thermique au pt d'integ + CompThermoPhysiqueAbstraite::SaveResul* sTP = tabSaveTP(ni); + // donnees propre a la loi mécanique au pt d'integ + Loi_comp_abstraite::SaveResul* sDon=NULL; // les données spécifique mécanique + if (sDon != NULL) {sDon = tabSaveDon(ni);}; // au pt d'integ si elles existes + // données propre à la déformation au pt d'integ + Deformation::SaveDefResul * sDefDon = tabSaveDefDon(ni); + + + + // affichage + sort << "\n=================== Point d\'integration [[[ " << ni<<" ]]] ==================" ; + sort << "\nCoordonnees avant deformation " ; Mpt0->Affiche(sort,16); + sort << "\nCoordonnees apres deformation " ; Mptfin->Affiche(sort,16); + sort <<" \n et les variations " ; ((*Mptfin) - (*Mpt0)).Affiche(sort,16); + if (nom.Taille() == 0) + { // cas d'une sortie complete + for (int indic =1; indic<=11; indic++) + AffDefCont + (sort,sTP,gradTB,gradT,ptIntegThermi.Norme_gradT() + ,DgradTB,DgradT,ptIntegThermi.Norme_DGradT() + ,fluxDH,fluxD,ptIntegThermi.Norme_flux() + ,ptIntegThermi.Temperature(),indic) ; + } + else + { +// pour mémoire je laisse le reste +// for (int ij = 1;ij<= nom.Taille(); ij++) +// if (nom(ij) == "Green-Lagrange") +// AffDefCont(sort,sDon,gradT0B,gradTB,DgradTB,DeltagradTB,fluxDH,epsHB,sigHB,valPropreEps,valPropreDeps,valPropreSig,Mises +// ,epsAlmBB,epslogBB,1); + }; + }; + // liberation des tenseurs intermediaires + LibereTenseur(); + }; +void ElemThermi::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) + { int dim = fluxDH.Dimension(); + switch (dim) + { case 1: + AffDefCont1D(sort,saveDon,gradTB,gradT,norme_gradT + ,DgradTB,DgradT,norme_dGradT + ,fluxDH,fluxD,norme_flux + ,temperature,indic); + break; + case 2: + AffDefCont2D(sort,saveDon,gradTB,gradT,norme_gradT + ,DgradTB,DgradT,norme_dGradT + ,fluxDH,fluxD,norme_flux + ,temperature,indic); + break; + case 3: + AffDefCont3D(sort,saveDon,gradTB,gradT,norme_gradT + ,DgradTB,DgradT,norme_dGradT + ,fluxDH,fluxD,norme_flux + ,temperature,indic); + break; + default : + {cout << "\nerreur seules les cas 1D 2D 3D sont pris considere et non " << dim; + cout << "\nElemThermi::AffDefCont( etc ..." << endl; + } + } + }; +void ElemThermi::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) +{ + switch (indic) + {case 1 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradT " ; + sort << setw (16) << gradT(1) ; + } + break; + case 2 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradTB " ; + sort << setw (16) << gradTB(1) ; + } + break; + case 3 :{ sort << "\nDensite de flux dans repere global"; + sort << "\n fluxD " ; + sort << setw (16) << fluxD(1) ; + } + break; + case 4 :{ sort << "\nDensite de flux dans repere local"; + sort << "\n fluxDH " ; + sort << setw (16) << fluxDH(1) ; + } + break; + case 5 :{ sort << "\nVitesse du gradient de temperature dans repere global"; + sort << "\n DgradT " ; + sort << setw (16) << DgradT(1) ; + } + break; + case 6 :{ sort << "\nVitesse du gradient de temperature dans repere local"; + sort << "\n DgradTB " ; + sort << setw (16) << DgradTB(1) ; + } + break; + case 7 :{ sort << "\n norme gradT "; + sort << "\n norme_gradT " ; + sort << setw (16) << norme_gradT ; + } + break; + case 8 :{ sort << "\n norme DgradT "; + sort << "\n norme_DGradT " ; + sort << setw (16) << norme_DGradT ; + } + break; + case 9 :{ sort << "\n norme fluxD "; + sort << "\n norme_flux " ; + sort << setw (16) << norme_flux; + } + break; + case 10 :{ sort << "\n Temperature "; + sort << "\n temperature " ; + sort << setw (16) << temperature ; + } + break; + case 11 :{ if (saveDon != NULL) + { sort << "\ngrandeurs attachees a la loi et au point "; + loiTP->AfficheDataSpecif(sort,saveDon); + } + } + break; + default : + {cout << "\nerreur seules les cas de 1 a 11 sont pris en consideration et non " << indic; + cout << "\nElemThermi::AffDefCont1D( etc ..." << endl; + } + + }; +}; + + +void ElemThermi::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) +{ + string type_repere=" repere global"; + int dim_glob = ParaGlob::Dimension(); + if (dim_glob == 3) + // lorsque que l'on sort des vecteur de dim 2 en dimension 3, on utilise un repère particulier local orthonormé + type_repere=" repere orthonorme local"; + int dim_loc = gradTB.Dimension(); + + + switch (indic) + {case 1 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradT \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << gradT(i) << " "; + } + break; + case 2 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradTB \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << gradTB(i) << " "; + } + break; + case 3 :{ sort << "\nDensite de flux dans repere global"; + sort << "\n fluxD \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << fluxD(i) << " "; + } + break; + case 4 :{ sort << "\nDensite de flux dans repere local"; + sort << "\n fluxDH \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << fluxDH(i) << " "; + } + break; + case 5 :{ sort << "\nVitesse du gradient de temperature dans repere global"; + sort << "\n DgradT \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << DgradT(i) << " "; + } + break; + case 6 :{ sort << "\nVitesse du gradient de temperature dans repere local"; + sort << "\n DgradTB \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << DgradTB(i) << " "; + } + break; + case 7 :{ sort << "\n norme gradT "; + sort << "\n norme_gradT " ; + sort << setw (16) << norme_gradT ; + } + break; + case 8 :{ sort << "\n norme DgradT "; + sort << "\n norme_DGradT " ; + sort << setw (16) << norme_DGradT ; + } + break; + case 9 :{ sort << "\n norme fluxD "; + sort << "\n norme_flux " ; + sort << setw (16) << norme_flux; + } + break; + case 10 :{ sort << "\n Temperature "; + sort << "\n temperature " ; + sort << setw (16) << temperature ; + } + break; + case 11 :{ if (saveDon != NULL) + { sort << "\ngrandeurs attachees a la loi et au point "; + loiTP->AfficheDataSpecif(sort,saveDon); + } + } + default : + {cout << "\nerreur seules les cas de 1 a 11 sont pris en consideration et non " << indic; + cout << "\nElemThermi::AffDefCont2D( etc ..." << endl; + } + + } +}; + +void ElemThermi::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) +{int dim_glob = 3; int dim_loc = 3; + switch (indic) + {case 1 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradT \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << gradT(i) << " "; + } + break; + case 2 :{ sort << "\nGradient de temperature dans repere global"; + sort << "\n gradTB \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << gradTB(i) << " "; + } + break; + case 3 :{ sort << "\nDensite de flux dans repere global"; + sort << "\n fluxD \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << fluxD(i) << " "; + } + break; + case 4 :{ sort << "\nDensite de flux dans repere local"; + sort << "\n fluxDH \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << fluxDH(i) << " "; + } + break; + case 5 :{ sort << "\nVitesse du gradient de temperature dans repere global"; + sort << "\n DgradT \n" ; + for (int i=1;i<=dim_glob;i++) sort << setw (16) << DgradT(i) << " "; + } + break; + case 6 :{ sort << "\nVitesse du gradient de temperature dans repere local"; + sort << "\n DgradTB \n" ; + for (int i=1;i<=dim_loc;i++) sort << setw (16) << DgradTB(i) << " "; + } + break; + case 7 :{ sort << "\n norme gradT "; + sort << "\n norme_gradT " ; + sort << setw (16) << norme_gradT ; + } + break; + case 8 :{ sort << "\n norme DgradT "; + sort << "\n norme_DGradT " ; + sort << setw (16) << norme_DGradT ; + } + break; + case 9 :{ sort << "\n norme fluxD "; + sort << "\n norme_flux " ; + sort << setw (16) << norme_flux; + } + break; + case 10 :{ sort << "\n Temperature "; + sort << "\n temperature " ; + sort << setw (16) << temperature ; + } + break; + case 11 :{ if (saveDon != NULL) + { sort << "\ngrandeurs attachees a la loi et au point "; + loiTP->AfficheDataSpecif(sort,saveDon); + } + } + default : + {cout << "\nerreur seules les cas de 1 a 11 sont pris en consideration et non " << indic; + cout << "\nElemThermi::AffDefCont2D( etc ..." << endl; + } + + } +}; + + +// 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 ElemThermi::Valeur_multi + (bool absolue,Enum_dure temps,const List_io& enu,int iteg,int cas ) + + { // ----- def de grandeurs de travail + // def de la dimension des tenseurs + int dim = ParaGlob::Dimension(); + PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(iteg); + // recup de l'incrément de temps + double deltat=ParaGlob::Variables_de_temps().IncreTempsCourant(); + double unSurDeltat=0; + if (Abs(deltat) >= ConstMath::trespetit) + {unSurDeltat = 1./deltat;} + else // si l'incrément de temps est tres petit on remplace 1/deltat par un nombre tres grand + { // un pas de temps doit être positif !! or certaine fois il peut y avoir des pb + if (unSurDeltat < 0) + { cout << "\n le pas de temps est négatif !! "; }; + unSurDeltat = ConstMath::tresgrand; + }; + + // def de grandeurs pour la sortie + Coordonnee fluxD(dim); + CoordonneeH fluxDH(dim) ; + Coordonnee gradT(dim); + CoordonneeB gradTB(dim); + CoordonneeB DgradTB(dim); + Coordonnee DgradT(dim); + CoordonneeB DeltagradTB(dim) ; + Coordonnee DeltagradT(dim) ; + + Coordonnee Mtdt(ParaGlob::Dimension()); // coordonnées éventuelles du point d'intégration considéré + + Tableau tab_ret (enu.size()); + // définition des grandeurs qui sont indépendante de la boucle sur les ddl_enum_etendue + + def->ChangeNumInteg(iteg); // on change le numéro de point d'intégration courant + if (((cas == 1) || (cas == 2))) + { // cas d'une premiere initialisation + Tableau tab(5); + tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt; + tab(4) = igiH_0; tab(5) = igijHH_0; + met->PlusInitVariables(tab) ; + } + // éléments de métrique et matrices de passage + TenseurHH* gijHH;TenseurBB* gijBB; + Coordonnee* Mpt0;Coordonnee* Mptfin; + BaseB * giB_0; BaseB * giB_tdt; + BaseH * giH_0; BaseH * giH_tdt; + Mat_pleine jB0(dim,dim),jBfin(dim,dim); + if ((cas==1) || (cas==11)) + // calcul d'une ortho interessance de visualisation des tenseurs + // cas de tenseur 3D -> Ia, cas 1D on prend un vecteur norme collineaire + // avec g1, dans le cas 2D + // la nouvelle base jB est calculee dans def par projection de "Ia" sur Galpha + // le resultat est une matrice de passage utilisable pour le changement de base + // jB0 a t=0, B pour les tenseurs BB, jH0 idem pour les tenseurs HH + // resultat a t+dt + {const Met_abstraite::InfoImp& ex = def->RemontImp(absolue,jB0,jBfin); + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + } + else if ((cas==2) || (cas==12)) + // resultat a t + {const Met_abstraite::InfoExp_tdt& ex= def->RemontExp_tdt(absolue,jB0,jBfin); + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + }; + + // on définie des indicateurs pour ne pas faire plusieurs fois le même calcul + List_io::const_iterator ie,iefin=enu.end(); + bool besoin_coordonnees = false; + for (ie=enu.begin(); ie!=iefin;ie++) + { if (Meme_famille((*ie).Enum(),X1)) besoin_coordonnees=true; + }; + + // ----- maintenant on calcule les grandeurs nécessaires ----- + + fluxDH = (ptIntegThermi.FluxH()); + CoordonneeB interB(dim); // variable inter + for (int i=1;i<= dim; i++) + interB += (*giB_tdt)(i) * fluxDH(i); + fluxD = interB.Coor(); + + gradTB = (ptIntegThermi.GradTB()); + CoordonneeH interH(dim); // variable inter + for (int i=1;i<= dim; i++) + interH += gradTB(i) * (*giH_tdt)(i); + gradT = interH.Coor(); + + DgradTB = (ptIntegThermi.DgradTB()); + interH.Zero(); // variable inter + for (int i=1;i<= dim; i++) + interH += DgradTB(i) * (*giH_tdt)(i); + DgradT = interH.Coor(); + + DeltagradTB = (ptIntegThermi.DeltaGradTB()); + interH.Zero(); // variable inter + for (int i=1;i<= dim; i++) + interH += DeltagradTB(i) * (*giH_tdt)(i); + DeltagradT = interH.Coor(); + + if (besoin_coordonnees) + Mtdt = def->Position_tdt(); + + // donnees propre a la loi thermique au pt d'integ + CompThermoPhysiqueAbstraite::SaveResul* sTP = tabSaveTP(iteg); + // donnees propre a la loi mécanique au pt d'integ + Loi_comp_abstraite::SaveResul* sDon=NULL; // les données spécifique mécanique + if (sDon != NULL) {sDon = tabSaveDon(iteg);}; // au pt d'integ si elles existes + // données propre à la déformation au pt d'integ + Deformation::SaveDefResul * sDefDon = tabSaveDefDon(iteg); + + //----- fin du calcul des grandeurs nécessaires ----- + + // on balaie maintenant la liste des grandeurs à sortir + int it; // it est l'indice dans le tableau de retour + for (it=1,ie=enu.begin(); ie!=iefin;ie++,it++) + { + switch ((*ie).Enum()) + { case FLUXD1 : tab_ret(it)= fluxD(1); break; + case FLUXD2 : tab_ret(it)= fluxD(2); break; + case FLUXD3 : tab_ret(it)= fluxD(3); break; + case GRADT1 : tab_ret(it)= gradT(1); break; + case GRADT2 : tab_ret(it)= gradT(2); break; + case GRADT3 : tab_ret(it)= gradT(3); break; + case DGRADT1 : tab_ret(it)= DgradT(1); break; + case DGRADT2 : tab_ret(it)= DgradT(2); break; + case DGRADT3 : tab_ret(it)= DgradT(3); break; + case TEMP : tab_ret(it)= ptIntegThermi.Temperature(); break; + case X1 : tab_ret(it)= Mtdt(1); break; + case X2 : tab_ret(it)= Mtdt(2); break; + case X3 : tab_ret(it)= Mtdt(3); break; + default : + {int posi = (*ie).Position()-NbEnum_ddl(); + switch (posi) + { case 107: /*norme_gradT*/ tab_ret(it)=ptIntegThermi.Norme_gradT() ;break; + case 108: /*norme_DgradT*/ tab_ret(it)=ptIntegThermi.Norme_DGradT_const() ;break; + case 109: /*norme_dens_flux*/ tab_ret(it)=ptIntegThermi.Norme_flux_const() ;break; + case 111: /*DeltagradT1*/ tab_ret(it)=DeltagradT(1) ;break; + case 112: /*DeltagradT2*/ tab_ret(it)=DeltagradT(2) ;break; + case 113: /*DeltagradT3*/ tab_ret(it)=DeltagradT(3) ;break; + default : + {cout << "\n cas de ddl actuellement non traite " + << "\n pas de ddl " << (*ie).Nom() << " dans l'element " + << "\n ou cas non implante pour l'instant" + << "\n ElemThermi::Valeur_multi(...."; + }; + }; // fin cas **** 2 >>>>> + }; + }; + + };// -- fin de la boucle sur la liste de Ddl_enum_etendu + + // liberation des tenseurs intermediaires + LibereTenseur(); + return tab_ret; + }; + + +// 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 ElemThermi::Valeurs_Tensorielles(bool absolue,Enum_dure temps,List_io& enu + ,int iteg,int cas ) + + { // ----- def de grandeurs de travail + // def de la dimension des tenseurs + int dim = ParaGlob::Dimension(); + PtIntegThermiInterne & ptIntegThermi = (*lesPtIntegThermiInterne)(iteg); + + + // def de conteneur pour la sortie + Coordonnee* fluxD=NULL; bool besoin_fluxD = false; + Coordonnee* gradT=NULL; bool besoin_gradT = false; + Coordonnee* DgradT=NULL; bool besoin_DgradT = false; + Coordonnee* DeltagradT=NULL; bool besoin_deltagradT = false; + + Coordonnee* Mtdt=NULL; // coordonnées éventuelles du point d'intégration considéré + bool besoin_coordonnees = false; + + double* erreur = NULL; bool besoin_erreur = false; + + // --- dev d'un ensemble de variable booléenne pour gérer les sorties en une passe ----- + // on se réfère au informations définit dans la méthode: Les_type_evolues_internes() + + // on initialise ces variables booléennes + List_io::iterator ipq,ipqfin=enu.end(); + for (ipq=enu.begin();ipq!=ipqfin;ipq++) + {switch ((*ipq).EnuTypeQuelconque().EnumTQ()) //,FLUXD, GRADT, DGRADT + {case FLUXD : {besoin_fluxD=true; + Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee())); + fluxD = gr.ConteneurCoordonnee(); break;} + case GRADT : {besoin_gradT=true; + Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee())); + gradT = gr.ConteneurCoordonnee(); break;} + + case DGRADT : {besoin_DgradT=true; + Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee())); + DgradT = gr.ConteneurCoordonnee(); break;} + case DELTAGRADT : {besoin_deltagradT=true; + Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) ((*ipq).Grandeur_pointee())); + DeltagradT = gr.ConteneurCoordonnee(); break;} + + default : + {// on initialise la grandeur pour éviter d'avoir des valeurs aléatoires + ((*ipq).Grandeur_pointee())->InitParDefaut(); + if (ParaGlob::NiveauImpression() > 0) + {cout << "\nWarning : attention cas non traite: " + << ((*ipq).EnuTypeQuelconque().NomPlein()) << "!\n"; + if (ParaGlob::NiveauImpression() > 5) + cout << "\n ElemThermi::Valeurs_Tensorielles(...."; + }; + }; + }; + }; + + // definition générale + def->ChangeNumInteg(iteg); // on change le numéro de point d'intégration courant + if (((cas == 1) || (cas == 2))) + { // cas d'une premiere initialisation + Tableau tab(5); + tab(1) = iM0; tab(2) = iMt; tab(3) = iMtdt; + tab(4) = igiH_0; tab(5) = igijHH_0; + met->PlusInitVariables(tab) ; + } + // éléments de métrique et matrices de passage + TenseurHH* gijHH;TenseurBB* gijBB; + Coordonnee* Mpt0;Coordonnee* Mptfin; + BaseB * giB_0; BaseB * giB_tdt; + BaseH * giH_0; BaseH * giH_tdt; + Mat_pleine jB0(dim,dim),jBfin(dim,dim); + if ((cas==1) || (cas==11)) + // calcul d'une ortho interessance de visualisation des tenseurs + // cas de tenseur 3D -> Ia, cas 1D on prend un vecteur norme collineaire + // avec g1, dans le cas 2D + // la nouvelle base jB est calculee dans def par projection de "Ia" sur Galpha + // le resultat est une matrice de passage utilisable pour le changement de base + // jB0 a t=0, B pour les tenseurs BB, jH0 idem pour les tenseurs HH + // resultat a t+dt + {const Met_abstraite::InfoImp& ex = def->RemontImp(absolue,jB0,jBfin); + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + } + else if ((cas==2) || (cas==12)) + // resultat a t + {const Met_abstraite::InfoExp_tdt& ex= def->RemontExp_tdt(absolue,jB0,jBfin); + Mpt0 = ex.M0; Mptfin = ex.Mtdt; + gijHH = ex.gijHH_tdt;gijBB = ex.gijBB_tdt; + giB_0 = ex.giB_0;giB_tdt = ex.giB_tdt; + giH_0 = ex.giH_0; giH_tdt = ex.giH_tdt; + } + else + { cout << "\n erreur, cas non prevu! " << "\n ElemThermi::Valeurs_Tensorielles(..."; Sortie(1);}; + + // ----- calcul des grandeurs à sortir + + // ----- maintenant on calcule les grandeurs nécessaires ----- + + if (besoin_fluxD) + {CoordonneeH & fluxDH = (ptIntegThermi.FluxH()); + CoordonneeB interB(dim); // variable inter + for (int i=1;i<= dim; i++) + interB += (*giB_tdt)(i) * fluxDH(i); + (*fluxD) = interB.Coor(); + }; + + if (besoin_gradT) + {CoordonneeB & gradTB = (ptIntegThermi.GradTB()); + CoordonneeH interH(dim); // variable inter + for (int i=1;i<= dim; i++) + interH += gradTB(i) * (*giH_tdt)(i); + (*gradT) = interH.Coor(); + }; + + if (besoin_DgradT) + {CoordonneeB & DgradTB = (ptIntegThermi.DgradTB()); + CoordonneeH interH(dim); // variable inter + for (int i=1;i<= dim; i++) + interH += DgradTB(i) * (*giH_tdt)(i); + (*DgradT) = interH.Coor(); + }; + + if (besoin_deltagradT) + {CoordonneeB & DeltagradTB = (ptIntegThermi.DeltaGradTB()); + CoordonneeH interH(dim); // variable inter + for (int i=1;i<= dim; i++) + interH += DeltagradTB(i) * (*giH_tdt)(i); + (*DeltagradT) = interH.Coor(); + }; + + if (besoin_coordonnees) + (*Mtdt) = def->Position_tdt(); + + + // donnees propre a la loi thermique au pt d'integ + CompThermoPhysiqueAbstraite::SaveResul* sTP = tabSaveTP(iteg); + // donnees propre a la loi mécanique au pt d'integ + Loi_comp_abstraite::SaveResul* sDon=NULL; // les données spécifique mécanique + if (sDon != NULL) {sDon = tabSaveDon(iteg);}; // au pt d'integ si elles existes + // données propre à la déformation au pt d'integ + Deformation::SaveDefResul * sDefDon = tabSaveDefDon(iteg); + + // liberation des tenseurs intermediaires + LibereTenseur(); + }; + + + + + diff --git a/Elements/Thermique/ElemThermi5.cc b/Elements/Thermique/ElemThermi5.cc new file mode 100755 index 0000000..43e3a23 --- /dev/null +++ b/Elements/Thermique/ElemThermi5.cc @@ -0,0 +1,847 @@ +// 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 "TypeQuelconqueParticulier.h" +#include "TypeConsTens.h" +#include "Loi_iso_elas3D.h" +#include "Loi_iso_elas1D.h" +#include "Loi_iso_elas2D_C.h" +#include "FrontPointF.h" + + + // -------------------- stabilisation d'hourglass ------------------- +// calcul d'élément de contrôle d'hourglass associée à un comportement +// str_precision : donne le type particulier d'élément à construire +void ElemThermi::Init_hourglass_comp(const ElemGeomC0& elgeHour, const string & str_precision + ,LoiAbstraiteGeneral * loiHourglass, const BlocGen & bloc) +{ + //!!!! en fait pour l'instant on n'utilise pas elgehour, on considère que le nombre de pti complet est celui de l'élément sans info annexe !!! + // sauf pour l'hexaèdre quadratique pour lequel on a définit un str_precision particulier + // on met à jour les indicateurs + if (Type_Enum_StabHourglass_existe(bloc.Nom(1))) + {type_stabHourglass = Id_Nom_StabHourglass(bloc.Nom(1).c_str()); + coefStabHourglass = bloc.Val(1); + } + else + { cout << "\n erreur, le type " << bloc.Nom(2) << " de gestion d'hourglass n'existe pas !!"; + if (ParaGlob::NiveauImpression() > 5) + cout << "\n ElemThermi::Init_hourglass_comp(..."; + cout << endl; + Sortie(1); + }; + switch (type_stabHourglass) + {case STABHOURGLASS_PAR_COMPORTEMENT : + { // -- choix de l'element pour le calcul de la raideur ----- + // on recherche un élément de même type, + // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage + // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas + // rattachés à un maillage existant en tant que tel + int nUmMail = this->Num_elt_const(); + int nUmElem = 1000000 + this->Num_elt(); + tab_elHourglass.Change_taille(1); + tab_elHourglass(1) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); + + if (tab_elHourglass(1) == NULL) + { // l'operation a echouee + cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; + cout << "\n l\'element : " << Nom_interpol(id_interpol) + << " " << Nom_geom(id_geom) << " " << str_precision + << " n\'est pas present dans le programme ! " << endl; + if (ParaGlob::NiveauImpression() > 5) + cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; + Sortie (1); + }; + // --- définition des noeuds de l'élément ----- + // on construit à partir des mêmes noeuds que ceux de l'élément père + // affectation des noeuds au nouvel élément + tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); + //--- def de la loi de comportement --- + // affectation de la loi + tab_elHourglass(1)->DefLoi(loiHourglass); + break; + } + case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : + { // ici on a besoin de deux éléments. Le premier sert à faire le calcul complet + // le second sert à faire un calcul réduit, comme l'élément réel + tab_elHourglass.Change_taille(2); + + // -- choix pour le calcul de la raideur ----- + // on recherche un élément de même type, + // par défaut : numéro de maillage = le numéro de this, car c'est bien rattaché à ce maillage, mais l'élément est caché, donc non accessible par le maillage + // numéro d'élément = 1000000 + numéro de this : a priori c'est deux numéros n'ont pas d'importance, car ils ne sont pas + // rattachés à un maillage existant en tant que tel + //-- le premier élément: + int nUmMail = this->Num_elt_const(); + int nUmElem = 1000000 + this->Num_elt(); + tab_elHourglass(1) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),str_precision); + if (tab_elHourglass(1) == NULL) + { // l'operation a echouee + cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; + cout << "\n l\'element : " << Nom_interpol(id_interpol) + << " " << Nom_geom(id_geom) << " " << str_precision + << " n\'est pas present dans le programme ! " << endl; + if (ParaGlob::NiveauImpression() > 5) + cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; + Sortie (1); + }; + //-- le second élément identique à this: on utilise le même numéro de maillage + // même infos annexes + nUmElem = 20000000 + this->Num_elt(); // on ajoute une unité pour le numéro + tab_elHourglass(2) = (ElemThermi*) Element::Choix_element(nUmMail,nUmElem,Id_geometrie(),Id_interpolation(),Id_TypeProblem(),this->infos_annexes); + + if (tab_elHourglass(2) == NULL) + { // l'operation a echouee + cout << "\n Erreur dans le choix d'un element interne utilise pour le blocage d'hourglass ****** "; + cout << "\n l\'element : " << Nom_interpol(id_interpol) + << " " << Nom_geom(id_geom) << " " << this->infos_annexes + << " n\'est pas present dans le programme ! " << endl; + if (ParaGlob::NiveauImpression() > 5) + cout << "\n ElemThermi::Init_hourglass_comp(..." << endl; + Sortie (1); + }; + // --- définition des noeuds de l'élément ----- + // on construit à partir des mêmes noeuds que ceux de l'élément père + // affectation des noeuds au nouvel élément + tab_elHourglass(1)->Tab_noeud() = this->Tab_noeud(); + tab_elHourglass(2)->Tab_noeud() = this->Tab_noeud(); + //--- def de la loi de comportement --- + // affectation de la loi + tab_elHourglass(1)->DefLoi(loiHourglass); + tab_elHourglass(2)->DefLoi(loiHourglass); + break; + } + + default : + cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; + cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; + Sortie(1); + }; +}; + +// stabilisation pour un calcul implicit +void ElemThermi::Cal_implicit_hourglass() +{ switch (type_stabHourglass) + {case STABHOURGLASS_PAR_COMPORTEMENT : + { // --- calcul de la raideur de l'élément, dans le cas implicite --- + Element::ResRaid resraid = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); + // on tiend compte du facteur de modération + (*(resraid.raid)) *= coefStabHourglass; + (*(resraid.res)) *= coefStabHourglass; + // on met à jour la raideur et le résidu de l'élément principal + (*raideur) += (*(resraid.raid)); + (*residu) += (*(resraid.res)); + +//---- debug +//cout << "\n raideur locale après stabilisation d'hourglass "; +//matRaideur.Affiche(); +//---- fin debug + }; + break; + case STABHOURGLASS_PAR_COMPORTEMENT_REDUIT : + { // --- calcul de la raideur de l'élément, dans le cas implicite --- + // ici on calcul la partie supposée supplémentaire à celle déjà présente dans le calcul réduit + + // au premier passage ou bien si on demande une grande précision de calcul, on calcul la raideur et le second membre, + // ensuite on ne calcul que le second membre + if ((raid_hourglass_transitoire == NULL)||(prepa_niveau_precision > 8)) + {// 1) calcul de la partie complète + Element::ResRaid resraid1 = tab_elHourglass(1)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); + // 2) calcul de la partie réduite + Element::ResRaid resraid2 = tab_elHourglass(2)->Calcul_implicit (ParaGlob::param->ParaAlgoControleActifs()); + // on soustrait en gardant le résultat dans resraid1 + (*(resraid1.raid)) -= (*(resraid2.raid)); + (*(resraid1.res)) -= (*(resraid2.res)); + // on tiend compte du facteur de modération + (*(resraid1.raid)) *= coefStabHourglass; + (*(resraid1.res)) *= coefStabHourglass; + // on sauvegarde la raideur + raid_hourglass_transitoire = new Mat_pleine((*(resraid1.raid))); + // on met à jour la raideur et le résidu de l'élément principal + (*raideur) += (*(resraid1.raid)); + (*residu) += (*(resraid1.res)); + } + else + {// sinon on utilise la précédente raideur sauvegardée et on ne calcul que la partie résidue + Vecteur* resHourglass1 = NULL; + resHourglass1 = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); + Vecteur* resHourglass2 = NULL; + resHourglass2 = tab_elHourglass(2)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs()); + // on soustrait les résidus en gardant le résultat dans resraid1 + (*(resHourglass1)) -= (*(resHourglass2)); + // on tiend compte du facteur de modération + (*(resHourglass1)) *= coefStabHourglass; + // on met à jour le résidu de l'élément principal + (*residu) += (*(resHourglass1)); + // pour la partie raideur: on met à jour la raideur de l'élément principal + (*raideur) += (*raid_hourglass_transitoire); + }; + +//---- debug +//cout << "\n raideur locale après stabilisation d'hourglass "; +//matRaideur.Affiche(); +//---- fin debug + }; + break; + case STABHOURGLASS_NON_DEFINIE : + // on ne fait rien + break; + default : + cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; + cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; + Sortie(1); + }; + +}; + +// stabilisation pour un calcul explicit +void ElemThermi::Cal_explicit_hourglass(bool atdt) +{ switch (type_stabHourglass) + {case STABHOURGLASS_PAR_COMPORTEMENT : + { // --- calcul de la raideur de l'élément, dans le cas implicite --- + Vecteur* resHourglass = NULL; + if (atdt) + {resHourglass = tab_elHourglass(1)->CalculResidu_tdt (ParaGlob::param->ParaAlgoControleActifs());} + else + {resHourglass = tab_elHourglass(1)->CalculResidu_t (ParaGlob::param->ParaAlgoControleActifs());}; + // on tiend compte du facteur de modération + (*resHourglass) *= coefStabHourglass; + // on met à jour le résidu de l'élément principal + (*residu) += (*resHourglass); + +//---- debug +//cout << "\n raideur locale après stabilisation d'hourglass "; +//matRaideur.Affiche(); +//---- fin debug + }; + break; + case STABHOURGLASS_NON_DEFINIE : + // on ne fait rien + break; + default : + cout << "\n*** Erreur : cas de gestop, d'hourglass non defini !\n"; + cout << "\n ElemThermi::Cal_implicit_hourglass() \n"; + Sortie(1); + }; + +}; + + +// récupération de l'energie d'hourglass éventuelle +double ElemThermi::Energie_Hourglass() +{ double enerHourglass = 0.; + switch (type_stabHourglass) + {case STABHOURGLASS_PAR_COMPORTEMENT : + { // on récupère les énergies stockées à l'élément + const EnergieThermi& energieTotale = tab_elHourglass(1)->EnergieTotaleElement(); + enerHourglass = coefStabHourglass * (energieTotale.EnergieElastique() + + energieTotale.DissipationPlastique() + energieTotale.DissipationVisqueuse()); + }; + break; + }; + return enerHourglass; +}; + +// fonction a renseigner par les classes dérivées, concernant les répercutions +// éventuelles due à la suppression de tous les frontières +// nums_i : donnent les listes de frontières supprimées +void ElemThermi::Prise_en_compte_des_consequences_suppression_tous_frontieres() +{// il faut supprimer toutes les déformations liés aux frontières + int tail_S = defSurf.Taille(); + for (int i=1;i<=tail_S;i++) + { delete defSurf(i); + defSurf(i)=NULL; + }; + int tail_A = defArete.Taille(); + for (int i=1;i<=tail_A;i++) + { delete defArete(i); + defArete(i)=NULL; + }; +}; +// idem pour une frontière (avant qu'elle soit supprimée) +void ElemThermi::Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront) +{ int taille = tabb.Taille(); +// on choisit en fonction du type de frontière + if (( elemFront->Type_geom_front() == LIGNE)&& (defArete.Taille()!=0)) + {int taille_ligne = taille - posi_tab_front_lin; // a priori = cas sans les points + if (posi_tab_front_point != 0) // cas où il y a des points + taille_ligne = posi_tab_front_point-posi_tab_front_lin; + for (int i=1; i<=taille_ligne; i++) + {if ((tabb(i+posi_tab_front_lin) == elemFront)&& (defArete(i) != NULL)) + {delete defArete(i);defArete(i)=NULL;break;} + } + } + else if (( elemFront->Type_geom_front() == SURFACE) && (defSurf.Taille()!=0)) + {if (posi_tab_front_lin != 0) // si == 0 cela signifie qu'il n'y a pas de surface à supprimer !! + { for (int i=1; i<=posi_tab_front_lin; i++) // posi_tab_front_lin == le nombre de surfaces, qui sont obligatoirement en début de tableau + if ((tabb(i) == elemFront)&& (defSurf(i) != NULL)) + {delete defSurf(i);defSurf(i)=NULL;break;} + }; + }; + +}; + + +// Calcul des frontieres de l'element +// creation des elements frontieres et retour du tableau de ces elements +// la création n'a lieu qu'au premier appel +// ou lorsque l'on force le paramètre force a true +// dans ce dernier cas seul les frontière effacées sont recréée +// cas : +// = 0 -> on veut toutes les frontières +// = 1 -> on veut uniquement les surfaces +// = 2 -> on veut uniquement les lignes +// = 3 -> on veut uniquement les points +// = 4 -> on veut les surfaces + les lignes +// = 5 -> on veut les surfaces + les points +// = 6 -> on veut les lignes + les points +Tableau const & ElemThermi::Frontiere_elethermi(int cas, bool force) +{// le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + int taille = tabb.Taille(); // la taille initiales des frontières + if (force) // dans ce cas on commence par tout effacer + { // on efface les surfaces (s'il y en a) + for (int i=1;i<=posi_tab_front_lin;i++) + {if (tabb(i) != NULL) + {delete tabb(i); //on commence par supprimer + tabb(i)=NULL; + // on supprime également éventuellement la déformation associée + if (defSurf.Taille() != 0) + if (defSurf(i) != NULL) + {delete defSurf(i);defSurf(i)=NULL;}; + ind_front_surf = 0; // on indique qu'il ne reste plus de frontière surface + }; + }; + // on efface les lignes (s'il y en a) + for (int i=1;i<=posi_tab_front_point - posi_tab_front_lin;i++) + {if (tabb(i+posi_tab_front_lin) != NULL) + {delete tabb(i+posi_tab_front_lin); //on commence par supprimer + tabb(i+posi_tab_front_lin)=NULL; + // on supprime également éventuellement la déformation associée + if (defArete.Taille() != 0) + if (defArete(i) != NULL) + {delete defArete(i);defArete(i)=NULL;}; + ind_front_lin = 0; // on indique qu'il ne reste plus de frontière ligne + }; + }; + // on efface les points (s'il y en a) + for (int i=1;i<=taille - posi_tab_front_point;i++) + {if (tabb(i+posi_tab_front_point) != NULL) + {delete tabb(i+posi_tab_front_point); //on commence par supprimer + tabb(i+posi_tab_front_point)=NULL; + ind_front_point = 0; // on indique qu'il ne reste plus de frontière ligne + }; + }; + }; + + // -- maintenant on s'occupe de la construction conditionnelle + bool built_surf = false;bool built_ligne = false; bool built_point = false; + switch (cas) + {case 0: built_surf = built_ligne = built_point = true; break; + case 1: built_surf = true; break; + case 2: built_ligne = true; break; + case 3: built_point = true; break; + case 4: built_surf = built_ligne = true; break; + case 5: built_surf = built_point = true; break; + }; + + if ( ((ind_front_surf == 0)&& (ind_front_lin == 0) && (ind_front_point == 0)) || force ) + { + // récup de l'élément géométrique + ElemGeomC0& el = ElementGeometrique(); + int tail_ar = el.NbSe(); // nombre potentiel d'arêtes + int tail_fa = el.NbFe(); // nombre potentiel de faces + int tail_po = el.Nbne(); // nombre potentiel de points + // récup du tableau de ddl actuel + const DdlElement & tdd = TableauDdl(); + + // --- on va construire en fonction des indicateurs des tableaux intermédiaires + int new_posi_tab_front_point = 0; //init par défaut + int new_posi_tab_front_lin = 0; //init par défaut + int new_ind_front_point = 0; + int new_ind_front_lin = 0; + int new_ind_front_surf = 0; + // -- pour les surfaces + Tableau tabb_surf; + if ((built_surf)&& ((ind_front_surf == 0)||force)) + {tabb_surf.Change_taille(tail_fa,NULL);// init par défaut + for (int num=1;num<=tail_fa;num++) + { int nbnoe = el.Nonf()(num).Taille(); // nb noeud de la surface + Tableau tab(nbnoe); // les noeuds de la frontiere + DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres + for (int i=1;i<= nbnoe;i++) + { tab(i) = tab_noeud(el.Nonf()(num)(i)); + ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); + }; + tabb_surf(num) = new_frontiere_surf(num,tab,ddelem); + }; + // nouveau indicateur d'existence + new_ind_front_surf = 1; + // on positionne les nouvelles positions + new_posi_tab_front_point += tail_fa; + new_posi_tab_front_lin += tail_fa; + }; + // -- pour les lignes + Tableau tabb_ligne; + if ((built_ligne)&& ((ind_front_lin == 0)||force)) + {tabb_ligne.Change_taille(tail_ar,NULL);// init par défaut + for (int num=1;num<=tail_ar;num++) + { int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête + Tableau tab(nbnoe); // les noeuds de l'arête frontiere + DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres + for (int i=1;i<= nbnoe;i++) + { tab(i) = tab_noeud(el.NonS()(num)(i)); + ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); + }; + tabb_ligne(num) = new_frontiere_lin(num,tab,ddelem); + }; + // nouveau indicateur d'existence + new_ind_front_lin = 1; + // on positionne les nouvelles positions + new_posi_tab_front_point += tail_ar; + }; + // -- pour les points + Tableau tabb_point; + if ((built_point) && ((ind_front_point == 0)||force)) + {tabb_point.Change_taille(tail_po,NULL);// init par défaut + // maintenant création des frontière point éventuellement + Tableau tab(1); // les noeuds de la frontiere (tab de travail) + DdlElement ddelem(1); // les ddlelements des points frontieres (tab de travail) + for (int i=1;i<=tail_po;i++) + if (tabb_point(i) == NULL) + { tab(1) = tab_noeud(i); + ddelem.Change_un_ddlNoeudElement(1,tdd(i)); + tabb_point(i) = new FrontPointF(tab,ddelem); + }; + // nouveau indicateur d'existence + new_ind_front_point = 1; + }; + + // --- mise à jour du tableau globale et des indicateurs ad hoc + int taille_finale = tabb_surf.Taille()+tabb_ligne.Taille()+tabb_point.Taille(); + tabb.Change_taille(taille_finale); + // cas des points + if (new_ind_front_point) // là is s'agit de nouveaux éléments + {for (int i=tail_po;i>0;i--) // transfert pour les noeuds + { tabb(i+new_posi_tab_front_point) = tabb_point(i);} + } + else if (ind_front_point) // là il s'agit d'anciens éléments + {for (int i=tail_po;i>0;i--) // transfert pour les noeuds en descendant + { tabb(i+new_posi_tab_front_point) = tabb(i+posi_tab_front_point);} + }; + // cas des lignes + if (new_ind_front_lin) // là il s'agit de nouveaux éléments + {for (int i=1;i<=tail_ar;i++) // transfert + { tabb(i+new_posi_tab_front_lin) = tabb_ligne(i);} + } + else if (ind_front_lin) // là il s'agit d'anciens éléments + {for (int i=tail_ar;i>0;i--) // transfert en descendant + { tabb(i+new_posi_tab_front_lin) = tabb(i+posi_tab_front_lin);} + }; + // cas des surfaces + if (new_ind_front_surf) // là is s'agit de nouveaux éléments + {for (int i=1;i<=tail_fa;i++) // transfert + { tabb(i) = tabb_surf(i);} + }; + // dans le cas où il y avait des anciens éléments, il n'y a rien n'a faire + // car le redimentionnement de tabb ne change pas les premiers éléments + + // mis à jour des indicateurs + ind_front_surf = new_ind_front_surf; + posi_tab_front_lin = new_posi_tab_front_lin; + ind_front_lin = new_ind_front_lin; + posi_tab_front_point = new_posi_tab_front_point; + ind_front_point = new_ind_front_point; + }; + // retour du tableau + return (Tableau &)tabb; +}; + +// ramène la frontière point +// éventuellement création des frontieres points de l'element et stockage dans l'element +// si c'est la première fois sinon il y a seulement retour de l'elements +// a moins que le paramètre force est mis a true +// dans ce dernier cas la frontière effacéee est recréée +// num indique le numéro du point à créer (numérotation EF) +ElFrontiere* const ElemThermi::Frontiere_points(int num,bool force) +{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer + // récup de l'élément géométrique + ElemGeomC0& el = ElementGeometrique(); + int tail_po = el.Nbne(); // nombre potentiel de points + if (num > tail_po) + return NULL; + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + // on regarde si les frontières points existent sinon on les crée + if (ind_front_point == 1) + {return (ElFrontiere*)tabb(posi_tab_front_point+num);} + else if ( ind_front_point == 2) + // cas où certaines frontières existent + {if (tabb(posi_tab_front_point+num) != NULL) + return (ElFrontiere*)tabb(posi_tab_front_point+num); + }; + + // arrivée ici cela veut dire que la frontière point n'existe pas + // on l'a reconstruit éventuellement + + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + if ((ind_front_point == 0) || force ) + {// récup du tableau de ddl + const DdlElement & tdd = TableauDdl(); + int taille = tabb.Taille(); // la taille initiales des frontières + int tail_fa = el.NbFe(); // nombre potentiel de faces + int tail_ar = el.NbSe(); // nombre potentiel d'arêtes + // dimensionnement du tableau de frontières ligne si nécessaire + if (ind_front_point == 0) + {if ((ind_front_lin > 0) && (ind_front_surf == 0)) + // cas où les frontières lignes existent seules, on ajoute les points + { int taille_finale = tail_ar + tail_po; + tabb.Change_taille(taille_finale); + for (int i=1;i<= tail_ar;i++) // transfert pour les lignes + tabb(i) = tabb(i+tail_ar); + posi_tab_front_point=tail_ar; + posi_tab_front_lin = 0; // car on n'a pas de surface + } + else if ((ind_front_lin > 0) && (ind_front_surf > 0)) + // cas où les frontières lignes existent et surfaces et pas de points, donc on les rajoutes + { int taille_finale = tail_fa + tail_po+tail_ar; + tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces et les lignes sont + // conservées, donc pas de transferts à prévoir + posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes + posi_tab_front_lin = tail_fa; // après les surfaces + } + else + { // cas où il n'y a pas de frontières lignes + if (ind_front_surf == 0) // cas où il n'y a pas de surface + {tabb.Change_taille(tail_po,NULL); // on n'a pas de ligne, pas de point et pas de surface + posi_tab_front_point = posi_tab_front_lin = 0;} + else {tabb.Change_taille(tail_po+tail_fa); // cas où les surfaces existent + // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau + posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces + }; + }; + // et on met les pointeurs de points en NULL + for (int i=1;i<= tail_po;i++) + { tabb(i+posi_tab_front_point) = NULL;} + }; + // maintenant création de la frontière point + Tableau tab(1); // les noeuds de la frontiere + tab(1) = tab_noeud(num); + DdlElement ddelem(1); // les ddlelements des points frontieres + ddelem.Change_un_ddlNoeudElement(1,tdd(num)); + tabb(posi_tab_front_point+num) = new FrontPointF(tab,ddelem); + // on met à jour l'indicateur ind_front_point + ind_front_point = 1; // a priori + for (int npoint=1;npoint<=tail_po;npoint++) + if (tabb(posi_tab_front_point+npoint) == NULL) + { ind_front_point = 2; break;}; + }; + // maintenant normalement la frontière est créé on la ramène + return (ElFrontiere*)tabb(posi_tab_front_point+num); +}; + +// ramène la frontière linéique +// éventuellement création des frontieres linéique de l'element et stockage dans l'element +// si c'est la première fois et en 3D sinon il y a seulement retour de l'elements +// a moins que le paramètre force est mis a true +// dans ce dernier cas la frontière effacéee est recréée +// num indique le numéro de l'arête à créer (numérotation EF) +// nbneA: nombre de noeuds des segments frontières +// el : l'élément +ElFrontiere* const ElemThermi::Frontiere_lineique(int num,bool force) +{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière linéique à calculer + // récup de l'élément géométrique + ElemGeomC0& el = ElementGeometrique(); + int tail_ar = el.NbSe(); // nombre potentiel d'arêtes + if (num > tail_ar) + return NULL; + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + // on regarde si les frontières linéiques existent sinon on les crée + if (ind_front_lin == 1) + {return (ElFrontiere*)tabb(posi_tab_front_lin+num);} + else if ( ind_front_lin == 2) + // cas où certaines frontières existent + {if (tabb(posi_tab_front_lin+num) != NULL) + return (ElFrontiere*)tabb(posi_tab_front_lin+num); + }; + + // arrivée ici cela veut dire que la frontière ligne n'existe pas + // on l'a reconstruit + + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + if ((ind_front_lin == 0) || force ) + {// récup du tableau de ddl + const DdlElement & tdd = TableauDdl(); + int taille = tabb.Taille(); // la taille initiales des frontières + int tail_fa = el.NbFe(); // nombre potentiel de faces + int tail_po = el.Nbne(); // nombre potentiel de points + // dimensionnement du tableau de frontières ligne si nécessaire + if (ind_front_lin == 0) + {if ((ind_front_point > 0) && (ind_front_surf == 0)) + // cas où les frontières points existent seules, on ajoute les lignes + { int taille_finale = tail_ar + tail_po; + tabb.Change_taille(taille_finale); + for (int i=1;i<= tail_po;i++) + tabb(i+tail_ar) = tabb(i); + posi_tab_front_point=tail_ar; + posi_tab_front_lin = 0; // car on n'a pas de surface + } + else if ((ind_front_point > 0) && (ind_front_surf > 0)) + // cas où les frontières points existent et surfaces et pas de ligne, donc on les rajoutes + { int taille_finale = tail_fa + tail_po+tail_ar; + tabb.Change_taille(taille_finale);// les grandeurs pour les surfaces sont conservées + for (int i=1;i<= tail_po;i++) // transfert pour les noeuds + { tabb(i+tail_ar+tail_fa) = tabb(i+tail_fa);}; + posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes + posi_tab_front_lin = tail_fa; // après les surfaces + } + else + { // cas où il n'y a pas de frontières points + if (ind_front_surf == 0) // cas où il n'y a pas de surface + {tabb.Change_taille(tail_ar,NULL); // on n'a pas de ligne, pas de point et pas de surface + posi_tab_front_lin = posi_tab_front_point = 0;} + else {tabb.Change_taille(tail_ar+tail_fa); // cas où les surfaces existent + // le redimensionnement n'affecte pas les surfaces qui sont en début de tableau + posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces + }; + }; + // et on met les pointeurs de lignes en NULL + for (int i=1;i<= tail_ar;i++) // transfert pour les noeuds + { tabb(i+posi_tab_front_lin) = NULL;} + }; + // maintenant création de la ligne + int nbnoe = el.NonS()(num).Taille(); // nb noeud de l'arête + Tableau tab(nbnoe); // les noeuds de l'arête frontiere + DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres + for (int i=1;i<= nbnoe;i++) + { tab(i) = tab_noeud(el.NonS()(num)(i)); + ddelem.Change_un_ddlNoeudElement(i,tdd(el.NonS()(num)(i))); + }; + tabb(posi_tab_front_lin+num) = new_frontiere_lin(num,tab,ddelem); + ind_front_lin = 1; // a priori + for (int nlign=1;nlign<=tail_ar;nlign++) + if (tabb(posi_tab_front_lin+nlign) == NULL) + { ind_front_lin = 2; break;}; + }; + // maintenant normalement la frontière est créé on la ramène + return (ElFrontiere*)tabb(posi_tab_front_lin+num); +}; + +// ramène la frontière surfacique +// éventuellement création des frontieres surfacique de l'element et stockage dans l'element +// si c'est la première fois sinon il y a seulement retour de l'elements +// a moins que le paramètre force est mis a true +// dans ce dernier cas la frontière effacéee est recréée +// num indique le numéro de la surface à créer (numérotation EF) +ElFrontiere* const ElemThermi::Frontiere_surfacique(int num,bool force) +{ // -- tout d'abord on évacue le cas où il n'y a pas de frontière surfacique à calculer + // récup de l'élément géométrique + ElemGeomC0& el = ElementGeometrique(); + int tail_fa = el.NbFe(); // nombre potentiel de faces + if (num > tail_fa) + return NULL; + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + // on regarde si les frontières surfacique existent sinon on les crée + if (ind_front_surf == 1) + {return (ElFrontiere*)tabb(num);} + else if ( ind_front_surf == 2) + // cas où certaines frontières existent + {if (tabb(num) != NULL) + return (ElFrontiere*)tabb(num); + }; + + // arrivée ici cela veut dire que la frontière surface n'existe pas + // on l'a reconstruit + + + // le calcul et la création ne sont effectués qu'au premier appel + // ou lorsque l'on veut forcer une recréation + if ((ind_front_surf == 0) || force ) + {// récup du tableau de ddl + const DdlElement & tdd = TableauDdl(); + int taille = tabb.Taille(); // la taille initiales des frontières + int tail_ar = el.NbSe(); // nombre potentiel d'arêtes + int tail_po = el.Nbne(); // nombre potentiel de points + // dimensionnement du tableau de frontières surfaces si nécessaire + if (ind_front_surf == 0) + {if ((ind_front_point > 0) && (ind_front_lin == 0)) + // cas où les frontières points existent seules, on ajoute les surfaces + { int taille_finale = tail_fa + tail_po; + tabb.Change_taille(taille_finale); + for (int i=1;i<= tail_po;i++) + tabb(i+tail_fa) = tabb(i); + posi_tab_front_lin=posi_tab_front_point=tail_fa; + } + else if ((ind_front_point > 0) && (ind_front_lin > 0)) + // cas où les frontières points existent et lignes et pas de surfaces, donc on les rajoutes + { int taille_finale = tail_fa + tail_po+tail_ar; + tabb.Change_taille(taille_finale); + // --transfert pour les noeuds et les lignes + for (int i=1;i<= tail_po;i++) // transfert pour les noeuds + { tabb(i+tail_ar+tail_fa) = tabb(i+tail_ar);}; + for (int i=1;i<= tail_ar;i++) // transfert pour les lignes + { tabb(i+tail_fa) = tabb(i);}; + // --def des indicateurs + posi_tab_front_point=tail_ar+tail_fa; // après les faces et les lignes + posi_tab_front_lin = tail_fa; // après les surfaces + } + else + { // cas où il n'y a pas de frontières points + if (ind_front_lin == 0) // cas où il n'y a pas de lignes + {tabb.Change_taille(tail_fa,NULL); // on n'a pas de ligne, pas de point et pas de surface + posi_tab_front_lin = posi_tab_front_point = tail_fa; + } // on peut tout mettre à NULL + else {tabb.Change_taille(tail_ar+tail_fa); // cas où les lignes existent + for (int i=1;i<= tail_ar;i++) // transfert pour les lignes + tabb(i+tail_fa) = tabb(i); + posi_tab_front_lin = posi_tab_front_point = tail_fa; // après les surfaces + }; + }; + // --et on met les pointeurs de surfaces en NULL + for (int i=1;i<=tail_fa;i++) + tabb(i)=NULL; + }; + // maintenant création de la surface + int nbnoe = el.Nonf()(num).Taille(); // b noeud de la surface + Tableau tab(nbnoe); // les noeuds de la frontiere + DdlElement ddelem(nbnoe); // les ddlelements des noeuds frontieres + for (int i=1;i<= nbnoe;i++) + { tab(i) = tab_noeud(el.Nonf()(num)(i)); + ddelem.Change_un_ddlNoeudElement(i,tdd(el.Nonf()(num)(i))); + }; + tabb(num) = new_frontiere_surf(num,tab,ddelem); + ind_front_surf = 1; // a priori + for (int nsurf=1;nsurf<=tail_fa;nsurf++) + if (tabb(nsurf) == NULL) + { ind_front_surf = 2; break;}; + }; + // maintenant normalement la frontière est créé on la ramène + return (ElFrontiere*)tabb(num); +}; + + + // calcul éventuel de la normale à un noeud + // ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D + // qui possède un repère d'orientation + // en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace + // si le calcul n'existe pas --> coor.Dimension() = 0 + // ramène un entier : + // == 1 : calcul normal + // == 0 : problème de calcul -> coor.Dimension() = 0 + // == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre + // c'est le cas par exemple des noeuds exterieurs pour les éléments SFE + // mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour + // calculer la normale à ce noeud là + // temps: indique à quel moment on veut le calcul + // pour des éléments particulier (ex: SFE) la méthode est surchargée + int ElemThermi::CalculNormale_noeud(Enum_dure temps,const Noeud& noe,Coordonnee& coor) + { + int retour = 1; // init du retour : on part d'un bon a priori + Enum_type_geom enutygeom = Type_geom_generique(this->Id_geometrie()); + // if ((enutygeom == LIGNE) || (enutygeom == SURFACE)) + if (enutygeom != SURFACE) // dans une première étape on ne s'occupe que des surfaces + {coor.Libere(); // pas de calcul possible + retour = 0; + } + else // sinon le calcul est possible + { // on commence par repérer le noeud dans la numérotation locale + int nuoe=0; + int borne_nb_noeud=tab_noeud.Taille()+1; + for (int i=1;i< borne_nb_noeud;i++) + {Noeud& noeloc = *tab_noeud(i); + if ( (noe.Num_noeud() == noeloc.Num_noeud()) + && (noe.Num_Mail() == noeloc.Num_Mail()) + ) + {nuoe = i; break; + }; + }; + // on ne continue que si on a trouvé le noeud + if (nuoe != 0) + { ElemGeomC0& elemgeom = ElementGeometrique(); // récup de la géométrie + // récup des coordonnées locales du noeuds + const Coordonnee& theta_noeud = elemgeom.PtelemRef()(nuoe); + // récup des phi et dphi au noeud + const Vecteur & phi = elemgeom.Phi(theta_noeud); + const Mat_pleine& dphi = elemgeom.Dphi(theta_noeud); + switch (temps) + {case TEMPS_0 : + {const BaseB& baseB = met->BaseNat_0(tab_noeud,dphi,phi); + coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); + coor.Normer(); + break; + } + case TEMPS_t : + {const BaseB& baseB = met->BaseNat_t(tab_noeud,dphi,phi); + coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); + coor.Normer(); + break; + } + case TEMPS_tdt : + {const BaseB& baseB = met->BaseNat_tdt(tab_noeud,dphi,phi); + coor = Util::ProdVec_coor( baseB.Coordo(1), baseB.Coordo(2)); + coor.Normer(); + break; + } + default : + cout << "\nErreur : valeur incorrecte du temps demande = " + << Nom_dure(temps) << " !\n"; + cout << "\n ElemThermi::CalculNormale_noeud(Enum_dure temps... \n"; + retour = 0; + Sortie(1); + }; + } + else + {cout << "\n *** erreur le noeud demande num= "<. +// +// 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: Définir des classes d'exception pour la gestion d'erreur * + * concernant les éléments thermiques. * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * * + * VERIFICATION: * + * * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * ! ! ! ! * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * + * MODIFICATIONS: * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * $ * + ************************************************************************/ +#ifndef EXCEPTIONSELEMTHERMI_H +#define EXCEPTIONSELEMTHERMI_H + + +/// @addtogroup groupe_des_elements_finis +/// @{ +/// + +// cas d'une erreur survenue à cause d'un jacobien négatif + +class ErrJacobienNegatif_ElemThermi {}; + /// @} // end of group + + +/// @addtogroup groupe_des_elements_finis +/// @{ +/// + +// cas d'une erreur survenue à cause d'une variation de jacobien trop grande + +class ErrVarJacobienMini_ElemThermi {}; +/// @} // end of group + +#endif diff --git a/Elements/Thermique/LesPtIntegThermiInterne.cc b/Elements/Thermique/LesPtIntegThermiInterne.cc new file mode 100755 index 0000000..b60c3dc --- /dev/null +++ b/Elements/Thermique/LesPtIntegThermiInterne.cc @@ -0,0 +1,243 @@ +// 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 "LesPtIntegThermiInterne.h" + + +// contructeur par défaut +LesPtIntegThermiInterne::LesPtIntegThermiInterne(): + tabPtInt(),tabfluxH(),tabfluxH_t() + {}; + +// contructeur fonction du nombre de points d'intégration et de la dimension de tenseurs +LesPtIntegThermiInterne::LesPtIntegThermiInterne(int nbpti, int dimtens): + tabPtInt(nbpti,PtIntegThermiInterne(dimtens)),tabfluxH(nbpti),tabfluxH_t(nbpti) + { // on relie les tableaux entre eux + for (int i=1; i<= nbpti; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + }; + +// contructeur de copie +LesPtIntegThermiInterne::LesPtIntegThermiInterne(const LesPtIntegThermiInterne& lespti): + tabPtInt(lespti.tabPtInt),tabfluxH(lespti.tabfluxH.Taille()) + ,tabfluxH_t(lespti.tabfluxH_t.Taille()) + { // on relie les tableaux entre eux + int nbpti = tabPtInt.Taille(); + for (int i=1; i<= nbpti; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + }; + +// DESTRUCTEUR : +// normalement il n'y a rien n'a faire car les pointeurs sont des copies +LesPtIntegThermiInterne::~LesPtIntegThermiInterne() +{ }; + +// Surcharge de l'operateur = +LesPtIntegThermiInterne& LesPtIntegThermiInterne::operator= ( const LesPtIntegThermiInterne& lespti) +{ int newTaille = lespti.NbPti(); + tabPtInt = lespti.tabPtInt; + tabfluxH.Change_taille(newTaille); + tabfluxH_t.Change_taille(newTaille); + // on relie les tableaux entre eux + int nbpti = tabPtInt.Taille(); + for (int i=1; i<= nbpti; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + // retour + return *this; +}; + +// changement de taille donc de nombre de points d'intégration +// fonction du nombre de points d'intégration et de la dimension de tenseurs +// attention: il s'agit d'un dimentionnement pas défaut (les activations diverses +// sont ensuite à faire: par exemple pour les invariants) +void LesPtIntegThermiInterne::Change_taille_PtIntegThermi(int nbpti, int dimtens) + { // tout d'abord on adapte la taille + tabPtInt.Change_taille(nbpti,PtIntegThermiInterne(dimtens)); + tabfluxH.Change_taille(nbpti); + tabfluxH_t.Change_taille(nbpti); + // on relie les tableaux entre eux + for (int i=1; i<= nbpti; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + }; +// idem, mais les instances ajoutées ou retirer ont la même dimension de tenseur que celles +// qui existent déjà +void LesPtIntegThermiInterne::Change_taille_PtIntegThermi(int nbpti) + { // tout d'abord on adapte la taille + tabPtInt.Change_taille(nbpti); + tabfluxH.Change_taille(nbpti); + tabfluxH_t.Change_taille(nbpti); + // on relie les tableaux entre eux + for (int i=1; i<= nbpti; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + }; + +// retour la dimension des coordonnées gérés +int LesPtIntegThermiInterne::DimCoord() const + {if (tabPtInt.Taille() != 0) + {return tabPtInt(1).GradTB().Dimension();} + else + {return 0;}; + }; + +//============= 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 LesPtIntegThermiInterne::Lecture_base_info (ifstream& ent,const int cas) + {switch (cas) + { case 1 : // ------- on récupère tout ------------------------- + { string nom; ent >> nom; // on ne vérifie pas le nom car on considère que + // ça a été écrit par le prog associé + int taille = 0; + ent >> nom >> taille; // lecture de la taille + tabPtInt.Change_taille(taille); + tabfluxH.Change_taille(taille); + tabfluxH_t.Change_taille(taille); + // lecture + for (int i=1;i<=taille;i++) + tabPtInt(i).Lecture_base_info (ent,cas); + // on relie les tableaux entre eux + for (int i=1; i<= taille; i++) + {tabfluxH(i)= &tabPtInt(i).FluxH(); + tabfluxH_t(i)= &tabPtInt(i).FluxH_t(); + }; + break; + } + case 2 : // ----------- lecture uniquement de se qui varie -------------------- + { string nom; ent >> nom; // on ne vérifie pas le nom car on considère que + // ça a été écrit par le prog associé + // lecture + int taille = tabPtInt.Taille(); + for (int i=1;i<=taille;i++) + tabPtInt(i).Lecture_base_info (ent,cas); + break; + } + default : + { cout << "\nErreur : valeur incorrecte du type de lecture !\n"; + cout << "LesPtIntegThermiInterne::Lecture_base_info(ifstream& ent,const " + << " 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 LesPtIntegThermiInterne::Ecriture_base_info(ofstream& sort,const int cas) + {switch (cas) + { case 1 : // ------- on sauvegarde tout ------------------------- + { sort << "\n grandeurs_aux_points_d_integration:" ; + int taille = tabPtInt.Taille(); + sort << " taille= " << taille << " " ; + for (int i=1;i<=taille;i++) + tabPtInt(i).Ecriture_base_info(sort,cas); + break; + } + case 2 : // ----------- sauvegarde uniquement de se qui varie -------------------- + { sort << "\n grandeurs_aux_points_d_integration:" ; + int taille = tabPtInt.Taille(); + for (int i=1;i<=taille;i++) + tabPtInt(i).Ecriture_base_info(sort,cas); + break; + } + default : + { cout << "\nErreur : valeur incorrecte du type d'écriture !\n"; + cout << "LesPtIntegThermiInterne::Ecriture_base_info(ofstream& sort,const int cas)" + << " cas= " << cas << endl; + Sortie(1); + } + } + }; + +// actualisation des grandeurs actives de t+dt vers t, pour celles qui existent +// sous ces deux formes +void LesPtIntegThermiInterne::TdtversT() + { int taille = tabPtInt.Taille(); + for (int i=1;i<=taille;i++) + tabPtInt(i).TdtversT(); + }; + +// actualisation des grandeurs actives de t vers tdt, pour celles qui existent +// sous ces deux formes +void LesPtIntegThermiInterne::TversTdt() + { int taille = tabPtInt.Taille(); + for (int i=1;i<=taille;i++) + tabPtInt(i).TversTdt(); + }; + + +// surcharge de l'operateur de lecture +istream & operator >> (istream & entree, LesPtIntegThermiInterne & lespti) + { // vérification du type + string nom; + entree >> nom; + #ifdef MISE_AU_POINT + if (nom != "LesPtIntegThermiInterne") + { cout << "\nErreur, en lecture d'une instance LesPtIntegThermiInterne " + << " on attendait LesPtIntegThermiInterne et on a lue: " << nom ; + cout << "istream & operator >> (istream & entree, LesPtIntegThermiInterne & pti)\n"; + Sortie(1); + }; + #endif + // puis lecture des différents éléments + lespti.tabPtInt.Entree(entree); + // on s'occupe des pointeurs + int nbpti = lespti.tabPtInt.Taille(); + lespti.tabfluxH.Change_taille(nbpti); + lespti.tabfluxH_t.Change_taille(nbpti); + // on relie les tableaux entre eux + for (int i=1; i<= nbpti; i++) + {lespti.tabfluxH(i)= &lespti.tabPtInt(i).FluxH(); + lespti.tabfluxH_t(i)= &lespti.tabPtInt(i).FluxH_t(); + }; + return entree; + }; + +// surcharge de l'operateur d'ecriture +ostream & operator << ( ostream & sort,const LesPtIntegThermiInterne & lespti) + { // tout d'abord un indicateur donnant le type + sort << "LesPtIntegThermiInterne " ; + // puis les différents éléments (pas les pointeurs qui n'ont aucun intérêt ici) + lespti.tabPtInt.Sortir(sort); + return sort; + }; + + + + + diff --git a/Elements/Thermique/LesPtIntegThermiInterne.h b/Elements/Thermique/LesPtIntegThermiInterne.h new file mode 100755 index 0000000..d1647aa --- /dev/null +++ b/Elements/Thermique/LesPtIntegThermiInterne.h @@ -0,0 +1,134 @@ +// 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: Classe pour stocker l'ensemble des informations aux points * + * d'intégration thermique * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * + * VERIFICATION: * + * * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * ! ! ! ! * + * $ * + * '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' * + * MODIFICATIONS: * + * ! date ! auteur ! but ! * + * ------------------------------------------------------------ * + * $ * + ************************************************************************/ +#ifndef LESPTINTEGTHERMIINTERNE_H +#define LESPTINTEGTHERMIINTERNE_H + +#include "PtIntegThermiInterne.h" + +/// @addtogroup Groupe_concernant_les_points_integration +/// @{ +/// + + +class LesPtIntegThermiInterne + +{ // surcharge de l'operator de lecture + friend istream & operator >> (istream &, LesPtIntegThermiInterne &); + // surcharge de l'operator d'ecriture + friend ostream & operator << (ostream &, const LesPtIntegThermiInterne &); + + public : + // CONSTRUCTEURS : + // contructeur par défaut + LesPtIntegThermiInterne(); + // contructeur fonction du nombre de points d'intégration et de la dimension des coordonnees + LesPtIntegThermiInterne(int nbpti, int dimcoor); + // contructeur de copie + LesPtIntegThermiInterne(const LesPtIntegThermiInterne& lespti); + + // DESTRUCTEUR : + ~LesPtIntegThermiInterne(); + + // METHODES PUBLIQUES : + // Surcharge de l'operateur = + LesPtIntegThermiInterne& operator= ( const LesPtIntegThermiInterne& lespti); + + // le tableau des grandeurs aux points d'intégration + // en lecture écriture + Tableau & TabPtIntThermi() {return tabPtInt;}; + // l'élément PtIntegThermiInterne de numéro i + PtIntegThermiInterne& operator () (int i) {return tabPtInt(i);}; + + + // les tableaux des densité de flux + Tableau & TabfluxH() {return tabfluxH;}; // densité flux finale + Tableau & TabfluxH_t() {return tabfluxH_t;}; // densité flux au début de l'incrément + // nombre de points d'intégration + int NbPti() const {return tabPtInt.Taille();}; + // changement de taille donc de nombre de points d'intégration + // fonction du nombre de points d'intégration et de la dimension des coordonnees + void Change_taille_PtIntegThermi(int nbpti, int dimtens); + // idem, mais les instances ajoutées ou retirer ont la même dimension de coordonnees que celles + // qui existent déjà + void Change_taille_PtIntegThermi(int nbpti); + // retour la dimension des vecteurs gérés + int DimCoord() const; + // actualisation des grandeurs actives de t+dt vers t, pour celles qui existent + // sous ces deux formes + void TdtversT(); + // actualisation des grandeurs actives de t vers tdt, pour celles qui existent + // sous ces deux formes + void TversTdt(); + + //============= 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 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); + + protected: + // données protégées + // grandeurs aux points d'intégration + Tableau tabPtInt; + // densité de flux groupées sous forme de tableau, qui pointent sur celles de tabPtThermiInt + Tableau tabfluxH; // densité flux finale + Tableau tabfluxH_t; // densité flux au début de l'incrément + + }; + /// @} // end of group + +#endif