// FICHIER : Element.cc // CLASSE : Element // 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 using namespace std; //introduces namespace std #include "Element.h" #include "ConstMath.h" #include "Util.h" #include "TypeQuelconqueParticulier.h" //---------------------------------------------------------------- // def des donnees commune a tous les elements ( membre static) //---------------------------------------------------------------- list Element::listTypeElement; // constantes générales qui permettent d'éviter d'utiliser des chiffres dans les classes // dérivées ceci pour plus de lisibilité et de sureté const double Element::epaisseur_defaut = -1. + sqrt(2.)/1000.; // épaisseur par défaut const double Element::largeur_defaut = -1. + sqrt(2.)/1001.; // largeur par défaut const double Element::section_defaut = -1. + sqrt(2.)/1002.; // section par défaut const double Element::masse_volumique_defaut = -1. + sqrt(2.)/1003.; // masse_volumique par défaut // variable de travail pour la fonction Choix_element bool Element::premier_passage_Choix_element=true; //-------------------------------------------------------------------------------------- // def des class internes et fonctions pour les classes internes //-------------------------------------------------------------------------------------- // constructeur par défaut Element::NouvelleTypeElement::NouvelleTypeElement() : id_geom(RIEN_GEOM),id_interpol(RIEN_INTERPOL) ,id_typeProblem(MECA_SOLIDE_DEFORMABLE),infos_annexes(""),el(NULL) {}; // constructeur normal Element::NouvelleTypeElement::NouvelleTypeElement(const Enum_geom id_g,const Enum_interpol id_in , const EnumElemTypeProblem id_type ,ConstrucElement * eli ,string discri ) : id_geom(id_g),id_interpol(id_in) ,id_typeProblem(id_type),infos_annexes(discri),el(eli) {}; // constructeur de copie Element::NouvelleTypeElement::NouvelleTypeElement(const NouvelleTypeElement& nvel) : id_geom(nvel.id_geom),id_interpol(nvel.id_interpol) ,id_typeProblem(nvel.id_typeProblem),infos_annexes(nvel.infos_annexes),el(nvel.el) {}; // opérateur d'assigment Element::NouvelleTypeElement& Element::NouvelleTypeElement::operator= (const Element::NouvelleTypeElement& nvel) { id_geom=nvel.id_geom;id_interpol=nvel.id_interpol; id_typeProblem=nvel.id_typeProblem;infos_annexes=nvel.infos_annexes;el=nvel.el; return (*this); }; // opérateur tests bool Element::NouvelleTypeElement::operator == (const Element::NouvelleTypeElement& nvel) { if ( (id_geom==nvel.id_geom)&&(id_interpol==nvel.id_interpol) &&(id_typeProblem==nvel.id_typeProblem)&&(infos_annexes==nvel.infos_annexes) &&(el==nvel.el)) return true; else return false; }; bool Element::NouvelleTypeElement::operator != (const Element::NouvelleTypeElement& elt) { if (*this == elt) return true; else return false; }; // retourne vraie si *this est le meme type d'élément que elt bool Element::NouvelleTypeElement::MemeTypeElement(const Element::NouvelleTypeElement& nvel) { if ( (id_geom==nvel.id_geom)&&(id_interpol==nvel.id_interpol) &&(id_typeProblem==nvel.id_typeProblem)&&(infos_annexes==nvel.infos_annexes)) return true; else return false; }; // surcharge de l'operateur d'ecriture pour les éléments de la classe signature ostream & operator << ( ostream & sort,const Element::Signature & signature) { // sortie sort << "element_finis_de_signature: " << NomElemTypeProblem(signature.id_problem) << " " << Nom_geom(signature.id_geom) << " " << Nom_interpol(signature.id_interpol) << " " << signature.infos_annexes; return sort; }; // surcharge de l'affectation Element::Signature& Element::Signature::operator = ( const Element::Signature& a) { id_interpol = a.id_interpol; id_geom = a.id_geom; id_problem = a.id_problem; infos_annexes = a.infos_annexes; return *this; }; // surcharge de l'égalité bool Element::Signature::operator == (const Element::Signature& a) { if ( (id_interpol==a.id_interpol) && (id_geom == a.id_geom) && (id_problem == a.id_problem) && (infos_annexes == a.infos_annexes)) return true; else return false; }; // surcharge de non égalité bool Element::Signature::operator != (const Element::Signature& a) { return !(*this == a);}; //-------------------------------------------------------------- //-- les constructeurs -- //-------------------------------------------------------------- Element::Element (int num_maill,int num_id) : // Constructeur utile quand le numero de maillage et d'identification de l'element est connu tab_noeud(),residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),num_maillage(0),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { num_maillage=num_maill; num_elt=num_id; id_interpol=RIEN_INTERPOL; id_geom=RIEN_GEOM; id_problem = RIEN_PROBLEM; infos_annexes = ""; }; Element::Element (int num_maill,int num_id,const Tableau& tab): // Constructeur utile quand le numero de maillage et de l'élément, et le tableau des noeuds // de l'element sont connu tab_noeud(tab),residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { num_maillage=num_maill; num_elt=num_id; id_interpol=RIEN_INTERPOL; id_geom=RIEN_GEOM; id_problem = RIEN_PROBLEM; infos_annexes = ""; }; // Constructeur utile quand le numero du maillage et d'identification est connu, // ainsi que la geometrie le type d'interpolation le problème traité de l'element // et éventuellement un string d'information annexe Element::Element (int num_maill,int num_id,Enum_interpol id_interp_elt,Enum_geom id_geom_elt, EnumElemTypeProblem id_prob,string info): num_maillage(num_maill),num_elt(num_id),id_interpol(id_interp_elt),id_geom(id_geom_elt) ,id_problem(id_prob),infos_annexes(info),tab_noeud() ,residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { }; // Constructeur fonction d'un numéro de maillage, d'un numero et de deux noms (geometrie, interpolation) //et le type de problème traité par l'element Element::Element (int num_maill,int num_id,const string& nom_interpol,const string& nom_geom, const string& nom_prob,string info): num_maillage(num_maill),num_elt(num_id),infos_annexes(info),tab_noeud() ,residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { id_interpol=Id_nom_interpol(nom_interpol); id_geom=Id_nom_geom(nom_geom); id_problem=Id_nom_ElemTypeProblem(nom_prob); }; // Constructeur fonction d'un numéro de maillage, d'un numero, du tableau de connexite des noeuds et de // trois identificateurs et un nom (geometrie, interpolation, type de probleme, // particularité éventuelle), // et du type de problème traité par l'element Element::Element (int num_maill,int num_id,const Tableau& tab,Enum_interpol id_interp_elt, Enum_geom id_geom_elt,EnumElemTypeProblem id_prob,string info): num_maillage(num_maill),num_elt(num_id),id_interpol(id_interp_elt),id_geom(id_geom_elt) ,id_problem(id_prob),infos_annexes(info),tab_noeud(tab) ,residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { }; // Constructeur fonction d'un numéro de maillage, d'un numero, du tableau de connexite des noeuds, de // quatre noms (geometrie, interpolation, type de probleme, particularité éventuelle), // et du type de problème traité par l'element Element::Element (int num_maill,int num_id,const Tableau& tab,const string& nom_interpol, const string& nom_geom,const string& nom_prob,string info): num_maillage(num_maill),num_elt(num_id),infos_annexes(info),tab_noeud(tab) ,residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(0.),volumePlan(ParaGlob::Dimension()) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(),prepa_niveau_precision(0) ,sens_numerotation(1) { id_interpol=Id_nom_interpol(nom_interpol); id_geom=Id_nom_geom(nom_geom); id_problem=Id_nom_ElemTypeProblem(nom_prob); }; // Constructeur de copie Element::Element (const Element& elt): num_maillage(elt.num_maillage),num_elt(elt.num_elt),id_interpol(elt.id_interpol) ,id_geom(elt.id_geom),id_problem(elt.id_problem),infos_annexes(elt.infos_annexes) ,tab_noeud(elt.tab_noeud) ,residu(NULL),raideur(NULL),res_extA(NULL),raid_extA(NULL) ,res_extS(NULL),raid_extS(NULL),mat_masse(NULL) ,volume(elt.volume),volumePlan(elt.volumePlan) ,integ_vol_typeQuel(NULL),integ_vol_typeQuel_t(NULL),index_Integ_vol_typeQuel(NULL) ,integ_vol_t_typeQuel(NULL),integ_vol_t_typeQuel_t(NULL),index_Integ_vol_t_typeQuel(NULL) ,enu_integ_vol_TQ(NULL),enu_integ_vol_t_TQ(NULL) ,tabb(),ind_front_lin(0),ind_front_surf(0),posi_tab_front_lin(0) ,ind_front_point(0),posi_tab_front_point(0) ,boite_encombre(elt.boite_encombre),prepa_niveau_precision(elt.prepa_niveau_precision) ,sens_numerotation(elt.sens_numerotation) // on ne recopie pas les adresses pointees car celles-ci peuvent changer, donc il vaut mieux // les reconstruire si besoin est {if (elt.integ_vol_typeQuel != NULL) {integ_vol_typeQuel = new Tableau (*(elt.integ_vol_typeQuel));}; if (elt.integ_vol_typeQuel_t != NULL) {integ_vol_typeQuel_t = new Tableau (*(elt.integ_vol_typeQuel_t));}; if (elt.index_Integ_vol_typeQuel != NULL) {index_Integ_vol_typeQuel = new Tableau (*(elt.index_Integ_vol_typeQuel));} if (elt.integ_vol_t_typeQuel != NULL) {integ_vol_t_typeQuel = new Tableau (*(elt.integ_vol_t_typeQuel));}; if (elt.integ_vol_t_typeQuel_t != NULL) {integ_vol_t_typeQuel_t = new Tableau (*(elt.integ_vol_t_typeQuel_t));}; if (elt.index_Integ_vol_t_typeQuel != NULL) {index_Integ_vol_t_typeQuel = new Tableau (*(elt.index_Integ_vol_t_typeQuel));} if (elt.enu_integ_vol_TQ != NULL) {enu_integ_vol_TQ = new Tableau (*(elt.enu_integ_vol_TQ));}; if (elt.enu_integ_vol_t_TQ != NULL) {enu_integ_vol_t_TQ = new Tableau (*(elt.enu_integ_vol_t_TQ));} }; Element::~Element() // Destructeur { int dimtaille= tabb.Taille(); ////---- debug //if ((num_elt==1) && (num_maillage==1)) // cout << "\n debug Element::~Element () "<entree) >> num_elt >> id_geom >> id_interpol; };*/ // test si l'element est complet int Element::TestComplet() { int ret =1; if (tab_noeud.Taille() == 0) { cout << " \n *** Warning le tableau de noeud est vide dans l element " << num_elt << '\n'; // ret = 0; } if (num_elt == -3) { cout << " \n l'element n a pas de numero d'identification \n "; ret = 0; }; if (id_geom == RIEN_GEOM) { cout << " \n la geometrie de l'element n est pas defini\n "; ret = 0; }; if (id_interpol == RIEN_INTERPOL) { cout << " \n l interpolation sur l'element n est pas defini\n "; ret = 0; }; if (id_problem == RIEN_PROBLEM) { cout << " \n le type de probleme de l'element n est pas defini\n "; ret = 0; }; return ret; }; // Libere la place occupee par le residu et eventuellement la raideur void Element::Libere () { // if (residu != NULL) delete residu; // tous les résidus, raideurs et tableaux de // if (raideur != NULL) delete raideur;// pointent sur des données static }; // mise à jour éventuel de repère d'anisotropie void Element::Mise_a_jour_repere_anisotropie(BlocGen & bloc,LesFonctions_nD* lesFonctionsnD) { cout << "\n Erreur , methode actuellement non defini pour l'element \n"; cout << "\n Element::Mise_a_jour_repere_anisotropie(.. \n"; Sortie(1); }; // test si this et l'élément passé en paramètre sont identiques uniquement concernant la signature, la géométrie // et le maillage // par contre il peut y avoir des différences au niveau de la loi, de la matière etc. // ramène true s'il y a identité, false sinon bool Element::Meme_signature_et_geometrie(const Element& elem)const { // on continue que si les deux éléments ont la même signature if ((this->Signature_element() == elem.Signature_element()) && (num_maillage == elem.Num_maillage())) { int ta = tab_noeud.Taille(); // nb de noeud de this const Tableau& tab_noeu_ext = elem.Tab_noeud_const(); // pour simplifier switch (ta) { case 1 : // cas d'un élément point, on simplifie if (tab_noeud(1) == tab_noeu_ext(1)) {return true;} else {return false;} break; case 2 : // cas d'un élément à 2 noeuds uniquement {if (tab_noeud(1) == tab_noeu_ext(1)) {if (tab_noeud(2) == tab_noeu_ext(2)) {return true;} else {return false;}} else if (tab_noeud(1) == tab_noeu_ext(2)) {if (tab_noeud(2) == tab_noeu_ext(1)) {return true;} else {return false;}} else {return false;}; break; } default : // les autres cas {// récup de l'élément géométrique const ElemGeomC0 & elemgeom = this->ElementGeometrique(); const Tableau & ind = elemgeom.Ind(); // récup du tableau des tranches int nb_tranche = ind.Taille(); // le nombre d'intervalle de numéros de noeuds constituant la numérotation // vérification que la taille de toutes les tranches est au moins supérieure à 1 #ifdef MISE_AU_POINT if (nb_tranche == 0) {cout << "\n *** erreur, pas de tranche de nb de noeud definie " << "\n Element::Meme_signature_et_geometrie(... " << endl; Sortie(1); }; for (int i1=1;i1<=nb_tranche;i1++) if (ind(i1) < 1) {cout << "\n *** erreur, une tranche de nb de noeud est nulle " << " tableau ind: " << ind << "\n Element::Meme_signature_et_geometrie(... " << endl; Sortie(1); }; #endif // on balaie chaque intervalle int deb_intervalle = 0; int fin_intervalle = 0; // init for (int iter =1;iter<= nb_tranche;iter++) { int tranche = ind(iter); deb_intervalle = fin_intervalle+1; // mise à jour des bornes de l'intervalle de scrutation fin_intervalle += tranche; // " " // on commence par chercher un premier noeud identique dans l'intervalle bool res = false; int nd; // indice du cote this Noeud * ptNoeud_a = tab_noeu_ext(deb_intervalle); for (nd=deb_intervalle; nd<= fin_intervalle; nd++) {if (tab_noeud(nd) == ptNoeud_a) { res = true; break; }; }; if (!res) // on arrête de suite si {return false;}; // on n'a pas trouvé de premier noeud !! // s'il n'y a qu'un seule noeud dans la tranche, on a finit cette tranche sinon on continue if (tranche > 1) { // on regarde dans quel sens il faut tourner int ndplus = nd + 1; if (ndplus > fin_intervalle) ndplus -= tranche; int ndmoins = nd - 1; if (ndmoins < deb_intervalle) ndmoins += tranche; if (tab_noeud(ndplus) == tab_noeu_ext(deb_intervalle+1)) {// on est dans le bon sens en augmentant, et c'est ok pour le 2ième noeud, // continue que s'il y a plus de 2 noeuds dans la tranche if (tranche > 2) { for (int i=1;i<= (tranche-2);i++) { ndplus++; if (ndplus > fin_intervalle) ndplus -= tranche; if (tab_noeud(ndplus) != tab_noeu_ext(deb_intervalle+i+1)) return false; }; }; // sinon ok, on vient de balayer tous les noeuds, on continue } // le sens 1 ne marche pas , on regarde l'autre sens else if (tab_noeud(ndmoins) == tab_noeu_ext(deb_intervalle+1)) {// le bon sens est finalement en diminuant // continue que s'il y a plus de 2 noeuds dans la tranche if (tranche > 2) { for (int i=1;i<= (tranche-2);i++) { ndmoins--; if (ndmoins < deb_intervalle) ndmoins += tranche; if (tab_noeud(ndmoins) != tab_noeu_ext(deb_intervalle+i+1)) return false; }; }; // sinon ok, on vient de balayer tous les noeuds, on continue } else // sinon ne marche pas dans les deux sens { return false;}; }; }; // fin de la boucle sur les tranches }; // fin du cas courant (default du switch) }; // fin du switch sur le nombre de noeuds } else // le type est different et ou le numéro de maillage est différent {return false;}; // si on arrive ici, cela veut dire que toutes les égalités sont bonnes pour un cas autre que // point ou élément à 2 noeuds return true; }; //------- calcul d'erreur, remontée des contraintes ------------------- // calcul du résidu et de la matrice de raideur pour le calcul d'erreur // pour l'instant uniquement virtuel, par la suite devra être virtuelle pure //1) remontée aux contraintes Element::Er_ResRaid Element::ContrainteAuNoeud_ResRaid() { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : ContrainteAuNoeud_ResRaid() \n"; Sortie(1); return Element::Er_ResRaid(); }; // 2) remontée aux erreurs aux noeuds Element::Er_ResRaid Element::ErreurAuNoeud_ResRaid() { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : ErreurAuNoeud_ResRaid() \n"; Sortie(1); return Element::Er_ResRaid(); }; // suppression d'un élément frontière void Element::SupprimeFront(ElFrontiere* elemFront) { // on commence par mettre à jour les répercussions de la // suppression sur les classes dérivées Prise_en_compte_des_consequences_suppression_une_frontiere(elemFront); // puis suppression dans les tableaux gérés par Element int taille = tabb.Taille(); for (int i=1; i<=taille; i++) if (tabb(i) == elemFront) { delete tabb(i); tabb(i) = NULL; // puis gestion des indicateurs if ((ind_front_point != 0) && (i>posi_tab_front_point)) // cas d'une frontière point ind_front_point = 2; else if ((ind_front_lin != 0) && (i> posi_tab_front_lin)) // cas d'une frontière linéique ind_front_lin = 2; else if (ind_front_surf != 0) // cas d'une frontière surfacique ind_front_surf = 2; else { cout << "\n erreur l'élément frontière n'est pas correcte " << "\n Element::SupprimeFront(ElFrontiere* elemFront)"; Sortie(1); } break; }; }; // suppression de tous les éléments frontières void Element::SupprimeFront() { // on commence par mettre à jour les répercussions de la // suppression sur les classes dérivées Prise_en_compte_des_consequences_suppression_tous_frontieres(); // puis suppression dans les tableaux gérés par Element int taille = tabb.Taille(); for (int i=1; i<=taille; i++) { delete tabb(i); tabb(i) = NULL; }; ind_front_surf = 0; ind_front_lin = 0; ind_front_point = 0; }; // 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() const DeuxCoordonnees& Element::Boite_encombre_element(Enum_dure temps) { int tab_taille= tab_noeud.Taille(); Coordonnee& encomb_min_e=boite_encombre.Premier(); Coordonnee& encomb_max_e=boite_encombre.Second(); switch (temps) { case TEMPS_0: {encomb_min_e=tab_noeud(1)->Coord0();encomb_max_e=encomb_min_e; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab_noeud(i)->Coord0(); encomb_min_e.Modif_en_min(co); encomb_max_e.Modif_en_max(co); }; break; } case TEMPS_t: {encomb_min_e=tab_noeud(1)->Coord1();encomb_max_e=encomb_min_e; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab_noeud(i)->Coord1(); encomb_min_e.Modif_en_min(co); encomb_max_e.Modif_en_max(co); }; break; } case TEMPS_tdt: {encomb_min_e=tab_noeud(1)->Coord2();encomb_max_e=encomb_min_e; // init for (int i=2;i<=tab_taille;i++) // balayage des autres noeuds { Coordonnee co=tab_noeud(i)->Coord2(); encomb_min_e.Modif_en_min(co); encomb_max_e.Modif_en_max(co); }; break; } }; // fin du switch // maintenant on tiend compte d'un facteur majorant pour incertitude Coordonnee delta=(encomb_max_e- encomb_min_e) * (ParaGlob::param->ParaAlgoControleActifs().Extra_boite_prelocalisation()-1.); // ajout d'un extra dans toutes les directions delta.Ajout_meme_valeur(ParaGlob::param->ParaAlgoControleActifs().Ajout_extra_boite_prelocalisation()); // mise à jour encomb_min_e -= delta; encomb_max_e += delta; // retour return boite_encombre; }; // test si le point passé en argument appartient à la boite d'encombrement de l'élément // tous les points sont supposées avoir la même dimension // si depass est différent de 0, les maxi et mini de la boite sont augmentés de "depass" bool Element::In_boite_emcombrement_elem(const Coordonnee& M,double depass) const { // on va essayer de faire efficace, pour cela on test le minimum const Coordonnee& co_min = boite_encombre.Premier(); // par commodité const Coordonnee& co_max = boite_encombre.Second(); // par commodité #ifdef MISE_AU_POINT if ((M.Dimension() != ParaGlob::Dimension())|| (M.Dimension() != co_min.Dimension())) { cout << "\n *** pb de dimensions non coherente !! " << "\n Element::In_boite_emcombrement_elem(..."; Sortie(1); }; #endif //debug //cout << "\n M= " << M << " co_min= " << co_min << " co_max= " << co_max << endl; //fin debug if (depass == 0.) {switch (ParaGlob::Dimension()) { case 3: if ((M(3) co_max(3))) return false; case 2: if ((M(2) co_max(2))) return false; case 1: if ((M(1) co_max(1))) return false; }; } else // cas ou il faut rajouter depass {depass = Dabs(depass); switch (ParaGlob::Dimension()) { case 3: if ((M(3)<(co_min(3)-depass)) || (M(3) > (co_max(3)+depass))) return false; case 2: if ((M(2)<(co_min(2)-depass)) || (M(2) > (co_max(2)+depass))) return false; case 1: if ((M(1)<(co_min(1)-depass)) || (M(1) > (co_max(1)+depass))) return false; }; }; // si on arrive ici c'est que le point est interne return true; }; void Element::Affiche (int n) const // Affiche les donnees liees a un element { // n indique un niveau d'impression if((n < 1) || (n > 4)) { cout << "\n il faut un chiffre entre 1 et 4 ! \n"; cout << " Element::Affiche (int n), n = " << n << '\n'; return; } switch (n) { case 4 : // + la raideur et la matrice de masse si elle existe { if ( raideur == NULL ) {cout << "\n ** pas encore de raideur \n";} else {cout << "\t raideur : \n"; cout << "nombre de ligne : " << (*raideur).Nb_ligne() << " .\n"; cout << "nombre de colonne : " << (*raideur).Nb_colonne() << " .\n"; cout << "Composante(s) :\n "; for (int i=1;i<= (*raideur).Nb_ligne();i++) { cout << "\t[ "; for (int j=1; j<= (*raideur).Nb_colonne(); j++) cout << (*raideur)(i,j) << " "; cout << "]\n\n"; }; }; if ( mat_masse == NULL ) {cout << "\n ** pas de matrice masse \n";} else {cout << "\t matrice_masse : \n"; cout << "nombre de ligne : " << (*mat_masse).Nb_ligne() << " .\n"; cout << "nombre de colonne : " << (*mat_masse).Nb_colonne() << " .\n"; cout << "Composante(s) :\n "; for (int i=1;i<= (*mat_masse).Nb_ligne();i++) { cout << "\t[ "; for (int j=1; j<= (*mat_masse).Nb_colonne(); j++) cout << (*mat_masse)(i,j) << " "; cout << "]\n\n"; }; }; } case 3 : // + le residu {if ( residu == NULL ) {cout << "\n ** pas encore de residu \n";} else {cout << "\t residu : \n"; cout << "Taille du residu : " << (*residu).Taille() << " .\n"; cout << "Composante(s) :\n\t[ "; for (int i=1;i<= (*residu).Taille();i++) cout << (*residu)(i) << " "; cout << "]\n\n"; }; } case 2 : // + tableau de noeuds {cout << "\tNoeuds de l'element : \n"; cout << "Taille du tableau : " << tab_noeud.Taille() << " .\n"; cout << "Composante(s) :\n\t[ "; for (int i=1;i<=tab_noeud.Taille();i++) cout << Num_noeud(i) << " "; cout << "]\n\n"; } case 1 : // donnees d'en-tete {cout << "\tNumero d'identification de l'element : "; if (num_elt > 1000000) { cout << " interne Hourglass \n"; } else { cout << num_elt << "\n"; }; cout << "\tType de geometrie : " << Nom_geom(id_geom) << "\n"; cout << "\tType d'interpolation : " << Nom_interpol(id_interpol) << "\n"; cout << "\tType de problem : " << NomElemTypeProblem(id_problem) << "\n"; if (infos_annexes != "") cout << "particularité: " << infos_annexes; } }; }; Element& Element::operator= (Element& elt) // Surcharge de l'operateur = : realise l'egalite de deux elements {num_elt=elt.num_elt; tab_noeud=elt.tab_noeud; id_interpol=elt.id_interpol; id_geom=elt.id_geom; id_problem=elt.id_problem; infos_annexes=elt.infos_annexes; //*residu = *elt.residu; // tous les résidus, raideurs et tableaux de //*raideur = *elt.raideur;// pointent sur des données static volume = elt.volume; volumePlan = elt.volumePlan; // ---- cas des intégrales ---- if (elt.integ_vol_typeQuel != NULL) {if (integ_vol_typeQuel == NULL) {integ_vol_typeQuel = new Tableau (*(elt.integ_vol_typeQuel));} else {(*integ_vol_typeQuel) = (*elt.integ_vol_typeQuel);}; } else {if (integ_vol_typeQuel != NULL) delete integ_vol_typeQuel;}; if (elt.integ_vol_typeQuel_t != NULL) {if (integ_vol_typeQuel_t == NULL) {integ_vol_typeQuel_t = new Tableau (*(elt.integ_vol_typeQuel_t));} else {(*integ_vol_typeQuel_t) = (*elt.integ_vol_typeQuel_t);}; } else {if (integ_vol_typeQuel_t != NULL) delete integ_vol_typeQuel_t;}; if (elt.integ_vol_t_typeQuel != NULL) {if (integ_vol_t_typeQuel == NULL) {integ_vol_t_typeQuel = new Tableau (*(elt.integ_vol_t_typeQuel));} else {(*integ_vol_t_typeQuel) = (*elt.integ_vol_t_typeQuel);}; } else {if (integ_vol_t_typeQuel != NULL) delete integ_vol_t_typeQuel;}; if (elt.integ_vol_t_typeQuel_t != NULL) {if (integ_vol_t_typeQuel_t == NULL) {integ_vol_t_typeQuel_t = new Tableau (*(elt.integ_vol_t_typeQuel_t));} else {(*integ_vol_t_typeQuel_t) = (*elt.integ_vol_t_typeQuel_t);}; } else {if (integ_vol_t_typeQuel_t != NULL) delete integ_vol_t_typeQuel_t;}; if (elt.index_Integ_vol_typeQuel != NULL) {if (index_Integ_vol_typeQuel == NULL) {index_Integ_vol_typeQuel = new Tableau (*(elt.index_Integ_vol_typeQuel));} else {(*index_Integ_vol_typeQuel) = (*elt.index_Integ_vol_typeQuel);}; } else {if (index_Integ_vol_typeQuel != NULL) delete index_Integ_vol_typeQuel;}; if (elt.index_Integ_vol_t_typeQuel != NULL) {if (index_Integ_vol_t_typeQuel == NULL) {index_Integ_vol_t_typeQuel = new Tableau (*(elt.index_Integ_vol_t_typeQuel));} else {(*index_Integ_vol_t_typeQuel) = (*elt.index_Integ_vol_t_typeQuel);}; } else {if (index_Integ_vol_t_typeQuel != NULL) delete index_Integ_vol_t_typeQuel;}; if (elt.enu_integ_vol_TQ != NULL) {if (enu_integ_vol_TQ == NULL) {enu_integ_vol_TQ = new Tableau (*(elt.enu_integ_vol_TQ));} else {(*enu_integ_vol_TQ) = (*elt.enu_integ_vol_TQ);}; } else {if (enu_integ_vol_TQ != NULL) delete enu_integ_vol_TQ;}; if (elt.enu_integ_vol_t_TQ != NULL) {if (enu_integ_vol_t_TQ == NULL) {enu_integ_vol_t_TQ = new Tableau (*(elt.enu_integ_vol_t_TQ));} else {(*enu_integ_vol_t_TQ) = (*elt.enu_integ_vol_t_TQ);}; } else {if (enu_integ_vol_t_TQ != NULL) delete enu_integ_vol_t_TQ;}; //--------- fin intégrale // tabb = elt.tabb; // non ça c'est une erreur car on fait une recopie de frontière et // pas de création int dim_tabb_new = elt.tabb.Taille(); // on commence par supprimer le tableau actuel, car les nouvelles frontières peuvent // être complètement différentes des anciennes Element::SupprimeFront(); // maintenant on affecte tabb.Change_taille(dim_tabb_new); for (int i=1;i<=dim_tabb_new;i++) if (elt.tabb(i) != NULL) tabb(i) = elt.tabb(i)->NevezElemFront(); // maintenant les indicateurs ind_front_lin = elt.ind_front_lin; ind_front_surf = elt.ind_front_surf; ind_front_point = elt.ind_front_point; posi_tab_front_lin = elt.posi_tab_front_lin; posi_tab_front_point = elt.posi_tab_front_point; boite_encombre = elt.boite_encombre; prepa_niveau_precision = elt.prepa_niveau_precision; sens_numerotation = elt.sens_numerotation; return (*this); }; // calcul d'une longueur géométrique mini représentative de l'élément // cas = 1: correspond à la distance mini entre deux noeuds coins de l'élément // cas = 2: dans le cas 1D -> distance mini entre noeuds extrèmes // en 2D: quadrangle: racine carré de la surface; triangle: racine carré de 2*surface // en 3D: hexa: racine cubique de vol; penta: racine cub de 2*vol, tétra: racine cub 6*vol // cas = 3: 1D idem cas 2, 2D: distance mini noeud arrête opposée, 3D: distance mini noeud face opposé double Element::LongueurGeometrique(int cas) const { double longueur=0.; // valeur de retour switch (cas) { case 1: { int nbne = tab_noeud.Taille(); // récup du nombre de noeud //cout << "\n nbne=" << nbne; // 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; if (tab_noeud(1)->ExisteCoord1()) {// cas où les coordonnées à t sont définit for (int i=1;i<= nbne;i++) // on itère sur les noeuds restants for (int j=i+1;j<= nbne;j++) { double dist_new = (tab_noeud(i)->Coord1() - tab_noeud(j)->Coord1()).Norme(); //cout << " dist_new= " << dist_new; if (dist_new < dist) dist = dist_new; } } else {// cas où seules les coordonnées à 0 sont définit for (int i=1;i<= nbne;i++) // on itère sur les noeuds restants 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; } } // traitement d'une erreur éventuelle if (dist <= ConstMath::petit) { cout << "\n **** ERREUR une longueur d'arrête de l'element est nulle" << "\n Element::LongueurGeometrique(int cas)" << "\n element: "; this->Affiche(1); #ifdef MISE_AU_POINT cout << "\n *** version mise au point: on continue neanmoins avec une longueur " << " arbitrairement tres petite (" < 8) cout << " Coordonnee & Element::VolumePlan() "; // cout << endl; }; #endif volumePlan.Change_dim(0); return volumePlan; }; // --- maintenant on est dans le cas d'un élément 2D et le calcul est en 3D // on récupère l'élément géométrique ElemGeomC0& elgeo = this->ElementGeometrique(); // on récupère la triangulation const Tableau > >& triaLinGlob = elgeo.Trian_lin(); // comme on a un élément surface, il n'y a qu'une face pour l'élément, on simplifie const Tableau > & triaLin = triaLinGlob(1); // on boucle sur les triangles int nbtriang = triaLin.Taille(); volumePlan.Zero(); for (int i=1;i<=nbtriang;i++) { const Tableau & tabNG = triaLin(i); // pour simplifier const Coordonnee& A = tab_noeud(tabNG(1))->Coord2(); const Coordonnee& B = tab_noeud(tabNG(2))->Coord2(); const Coordonnee& C = tab_noeud(tabNG(3))->Coord2(); Coordonnee AB(B-A); Coordonnee AC(C-A); Coordonnee G=1./3.*(A+B+C); // coordonnées du centre de gravité Coordonnee so=0.5*Util::ProdVec_coor(AB,AC); so(1) *=G(1);so(2) *=G(2);so(3) *=G(3); volumePlan += so; }; // retour return volumePlan; }; // vérification de l'existence d'un point d'intégration correspondant à un ddl bool Element::Existe_pt_integ (int nbptinteg, Enum_ddl enu) const { // récup de l'élement géométrique de l'élément const ElemGeomC0& elemgeo = this->ElementGeometrie(enu); // vérif du numéro de pt d'integ if ((nbptinteg <= 0) || (nbptinteg > elemgeo.Nbi())) return false; else return true; }; // avec la méthode Frontiere() on obtient un tableau de frontières tabb(i) , qui peut contenir des points, lignes ou surfaces // la méthode qun peu redondante, mais pratique, qui ramène le numéro local "n" de frontière dans le type en fonction du numéro global "i" // d'une manière générale supposons que tabb contient des lignes, points et surfaces, alors: // si tabb(i) est une surface, Num_de_frontiere_dans_le_type(i) donnera le numéro de la surface // si tabb(i) est une ligne, Num_de_frontiere_dans_le_type(i) donnera le numéro de la ligne // si tabb(i) est un point, Num_de_frontiere_dans_le_type(i) donnera le numéro du point int Element::Num_de_frontiere_dans_le_type(int i) const { // on supprime les cas hors du tableau tabb if (i<1) return 0; int tailletab = tabb.Taille(); if (i>tailletab) return 0; // cas normal if (i <= posi_tab_front_lin) // cela veut dire que i est une surface car les premières frontières sont les surfaces, de plus i est directement le numéro de surface { return i;} else if (i <= posi_tab_front_point) // cela veut dire que i est une ligne car les frontières après les surfaces sont les lignes { return (i-posi_tab_front_lin); } else // cela veut dire que i est un point car les frontières après les lignes sont des points { return (i-posi_tab_front_point);}; }; // ramene le numero de la frontière passée en argument si elle existe actuellement au niveau de l'élément // sinon ramène 0 // ramene également type_front: qui indique le type de frontière: POINT_G, LIGNE ou SURFACE // c'est une méthode très longue, a utiliser avec précaution int Element::Num_frontiere(const ElFrontiere& fronti, Enum_type_geom& type_front) { int num=0; type_front = RIEN_TYPE_GEOM; // initialisation du retour // on commence par balayer toutes les frontières pour trouver le numéro global int tail_tab=tabb.Taille(); for (int i=1;i<=tail_tab;i++) if (fronti == (*tabb(i))) {num = i; break;} // si num est diff de 0 c'est ok, on recherche le type de frontière if (num != 0) { // les frontières sont rangées selon: surface, ligne, point // s'il n'y a pas de point: ind_front_point = 0, dans ce cas posi_tab_front_point = 0 par défaut et ne veut rien dire // idem pour les lignes et les surfaces // suivant le type de frontière on retire la position initiale de ce type dans le tableau if ((num > posi_tab_front_point)&&(ind_front_point!=0)) {type_front = POINT_G;num -= posi_tab_front_point;} else if ((num > posi_tab_front_lin)&&(ind_front_lin!=0)) {type_front = LIGNE;num -= posi_tab_front_lin;} // si ce n'est ni un point ni une ligne, vue que ça doit-être quelque chose ça ne peut être qu'une surface else {type_front = SURFACE;}; // et num a directement la bonne valeur que ce sont d'abord les faces qui sont stockées } // retour des infos return num; }; // ========== 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 // numface indique le numéro de la face chargée // retourne le second membre résultant // ici la définition est celle par défaut qui concerne tous les éléments // qui ne possède pas de surface externe, type biellette etc // -> version explicite à t Vecteur Element::SM_charge_surfacique_E_t(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_surfacique_E_t(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> version explicite à tdt Vecteur Element::SM_charge_surfacique_E_tdt(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_surfacique_E_tdt(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // cas d'un chargement surfacique, sur les frontières des éléments // force indique la force surfacique appliquée // numface indique le numéro de la face chargée // NB: il y a une définition par défaut pour les éléments qui n'ont pas de // surface externe -> message d'erreur d'où le virtuel et non virtuel pur // ici la définition est celle par défaut qui concerne tous les éléments // -> implicit // pa : permet de déterminer si oui ou non on calcul la contribution à la raideur Element::ResRaid Element::SMR_charge_surfacique_I(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_surfacique_I( " << "Coordonnee& force,int numFace) \n"; Sortie(1); return ResRaid(); }; // cas d'un chargement de type pression, sur les frontières des éléments // pression indique la pression appliquée // numface indique le numéro de la face chargée // retourne le second membre résultant // NB: il y a une définition par défaut pour les éléments qui n'ont pas de // surface externe -> message d'erreur d'où le virtuel et non virtuel pur // -> cas d'un calcul explicite à t Vecteur Element::SM_charge_pression_E_t(double ,Fonction_nD* ,int ,const ParaAlgoControle &) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_pression_E_t( " << "double pression,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> cas d'un calcul explicite à tdt Vecteur Element::SM_charge_pression_E_tdt(double ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_pression_E_tdt( " << "double pression,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_pression_I(double ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_pression_I( " << "double pression,int numFace) \n"; Sortie(1); return ResRaid(); }; // cas d'un chargement de type pression unidirectionnelle, sur les frontières des éléments // presUniDir indique le vecteur appliquée // numface indique le numéro de la face chargée // retourne le second membre résultant // NB: il y a une définition par défaut pour les éléments qui n'ont pas de // surface externe -> message d'erreur d'où le virtuel et non virtuel pur // -> cas d'un calcul explicite à t Vecteur Element::SM_charge_presUniDir_E_t(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_presUniDir_E_t( " << "const Coordonnee& presUniDir,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> cas d'un calcul explicite à tdt Vecteur Element::SM_charge_presUniDir_E_tdt(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_presUniDir_E_tdt( " << "const Coordonnee& presUniDir,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_presUniDir_I(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_presUniDir_I( " << "const Coordonnee& presUniDir,int numFace) \n"; Sortie(1); return ResRaid(); }; // 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 // ici la définition est celle par défaut qui concerne tous les éléments // qui ne possède pas d'arete externe, type point ! // -> explicite à t Vecteur Element::SM_charge_lineique_E_t(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_lineique_E_t(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> explicite à tdt Vecteur Element::SM_charge_lineique_E_tdt(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_lineique_E_tdt(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_lineique_I(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_lineique__I(bool " << "Coordonnee& force,int numFace) \n"; Sortie(1); return ResRaid(); }; // cas d'un chargement lineique suiveuse, sur les aretes frontières des éléments 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 // ici la définition est celle par défaut qui concerne tous les éléments // qui ne possède pas d'arete externe, type point ! ou 3D pour lesquels la fonction n'est pas implantée // -> explicite à t Vecteur Element::SM_charge_lineique_Suiv_E_t(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_lineique_Suiv_E_t(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> explicite à tdt Vecteur Element::SM_charge_lineique_Suiv_E_tdt(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_lineique_Suiv_E_tdt(const " << "Coordonnee& force,int numFace) \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_lineique_Suiv_I(const Coordonnee& ,Fonction_nD* ,int ,const ParaAlgoControle &) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_lineique_Suiv_I(bool " << "Coordonnee& force,int numFace) \n"; Sortie(1); return ResRaid(); }; // cas d'un chargement volumique, // force indique la force volumique appliquée // retourne le second membre résultant // -> explicite à t Vecteur Element::SM_charge_volumique_E_t(const Coordonnee& ,Fonction_nD* ,const ParaAlgoControle & ,bool ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_volumique_E_t(const " << "Coordonnee& force) \n"; Sortie(1); return Vecteur(); }; // -> explicite à tdt Vecteur Element::SM_charge_volumique_E_tdt(const Coordonnee& ,Fonction_nD* ,const ParaAlgoControle & ,bool ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SM_charge_volumique_E_tdt(const " << "Coordonnee& force) \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_volumique_I(const Coordonnee& ,Fonction_nD* ,const ParaAlgoControle & ,bool ) { cout << "\n Erreur , fonction non défini pour l'élément \n"; cout << "\n méthode : SMR_charge_volumique_I(bool " << "Coordonnee& force) \n"; Sortie(1); return ResRaid(); }; // cas d'un chargement surfacique hydrostatique, // poidvol: indique le poids volumique du liquide // M_liquide : un point de la surface libre // dir_normal_liquide : direction normale à la surface libre // sans_limitation : indique s'il y a une limitation du calcul pour les seuls positions négatives // retourne le second membre résultant // -> explicite à t Vecteur Element::SM_charge_hydrostatique_E_t(const Coordonnee& ,const double& ,int ,const Coordonnee& ,const ParaAlgoControle & , bool) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SM_charge_hydrostatique_E_t(... \n"; Sortie(1); return Vecteur(); }; // -> explicite à tdt Vecteur Element::SM_charge_hydrostatique_E_tdt(const Coordonnee& ,const double& ,int ,const Coordonnee& ,const ParaAlgoControle & ,bool ) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SM_charge_hydrostatique_E_tdt(... \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_hydrostatique_I(const Coordonnee& ,const double& ,int ,const Coordonnee& ,const ParaAlgoControle & ,bool) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SMR_charge_hydrostatique_I(... \n"; Sortie(1); return ResRaid(); }; // 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 Element::SM_charge_hydrodynamique_E_t( Courbe1D* ,const double& , Courbe1D* ,int ,const double& , Courbe1D* ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SM_charge_hydrodynamique_E_t(... \n"; Sortie(1); return Vecteur(); }; // -> explicite à tdt Vecteur Element::SM_charge_hydrodynamique_E_tdt( Courbe1D* ,const double& , Courbe1D* ,int ,const double& , Courbe1D* ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SM_charge_hydrodynamique_E_tdt(... \n"; Sortie(1); return Vecteur(); }; // -> 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 Element::SMR_charge_hydrodynamique_I( Courbe1D* ,const double& , Courbe1D* ,int ,const double& , Courbe1D* ,const ParaAlgoControle & ) { cout << "\n Erreur , fonction non defini pour l'element \n"; cout << "\n methode : SMR_charge_hydrodynamique_I(... \n"; Sortie(1); return ResRaid(); }; // ======== choix d'un element ===================================== // choix d'un element derive etaffectation d'un pointeur d'element // en fonction de id_geom et id_interpol // le numero d'element : num_elt, est affecte a l'element pointe par ptr // fonctionnement : le choix est effectue grace a la liste static "listTypeElement" // qui est rempli au moment du chargement du programme, par toutes // classes derivees Element* Element::Choix_element(int num_mail,int num_elt,Enum_geom id_geom, Enum_interpol id_interpol,EnumElemTypeProblem id_typeProb ,const string& infos_annexes) { // déclaration d'une variable static qui permet de gagner du temps de recherche static list ::iterator dernier_itt; list ::iterator itt=dernier_itt; Element * ptr = NULL; if (!premier_passage_Choix_element) // on teste de dernier choix d'élément {if (((*itt).id_interpol == id_interpol) && ((*itt).id_geom == id_geom) && ((*itt).id_typeProblem == id_typeProb)&&((*itt).infos_annexes == infos_annexes)) {// on a trouve le bon element ptr = ((*itt).el)->NouvelElement(num_mail,num_elt); // on sauvegarde le pointeur pour la prochaine fois pour gagner du temps de recherche dernier_itt=itt; return ptr; } } // si l'on n'a pas trouvé on balaie la liste des elements enregistre for (itt=Element::listTypeElement.begin() ; itt != Element::listTypeElement.end(); itt++) if (((*itt).id_interpol == id_interpol) && ((*itt).id_geom == id_geom) && ((*itt).id_typeProblem == id_typeProb) &&((*itt).infos_annexes == infos_annexes)) {/*cout << "\n(*itt).infos_annexes.size() " << (*itt).infos_annexes.size(); cout << "\n infos_annexes.size() " << infos_annexes.size(); cout << "\n (*itt).infos_annexes " << (*itt).infos_annexes; if ((((*itt).infos_annexes.size()==0)&&(infos_annexes.size()==0)) || ((*itt).infos_annexes == infos_annexes)) */ {// on a trouve le bon element ptr = ((*itt).el)->NouvelElement(num_mail,num_elt); // on sauvegarde le pointeur pour la prochaine fois pour gagner du temps de recherche dernier_itt=itt; return ptr; } } // cas ou l'on n'a pas trouve d'element ptr = NULL; itt = Element::listTypeElement.begin(); // pour éviter une erreur au prochain passage return ptr; }; // idem en fonction de la signature Element* Element::Choix_element(int num_mail,int num_elt,Signature signa) { return Choix_element(num_mail,num_elt,signa.id_geom,signa.id_interpol,signa.id_problem ,signa.infos_annexes); }; // renseignement d'un élément complet à partir d'un élément incomplet de même type // retourne les nouveaux noeuds construit à partir de l'interpolation incomplète. // dans le cas l'élément n'est pas concerné, retourne une liste vide // ramène également une liste de même dimension contenant les bornes en numéros de noeuds // entre lesquelles il faut définir les nouveaux numéros de noeuds si l'on veut conserver // une largeur de bande optimisée du même type // nbnt+1: est le premier numéro de noeud utilisable pour les nouveaux noeuds list Element::Construct_from_imcomplet(const Element & ,list & ,int ) { list li; if (this->id_interpol != QUADRACOMPL) // l'élément n'est pas concerné return li; else { cout << "\n fonction non implante actuellement pour l'element "; Affiche(); Sortie(1); } return li; // pour faire taire le compilo }; // renseignement d'un élément quadratique incomplet à partir d'un élément linéaire de même type // retourne les nouveaux noeuds construit à partir de l'interpolation linéqire. // dans le cas où l'élément n'est pas concerné, retourne une liste vide // ramène également une liste de même dimension contenant les bornes en numéros de noeuds // entre lesquelles il faut définir les nouveaux numéros de noeuds si l'on veut conserver // une largeur de bande optimisée du même type // nbnt+1: est le premier numéro de noeud utilisable pour les nouveaux noeuds list Element::Construct_from_lineaire(const Element & ,list & , int ) { list li; if (this->id_interpol != LINEAIRE) // l'élément n'est pas concerné return li; else { cout << "\n fonction non implante actuellement pour l'element "; Affiche(); Sortie(1); } return li; // pour faire taire le compilo }; // réaffectation d'un pointeur de noeud // ramène faux si l'opération n'est pas possible bool Element::Reaffectation_pointeur_noeud(Noeud * ancien, Noeud * nouveau) { // on balaie les noeuds de l'éléments int nbn = tab_noeud.Taille(); for (int i=1;i<=nbn;i++) { if (tab_noeud(i)==ancien) { tab_noeud(i) = nouveau; return true; } } // cas ou l'on n'a pas trouvé le noeud return false; }; // ======== sortie fichier de commande ==================================== // ramène un tableau de pointeur d'élément qui sont concerné // par la sortie des commandes Tableau Element::Info_commande_Element(UtilLecture * ) { // tout d'abord on balaie la liste des elements enregistre pour savoir le nombre // d'element concerné string ordd = "concerne"; int nbel=0; int nbmail=0; list ::iterator itt; for (itt=Element::listTypeElement.begin() ; itt != Element::listTypeElement.end(); itt++) {bool ret = ((*itt).el)->Element_possible(); if (ret) nbel++; } // maintenant on peut dimensionner le tableau de manière a_doc Tableau retour(nbel); // on cree le tableau d'element nbel=1; for (itt=Element::listTypeElement.begin() ; itt != Element::listTypeElement.end(); itt++) {bool ret = ((*itt).el)->Element_possible(); if (ret) { retour(nbel) = ((*itt).el)->NouvelElement(nbmail,nbel); nbel++; } } return retour; }; //===================================================================================== // METHODES PROTEGEES utilisables par les classes derivees : //===================================================================================== // affichage d'info en fonction de ordre // ordre = "commande" : affichage d'un exemple d'entree pour l'élément void Element::Info_com_El (int nbnoeu,UtilLecture * entreePrinc,string& ordre,Tableau * tabMaillageNoeud) { if (ordre == "commande") { // def des noeuds de l'élément tab_noeud.Change_taille(nbnoeu); for (int i=1;i<=nbnoeu;i++) tab_noeud(i) = (*tabMaillageNoeud)(i); // construction du tableau de ddl des noeuds de biellette ConstTabDdl(); // affichage de l'élément ofstream & sort = *(entreePrinc->Commande_pointInfo()); sort << "\n " << setw (6) << this->Num_elt() << " " << this->Geometrie() << " " << this->Interpolation() << " "; // sortie de la connection int compteur_ligne=6; for (int n1=1;n1<= nbnoeu;n1++,compteur_ligne++) { if (compteur_ligne > 10) { compteur_ligne = 0; sort << "\n";} sort << setw (6) << n1 <<" "; } } }; // ---------------- lecture écriture dans base info ---------------- // pour les données spécifiques à element // 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 Element::Lect_bas_inf_element (ifstream& ent,const Tableau * tabMaillageNoeud,const int cas) {switch (cas) { case 1 : // ------- on récupère tout ------------------------- { // le tableau de connection des noeuds int tab_noeudTaille; string toto; ent >> toto >> tab_noeudTaille >> toto; if (tab_noeud.Taille() != tab_noeudTaille) { cout << "\nErreur : valeur incorrecte du nombre de noeud !\n"; cout << "Element::Lect_bas_inf_element(...)"; Sortie(1); }; int nb; for (int i=1;i<= tab_noeudTaille; i++) { ent >> nb; tab_noeud(i) = (*tabMaillageNoeud)(nb); }; break; } case 2 : // ----------- lecture uniquement de se qui varie -------------------- { // ici on lit et on vérifie que la connexion est correcte mais on ne change rien int tab_noeudTaille; string toto; // sort << "connexion " << tab_noeudTaille << " noeuds: "; ent >> toto >> tab_noeudTaille >> toto; bool erreur_connexion=false; if (tab_noeud.Taille() != tab_noeudTaille) erreur_connexion = true; Tableau inter(tab_noeudTaille); for (int i=1;i<= tab_noeudTaille; i++) { ent >> inter(i); if (inter(i) != tab_noeud(i)->Num_noeud()) {erreur_connexion = true;} }; if (erreur_connexion) { cout << "\nErreur : valeur incorrecte du nombre de noeud lu !" << " element nb: "<< num_elt << " maillage " << num_maillage; cout << " \n la connexion en cours :"; cout << "connexion " << tab_noeud.Taille() << " noeuds: "; for (int i=1;i<= tab_noeud.Taille(); i++) cout << tab_noeud(i)->Num_noeud() << " "; cout << "\n connexion lue: " << tab_noeudTaille << " noeuds: "; for (int i=1;i<= tab_noeudTaille; i++) cout << inter(i) << " "; cout << "\n"; if (ParaGlob::NiveauImpression() > 5) cout << "Element::Lect_bas_inf_element(...)"; Sortie(1); }; // lecture du volume ent >> toto >> volume; // --- cas des intégrales volumiques: // 1) les intégrales de volume string mot; ent >> mot; if (mot != "int_vol" ) { cout << "\n *** erreur en lecture du .info, le mot cle lu est "<> indic_test; // on ne continue que si indic est diff de 0 if (indic_test) { int taille=indic_test; for (int i=1; i<= taille;i++) {// lecture avec création éventuelle si le type n'existe pas TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::Lecture_avec_creation_eventuelle(ent); // on parcours la liste actuelle pour trouver la bonne grandeur éventuelle int indic = 0 ; // init if (enu_integ_vol_TQ != NULL) indic = enu_integ_vol_TQ->Contient(tqnevez); // maintenant, éventuellement indic = le numéro du conteneur existant if (indic) { (*integ_vol_typeQuel_t)(indic).Grandeur_pointee()->Lecture_grandeur(ent); } else // cas ou la grandeur n'existe pas { // c'est un peu plus délicat car on ne sait pas ce que l'on doit lire // on lit l'entête du type quelconque // -> on crée un grandeur quelconque sans grandeur associé ceci pour lire les entêtes TypeQuelconque pour_lire(RIEN_TYPEQUELCONQUE); // lecture de l'entête et récup d'enu EnuTypeQuelParticulier enu = pour_lire.Lecture_un(ent); // création d'une grandeur associée et lecture des information sur le flot TypeQuelconque::Grandeur* grandeur =NevezGrandeurParticuliereEnLecture(enu,ent); // création du type quelconque TypeQuelconque typQ(pour_lire.EnuTypeQuelconque(),pour_lire.Enum(),*grandeur); delete grandeur; // car il ne sert plus à rien // maintenant on va mettre à jour le stockage interne // ici on rajoute à la fin des tableaux, donc cela ne change pas ce qui a été lue // à l'initialisation du .info taille = integ_vol_typeQuel->Taille()+1; integ_vol_typeQuel->Change_taille(taille); integ_vol_typeQuel_t->Change_taille(taille); (*integ_vol_typeQuel)(taille) = typQ; (*integ_vol_typeQuel_t)(taille) = typQ; index_Integ_vol_typeQuel->Change_taille(taille); // par défaut on met l'index à -1, ce qui veut dire que la grandeur est // pour l'instant figé, tant que le calcul n'a pas démarré et que // l'utilisateur a indiqué qu'il désirait continuer l'intégration (*index_Integ_vol_typeQuel)(taille) = -1; enu_integ_vol_TQ->Change_taille(taille); (*enu_integ_vol_TQ)(taille)=tqnevez; }; }; }; // 2) les intégrales de volume et en temps ent >> mot; if (mot != "int_vol_t" ) { cout << "\n *** erreur en lecture du .info, le mot cle lu est "<> indic_test_t; // on ne continue que si indic est diff de 0 if (indic_test_t) { int taille=indic_test_t; for (int i=1; i<= taille;i++) {// lecture avec création éventuelle si le type n'existe pas TypeQuelconque_enum_etendu tqnevez = TypeQuelconque_enum_etendu::Lecture_avec_creation_eventuelle(ent); // on parcours la liste actuelle pour trouver la bonne grandeur éventuelle int indic = 0 ; // init if (enu_integ_vol_t_TQ != NULL) indic = enu_integ_vol_t_TQ->Contient(tqnevez); // maintenant, éventuellement indic = le numéro du conteneur existant if (indic) // cas simple où la grandeur exise déjà { (*integ_vol_t_typeQuel_t)(indic).Grandeur_pointee()->Lecture_grandeur(ent); } else // cas ou la grandeur n'existe pas { // c'est un peu plus délicat car on ne sait pas ce que l'on doit lire // on lit l'entête du type quelconque // -> on crée un grandeur quelconque sans grandeur associé ceci pour lire les entêtes TypeQuelconque pour_lire(RIEN_TYPEQUELCONQUE); // lecture de l'entête et récup d'enu EnuTypeQuelParticulier enu = pour_lire.Lecture_un(ent); // création d'une grandeur associée et lecture des information sur le flot TypeQuelconque::Grandeur* grandeur =NevezGrandeurParticuliereEnLecture(enu,ent); // création du type quelconque TypeQuelconque typQ(pour_lire.EnuTypeQuelconque(),pour_lire.Enum(),*grandeur); delete grandeur; // car il ne sert plus à rien // maintenant on va mettre à jour le stockage interne // ici on rajoute à la fin des tableaux, donc cela ne change pas ce qui a été lue // à l'initialisation du .info taille = integ_vol_t_typeQuel->Taille()+1; integ_vol_t_typeQuel->Change_taille(taille); integ_vol_t_typeQuel_t->Change_taille(taille); (*integ_vol_t_typeQuel)(taille) = typQ; (*integ_vol_t_typeQuel_t)(taille) = typQ; index_Integ_vol_t_typeQuel->Change_taille(taille); // par défaut on met l'index à -1, ce qui veut dire que la grandeur est // pour l'instant figé, tant que le calcul n'a pas démarré et que // l'utilisateur a indiqué qu'il désirait continuer l'intégration (*index_Integ_vol_t_typeQuel)(taille) = -1; enu_integ_vol_t_TQ->Change_taille(taille); (*enu_integ_vol_t_TQ)(taille)=tqnevez; }; }; }; break; } default : { cout << "\nErreur : valeur incorrecte du type de lecture !\n"; cout << "Element::Lect_bas_inf_element( " << " 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 Element::Ecri_bas_inf_element(ofstream& sort,const int 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 ------------------------- { // le tableau de connection des noeuds int tab_noeudTaille = tab_noeud.Taille(); sort << "connexion " << tab_noeudTaille << " noeuds: "; for (int i=1;i<= tab_noeudTaille; i++) sort << tab_noeud(i)->Num_noeud() << " "; sort << "\n"; break; } case 2 : // ----------- sauvegarde uniquement de se qui varie -------------------- { // on sauvegarde néanmoins la connexion, car cela permettra de détecter une variation // éventuelle de la numérotation, ce qui conduit à des erreurs de restart, très difficile // à localiser !! // donc le tableau de connection des noeuds int tab_noeudTaille = tab_noeud.Taille(); sort << "connexion " << tab_noeudTaille << " noeuds: "; for (int i=1;i<= tab_noeudTaille; i++) sort << tab_noeud(i)->Num_noeud() << " "; sort << "\n vol= " << volume << " "; // --- cas des grandeurs intégrés éventuelles // 1) les intégrales de volume sort << "\n int_vol "; if (integ_vol_typeQuel == NULL) {sort << 0 << " "; } else // sinon on sort les informations { int taille = integ_vol_typeQuel->Taille(); sort << taille ; for (int i=1; i<= taille;i++) { sort << " \n " << (*enu_integ_vol_TQ)(i) << " "; // l'identificateur // puis la grandeur à t (*integ_vol_typeQuel_t)(i).Const_Grandeur_pointee()->Ecriture_grandeur(sort); }; }; // 2) les intégrales de volume et en temps sort << "\n int_vol_t "; if (integ_vol_t_typeQuel == NULL) {sort << 0 << " "; } else // sinon on sort les informations { int taille = integ_vol_t_typeQuel->Taille(); sort << taille ; for (int i=1; i<= taille;i++) { sort << " \n " << (*enu_integ_vol_t_TQ)(i) << " "; // l'identificateur // puis la grandeur à t (*integ_vol_t_typeQuel_t)(i).Const_Grandeur_pointee()->Ecriture_grandeur(sort); }; }; sort << "\n"; break; } default : { cout << "\nErreur : valeur incorrecte du type d'écriture !\n"; cout << "ElemMeca::Ecriture_bas_inf(ofstream& sort,const int cas)" << " cas= " << cas << endl; Sortie(1); } }; };