// 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) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.



# include <iostream>
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::NouvelleTypeElement> 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<Noeud *>& 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<Noeud *>& 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<Noeud *>& 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 <TypeQuelconque>(*(elt.integ_vol_typeQuel));};
 if (elt.integ_vol_typeQuel_t != NULL)
    {integ_vol_typeQuel_t = new Tableau <TypeQuelconque>(*(elt.integ_vol_typeQuel_t));};
 if (elt.index_Integ_vol_typeQuel != NULL)
    {index_Integ_vol_typeQuel = new Tableau <int> (*(elt.index_Integ_vol_typeQuel));}
 if (elt.integ_vol_t_typeQuel != NULL)
    {integ_vol_t_typeQuel = new Tableau <TypeQuelconque>(*(elt.integ_vol_t_typeQuel));};
 if (elt.integ_vol_t_typeQuel_t != NULL)
    {integ_vol_t_typeQuel_t = new Tableau <TypeQuelconque>(*(elt.integ_vol_t_typeQuel_t));};
 if (elt.index_Integ_vol_t_typeQuel != NULL)
    {index_Integ_vol_t_typeQuel = new Tableau <int> (*(elt.index_Integ_vol_t_typeQuel));}
 if (elt.enu_integ_vol_TQ != NULL)
    {enu_integ_vol_TQ = new Tableau <TypeQuelconque_enum_etendu>(*(elt.enu_integ_vol_TQ));};
 if (elt.enu_integ_vol_t_TQ != NULL)
    {enu_integ_vol_t_TQ = new Tableau <TypeQuelconque_enum_etendu> (*(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 () "<<endl;
////--- fin debug

  for (int i=1;i<= dimtaille;i++)
    if (tabb(i) != NULL) delete tabb(i);

  // cas des intégrales de volumes
  if (integ_vol_typeQuel != NULL)
     {delete integ_vol_typeQuel;};
  if (integ_vol_typeQuel_t != NULL)
     {delete integ_vol_typeQuel_t;};
  if (integ_vol_t_typeQuel != NULL)
     {delete integ_vol_t_typeQuel;};
  if (integ_vol_t_typeQuel_t != NULL)
     {delete integ_vol_t_typeQuel_t;};
  if (index_Integ_vol_typeQuel != NULL)
     delete index_Integ_vol_typeQuel;
  if (index_Integ_vol_t_typeQuel != NULL)
     delete index_Integ_vol_t_typeQuel;
  if (enu_integ_vol_TQ != NULL)
     delete enu_integ_vol_TQ;
  if (enu_integ_vol_t_TQ != NULL)
     delete enu_integ_vol_t_TQ;
};

/*// lecture de l'entete de l'element, permet son identification parmi
// tous les elements derivants
void Element::LectureEnTete(UtilLecture * entreePrinc)
{ *(entreePrinc->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<Noeud *>& 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 <int> & 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_min(3)) || (M(3) > co_max(3))) return false;
       case 2: if ((M(2)<co_min(2)) || (M(2) > co_max(2))) return false;
   	   case 1: if ((M(1)<co_min(1)) || (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 <TypeQuelconque>(*(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 <TypeQuelconque>(*(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 <TypeQuelconque>(*(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 <TypeQuelconque>(*(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 <int>(*(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 <int>(*(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 <TypeQuelconque_enum_etendu>(*(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 <TypeQuelconque_enum_etendu>(*(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_mini(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_mini(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 (" <<ConstMath::petit <<")  ";
            #else
            Sortie(1);
            #endif
           }
         longueur=dist; //enregistrement     
         break;
        }
      default :
	   cout << "\nErreur : cas:" << cas <<" non encore traite  !\n"
			<< "Element::LongueurGeometrique_mini(int cas) ) \n";
	   Sortie(1);
	 }  
//cout << " longueur= "<<  longueur << endl;
   return longueur;   
  };

// calcul le volume entre l'élément (=surface2D) et les plans de ref: yz, xz, xy, dans cet ordre
// valable uniquement pour les éléments 2D dans un espace 3D, ramène une dim nulle sinon
// le calcul est approché, il est effectué à partir d'une triangulation de la surface de l'élément
const Coordonnee & Element::VolumePlan()
{ // petite vérif au début
  if (!((ParaGlob::Dimension()==3)&&(Type_geom_generique(id_geom)==SURFACE)))
    {
     #ifdef MISE_AU_POINT
      if (ParaGlob::NiveauImpression() > 4)
       {cout << "\n **** attention "
             << " ( elem "<<num_elt<<" du maillage "<< num_maillage <<") ";
        if (ParaGlob::Dimension()!=3) cout << " dim " << ParaGlob::Dimension();
        if (Type_geom_generique(id_geom)!=SURFACE)
         cout << " geometrie " << Nom_type_geom(Type_geom_generique(id_geom));
        cout << " pas de calcul definit de volume entre surface et plans de ref ";
       
//       cout << "\n **** attention, soit la geometrie n'est pas une surface, soit la dimension n'est pas 3 !!!! "
//             << "\n ( elem "<<num_elt<<" du maillage "<< num_maillage <<") "
//             << "\n **** le calcul du volume entre la surface et les plans de reference n'est pas definit dans ce cas " ;
        if (ParaGlob::NiveauImpression() > 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<Tableau<Tableau<int> > >& 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<Tableau<int> > & triaLin = triaLinGlob(1); 
  // on boucle sur les triangles
  int nbtriang = triaLin.Taille();
  volumePlan.Zero();
  for (int i=1;i<=nbtriang;i++)
   { const Tableau<int> & 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) const
 { 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++)
    {// le tableau global peut avoir été correctement dimensionné
     // mais les éléments frontières peuvent avoir été supprimés
     if (tabb(i) != NULL) // cas où la frontière existe
       {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 <Element::NouvelleTypeElement>::iterator dernier_itt;       
     list <Element::NouvelleTypeElement>::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 <Noeud *> Element::Construct_from_imcomplet(const Element & ,list <DeuxEntiers> & ,int  )
   { list <Noeud *> 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 <Noeud *> Element::Construct_from_lineaire(const Element & ,list <DeuxEntiers> & , int )
   { list <Noeud *> 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*> 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 <Element::NouvelleTypeElement>::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 <Element*> 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<Noeud  *> * 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<Noeud  *> * 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 <int> 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 "<<mot
                << " on attendait int_vol , la suite va etre erronee, on stop la lecture "
                << endl;
           Sortie(1);
         };
       int indic_test=0; ent >> 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 "<<mot
                << " on attendait int_vol_t , la suite va etre erronee, on stop la lecture "
                << endl;
           Sortie(1);
         };
       int indic_test_t=0; ent >> 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);
      }
    };
 };


