// FICHIER : Element.h
// 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/>.


// La classe Element est une classe abstraite qui regroupe les caracteristiques communes
// a tout type d'element : un numero d'identification, deux identificateurs de type 
// enumere (un pour la geometrie, un pour le type d'interpolation), un tableau de
// connexite des noeuds de l'element.


#ifndef ELEMENT_H
#define ELEMENT_H

using namespace std;


#include <iostream>
#include <stdlib.h>
#include "Sortie.h"

#include "ElFrontiere.h"   
#include "Enum_interpol.h"
#include "Enum_geom.h"
#include "EnumElemTypeProblem.h"
#include "Enum_dure.h"
#include "Mat_pleine.h"
#include "Noeud.h"
#include "Tableau_T.h"
#include "Vecteur.h"
#include "Tenseur.h"
#include "UtilLecture.h"
#include "DdlElement.h"
#include "LoiAbstraiteGeneral.h"
#include <list>
#include "Bloc.h" 
#include "ElemGeomC0.h"  
#include "Enum_calcul_masse.h"
#include "ParaAlgoControle.h"
#include "Ddl_etendu.h"
#include "Basiques.h"
#include "Enum_type_geom.h"
#include "TypeQuelconque.h"
#include "PlusieursCoordonnees.h"
#include "Enum_PiPoCo.h"
#include "Enum_chargement.h"

/** @defgroup groupe_des_elements_finis
*
* La classe Element est une classe abstraite qui regroupe les caracteristiques communes
* a tout type d'element : un numero d'identification, deux identificateurs de type
* enumere (un pour la geometrie, un pour le type d'interpolation), un tableau de
* connexite des noeuds de l'element.
*
*
* \author    Gérard Rio
* \version   1.0
* \date       23/01/97
* \brief       groupe relatif aux éléments finis
*
*/

/// @addtogroup groupe_des_elements_finis
///  @{
///


class Element
{  
	
	public:
		
		
		// CONSTRUCTEURS :
		
		// Constructeur par defaut (ou fonction d'un numero d'identification)
		Element (int num_maill=0,int num_id=-3);
				
		// Constructeur fonction d'un numero de maillage et du tableau de connexite des noeuds
		Element (int num_maill, int num_id,const Tableau<Noeud *>& tab);
		
		// Constructeur fonction d'un numéro de maillage, d'un numero d'élément,  de trois identificateurs 
		// (geometrie, interpolation, type de probléme )
		// éventuellement un string d'information annexe
		Element (int num_maill,int num_id, Enum_interpol id_interp_elt,Enum_geom id_geom_elt,
		          EnumElemTypeProblem id_prob,string info="");
		
		  
		// Constructeur fonction d'un numéro de maillage, d'un numero d'élément et d'un numéro de maillage
		// et de deux noms (geometrie, interpolation)
		//et le type de problème traité par  l'element  
		Element (int num_maill,int num_id,const string& nom_interpol,const string& nom_geom,
		         const string& nom_prob,string info="");
		
		// 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 (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="");
																	
		// Constructeur fonction d'un numéro de maillage, d'un numero, du tableau de connexite des noeuds et de
		// quatre noms (geometrie, interpolation, type de probleme, particularité éventuelle),  															
		// et du type de problème traité par  l'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="");
		
		// Constructeur de copie
		Element (const Element& elt);
		
		
		// DESTRUCTEUR :
		// La variable loicomp doit etre instanciee a l'exterieur de cette classe
		// aussi lors de la destruction d'un element il n'y a pas destruction de la
		// loi de comportement associee
		// on ne recopie pas les adresses pointees car celles-ci peuvent changer,
		// donc il vaut mieux les reconstruire si besoin est.
		virtual ~Element ();
		
		
	// METHODES NON VIRTUELLES:
		
	/*	// lecture de l'entete de l'element, permet son identification parmi
		// tous les elements derivants
		void LectureEnTete(UtilLecture * entreePrinc); */
		
		// Affiche les donnees liees a l'element
		// n=1 : donnees d'en tete
		// n=2 : + tableau de noeuds
		// n=3 : + residu
		// n=4 : + raideur et matrice de masse si elle existe
		void Affiche (int n = 4) const;
		
		// Surcharge de l'operateur = : realise l'egalite de deux elements
		Element& operator= (Element& elt);
		
		inline void Change_num_elt (int nouveau_num)
		// Modifie le numero d'identification de l'element
		// ATTENTION : Les modifications liees au changement de numero de l'element sont
		// a la charge de l'utilisateur
		   { num_elt=nouveau_num; };
		
		inline void Change_interpol (string& nouveau_nom)
		// Remplace le nom du type d'interpolation par nouveau_nom
		// (par l'intermediaire du type enumere associe)
		// ATTENTION : Les modifications liees au changement du type d'interpolation
		// sont a la charge de l'utilisateur.
		   { id_interpol=Id_nom_interpol(nouveau_nom); };
		
		inline void Change_interpol (Enum_interpol nouveau_id)
		// Remplace l'identificateur d'interpolation par nouveau_id
		// ATTENTION : Les modifications liees au changement du type d'interpolation
		// sont a la charge de l'utilisateur.
		   { id_interpol=nouveau_id; };
		
		inline void Change_geom (string& nouveau_nom)
		// Remplace le nom de la geometrie par nouveau_nom
		// (par l'intermediaire du type enumere associe)
		// ATTENTION : Les modifications liees au changement de geometrie sont a la
		// charge de l'utilisateur.
		   { id_geom=Id_nom_geom(nouveau_nom); };
		
		inline void Change_geom (Enum_geom nouveau_id)
		// Remplace l'identificateur d'interpolation par nouveau_id
		// ATTENTION : Les modifications liees au changement de geometrie sont a
		// la charge de l'utilisateur.
		   { id_geom=nouveau_id; };
		
		inline string Geometrie ()
		// Retourne le nom correspondant a la geometrie de l'element
		   { return Nom_geom(id_geom); };
		
		inline Enum_geom Id_geometrie () const
		// Retourne l'identificateur correspondant a la geometrie de l'element
		// (de type enumere)
		   { return id_geom; };
		
		inline string Interpolation ()
		// Retourne le type d'interpolation de l'element
		   { return Nom_interpol(id_interpol); };
		
		inline Enum_interpol Id_interpolation () const
		// Retourne l'identificateur associe a l'interpolation de l'element
		// (de type enumere)
		   { return id_interpol; };
		
		inline string TypeProblem ()
		// Retourne le type de problème traité par l'element
		   { return NomElemTypeProblem (id_problem); };
		
		// retourne les infos annexes éventuelles de l'éléments
		// redéfini que pour les éléments particuliers
		virtual string Infos_annexe() const {return infos_annexes;};
		
		inline EnumElemTypeProblem Id_TypeProblem () const
		// Retourne l'identificateur associe au problème traité par l'element
		// (de type enumere)
		   { return id_problem; };
		
		inline int Num_noeud (int i) const 
		// Retourne le numero global du ieme noeud lie a l'element
		   {
   #ifdef MISE_AU_POINT
      if ( (i<1) || (i>tab_noeud.Taille()) )
		   	  {cout << "\nErreur : composante inexistante !\n";
		   		  cout << "ELEMENT::NUM_NOEUD (int ) \n";
         Sortie(1);
		   	  };
   #endif
		   	return tab_noeud(i)->Num_noeud();
		   };
		
		inline Noeud& Noeud_elt (int i)
		// Retourne le ieme noeud de connexite de l'element
		   {  
   #ifdef MISE_AU_POINT
		    if ( (i<1) || (i>tab_noeud.Taille()) )
			    {cout << "\nErreur : composante inexistante !\n";
				    cout << "ELEMENT::NOEUD_ELT (int ) \n";
				    Sortie(1);
			    };
   #endif
			   return *tab_noeud(i);	
		};
		
		inline int Nombre_noeud() const
		// Retourne le nombre de noeuds lies a l'element
		   { return tab_noeud.Taille(); };
		
		inline int& Num_elt()
		// Retourne le numero d'identification de l'element
		   { return num_elt; };
		// idem en lecture
		inline int Num_elt_const() const {return num_elt;};
		
		// retourne le numéro de maillage de l'élément
	 int Num_maillage() const {return num_maillage;};
		// change le numéro de maillage de l'élément
	 void Change_num_maillage(int newnum)  {num_maillage = newnum;};
		
		inline Tableau<Noeud *>& Tab_noeud()  
		// Retourne le tableau des noeuds appartenant a l'element
		   { return tab_noeud; };
    
  // change le numéro du noeud: ***** a utiliser avec discernement !!
  // car évidemment cela peut complètement changer l'intégrité de l'élément
  inline void Change_noeud(int i, Noeud* noe)
     {tab_noeud(i) = noe;};
		
		// idem précédent, mais en const, Retourne le tableau des noeuds appartenant a l'element
		inline const Tableau<Noeud *>& Tab_noeud_const()  const
		   { return tab_noeud; };
		
    // METHODES VIRTUELLES:		
		// test si l'element est complet
		// = 1 tout est ok, =0 element incomplet
		virtual int TestComplet();
	
	 // Libere la place occupee par le residu et eventuellement la raideur
		virtual void Libere ();
			
	     	
	   // METHODES VIRTUELLES PURES :
		
	 // Lecture des donnees de la classe sur fichier
	 // attribution des ddl aux noeuds relies a l'element
	 // en fonction du type d'element
		virtual void LectureDonneesParticulieres 
		   (UtilLecture * ,Tableau<Noeud  *> * ) = 0;
		
		// Calcul du residu local et de la raideur locale a t+dt
		//  pour le schema implicite
		class ResRaid { public : Vecteur* res; Mat_pleine * raid ; };
		virtual ResRaid Calcul_implicit (const ParaAlgoControle & pa ) = 0;
  // récup uniquement du conteneur raideur (pas forcément rempli, mais de la bonne taille)
  Mat_pleine * Conteneur_raideur () {return raideur; };
		
		// Calcul du residu local a l'instant t
		// pour le schema explicit, resultat dans le vecteur pointe
		virtual  Vecteur* CalculResidu_t (const ParaAlgoControle & pa) = 0;

		// Calcul du residu local a l'instant tdt
		// pour le schema explicit, resultat dans le vecteur pointe
		virtual  Vecteur* CalculResidu_tdt (const ParaAlgoControle & pa) = 0;
  // récup uniquement du conteneur résidu (pas forcément rempli, mais de la bonne taille)
  Vecteur* Conteneur_Residu () {return   residu;};

  // Calcul de la matrice masse pour l'élément
  virtual Mat_pleine * CalculMatriceMasse (Enum_calcul_masse id_calcul_masse) = 0;
		
		// procedure permettant de completer l'element apres
		// sa creation avec les donnees du bloc transmis
		// peut etre appeler plusieurs fois
		virtual Element* Complete(BlocGen & bloc,LesFonctions_nD*  lesFonctionsnD) = 0;
 
  // mise à jour éventuel de repère d'anisotropie
  virtual void Mise_a_jour_repere_anisotropie(BlocGen & bloc,LesFonctions_nD*  lesFonctionsnD);

     //------- gestion des ddl et grandeurs actives de l'élément --------------
  //-------  (et non les ddl des noeuds !!) --------------------------------
  // actualisation des ddl et des grandeurs actives de t+dt vers t      
  virtual void TdtversT() = 0;
  // actualisation des ddl et des grandeurs actives de t vers tdt      
  virtual void TversTdt() = 0;
  
     // -------------- grandeurs géométriques relatives à l'élément ----------------
		
		// ramene l'element geometrique 
		virtual ElemGeomC0& ElementGeometrique() const =0; 
		// ramene l'element geometrique en constant
		virtual const ElemGeomC0& ElementGeometrique_const() const =0;
  
		// 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
  double LongueurGeometrique_mini(int cas) const;
  
  // ramène la coordonnée maxi dans la direction i de l'ensemble des noeuds de l'élément
  // à l'instant tdt, ou t ou t=0 en fonction de temps
  double Maxi_xi_noeud(int i, Enum_dure temps);
  
  // calcul d'une longueur géométrique caractéristique représentative de l'élément
  // cas = 1: correspond à la distance moyenne entre deux noeuds coins de l'élément
  // cas = 2: dans le cas 1D -> distance moyenne entre noeuds extrèmes
  // modif 11 oct 24:
  //    old      en 2D: quadrangle: racine carré de la surface; triangle: racine carré de la 2*surface
  //    old      en 3D: hexa: racine cubique de vol; penta: racine cub de 2*vol, tétra: racine cub 6*vol
  //         en 2D: quadrangle et triangle : racine carré de la surface;
  //         en 3D:  racine cubique de vol;
  //  en axi avec cas == 2, la méthode n'est pas a employer, on retourne une erreur
  double LongueurGeometrique_caracteristique(int cas);
  
		// récupération du volume de l'élément (qui doit avoir été calculé dans une des classes dérivées
		// par exemple en mécanique via un calcul explicite ou implicite d'équilibre mécanique
		//  pour un élément 3D: le volume au sens classique
		//  pour un élément 2D: il s'agit de la surface * l'épaisseur
		//  pour un élément 1D: il s'agit de la longueur * la section
  // NB: ramène -ConstMath::tresgrand s'il n'a pas été calculé
		double Volume() const {return volume;};
		// 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 & VolumePlan();
  // modification de l'orientation de l'élément en fonction de cas_orientation
  // =0: inversion simple (sans condition) de l'orientation
  // si cas_orientation est diff de 0: on calcul le jacobien aux différents points d'intégration
  // 1.  si tous les jacobiens sont négatifs on change d'orientation
  // 2.  si tous les jacobiens sont positifs on ne fait rien
  // 3.  si certains jacobiens sont positifs et d'autres négatifs message
  //     d'erreur et on ne fait rien
  // ramène true: s'il y a eu changement effectif, sinon false
		virtual bool Modif_orient_elem(int cas_orientation) = 0;
  
  // calcul éventuel de la normale à un noeud
  // ce calcul existe pour les éléments 2D, 1D axi, et aussi pour les éléments 1D
  // qui possède un repère d'orientation
  // en retour coor = la normale si coor.Dimension() est = à la dimension de l'espace
  // si le calcul n'existe pas -->  coor.Dimension() = 0
  // ramène un entier :
  //    == 1 : calcul normal
  //    == 0 : problème de calcul -> coor.Dimension() = 0
  //    == 2 : indique que le calcul n'est pas licite pour le noeud passé en paramètre
  //           c'est le cas par exemple des noeuds exterieurs pour les éléments SFE
  //           mais il n'y a pas d'erreur, c'est seulement que l'élément n'est pas ad hoc pour
  //           calculer la normale à ce noeud là
  // temps: indique  à quel moment on veut le calcul
  virtual int CalculNormale_noeud(Enum_dure temps, const Noeud& noe
                                 ,Coordonnee& coor) = 0;
 
  //----------- intégration sur volume et temps ---------------
 // --- cas des intégrales volumiques: définition du conteneur, il peut également s'agir d'une intégration temporelle en +
  // d'où la grandeur courante et celle à t
  // dans le cas où il n'y a pas d'intégrale, retour d'un pointeur NULL
  // 1) retour des intégrations de volume uniquement
  //    cas des valeurs courantes
  const Tableau <TypeQuelconque>* Integ_vol_typeQuel() const {return integ_vol_typeQuel;};
  //    cas des valeurs à l'incrément précédent
  const Tableau <TypeQuelconque>* Integ_vol_typeQuel_t() const {return integ_vol_typeQuel_t;};
  //    une liste d'index qui est utilisable par les méthodes qui récupère les infos
  //    il y a un index par intégrale
  // NB: si le numéro est négatif, cela veut dire que l'intégrale est figée, on n'intègre plus
  //    cela vient d'un restart par exemple, qui contenait l'ingégrale, mais l'utilisateur
  //    ne veut plus que l'intégration continue
  const Tableau <int> * Index_Integ_vol_typeQuel() const {return index_Integ_vol_typeQuel;};
  // 2) intégration de volume et en temps: donc on commule le delta
  //    cas des valeurs courantes
  const Tableau <TypeQuelconque>* Integ_vol_t_typeQuel() const {return integ_vol_t_typeQuel;};
  //    cas des valeurs à l'incrément précédent
  const Tableau <TypeQuelconque>* Integ_vol_t_typeQuel_t() const {return integ_vol_t_typeQuel_t;};
  //    une liste d'index qui est utilisable par les méthodes qui récupère les infos
  //    il y a un index par intégrale
  const Tableau <int> * Index_Integ_vol_t_typeQuel() const {return index_Integ_vol_t_typeQuel;};
 
		
		
        //------- calcul d'erreur, remontée des contraintes -------------------
  // calcul du résidu et de la matrice de raideur pour la remontée des contraintes
  // et le calcul d'erreur
  class Er_ResRaid { public : 
	         Er_ResRaid(){}; // par défaut
	         Er_ResRaid(Tableau <Vecteur*>*  resEr, Mat_pleine*  raidEr) :
	            resErr(resEr),raidErr(raidEr)     {};
	         Tableau <Vecteur *>*  resErr; Mat_pleine*  raidErr;
                   };
	 // pour l'instant uniquement virtuel, par la suite devra être virtuelle pure
     //1) remontée aux contraintes
  virtual Er_ResRaid ContrainteAuNoeud_ResRaid();
     // 2) remontée aux erreurs aux noeuds
  virtual Er_ResRaid ErreurAuNoeud_ResRaid(); 
                                   
		// retourne les tableaux de ddl associés aux noeuds, gere par l'element
		// qui sont actifs au moment de la demande
		// ce tableau et specifique a l'element
  virtual const DdlElement & TableauDdl() const  = 0;
        
		// retourne la liste de tous les  types de ddl interne actuellement utilisés
		// par l'élément (actif ou non), sont exclu de cette liste les ddl des noeuds
		// reliés à l'élément (ddl implique grandeur uniquement scalaire !)
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
		virtual List_io <Ddl_enum_etendu> Les_type_de_ddl_internes(bool absolue) const = 0;
		// idem pour les grandeurs évoluées c'est-à-dire directement sous forme de vecteur, tenseurs, scalaire ....		 
		virtual List_io <TypeQuelconque> Les_type_evolues_internes(bool absolue) const = 0;
		// idem pour les données particulières
		virtual List_io <TypeQuelconque> Les_types_particuliers_internes(bool absolue) const = 0;
  
  // retourne la liste de toutes les  grandeurs quelconques relatives aux faces de
  // l'élément (actif ou non),
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual List_io <TypeQuelconque> Les_type_quelconque_de_face(bool absolue) const = 0;

  // retourne la liste de toutes les  grandeurs quelconques relatives aux arêtes de
  // l'élément (actif ou non),
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual List_io <TypeQuelconque> Les_type_quelconque_de_arete(bool absolue) const = 0;

        //  ----- activation ou non des ddl primaires, ----
  // ------ défini dans les classes dérivées ----
  // inactive les ddl primaires 
  virtual void Inactive_ddl_primaire() {};  
  // active les ddl primaires 
  virtual void Active_ddl_primaire()  {}; 
  // sortie de l'erreur à l'élément
  virtual double Erreur() = 0;
         
		// acquisition  d'une loi de comportement
		virtual void DefLoi(LoiAbstraiteGeneral * NouvelleLoi) = 0;
		// Compléter pour la mise en place de la gestion de l'hourglass via un comportement
		// ramène un pointeur null si la complexion n'est pas adaptée à l'élément
		virtual Element* Complet_Hourglass(LoiAbstraiteGeneral * NouvelleLoi, const BlocGen & bloc) = 0;
		// méthode pour indiquer à l'élément de préparer ses paramètres internes pour un futur calcul suivant une précision donnée
		// precision = 0 : aucune précision demandée, precision >=0 : précision maximale demandée
		void Drapeau_preparation_calcul_precis(int precision) {prepa_niveau_precision = precision;};

		// calcul d'un point dans l'élément réel en fonction des coordonnées dans l'élément de référence associé
		// temps: indique si l'on veut les coordonnées à t = 0, ou t ou tdt
		// 1) cas où l'on utilise la place passée en argument
		virtual Coordonnee & Point_physique(const Coordonnee& c_int,Coordonnee & co,Enum_dure temps) = 0;
		// 2) cas avec création
		Coordonnee Point_physique(const Coordonnee& c_int,Enum_dure temps)
          { Coordonnee co(ParaGlob::Dimension());Point_physique(c_int,co,temps);return co;};
		// 3) cas où l'on veut les coordonnées aux 1, 2 ou trois temps selon la taille du tableau t_co
		virtual void Point_physique(const Coordonnee& c_int,Tableau <Coordonnee> & t_co) = 0;
						
		// vérification de l'existence d'un point d'intégration correspondant à un ddl
		virtual bool Existe_pt_integ (int nbptinteg, Enum_ddl) const;
		// ramène le nombre total de points d'intégration correspondant à un type énuméré
		// peut-être surchargé pour des éléments particuliers (type sfe par exemple)
		virtual int NbPtInteg(Enum_ddl enu) const {return this->ElementGeometrie(enu).Nbi();};

		// ramene l'element geometrique correspondant au ddl passé en paramètre
		virtual ElemGeomC0& ElementGeometrie(Enum_ddl  ddl) const =0;
		// ramène le nombre de grandeurs génératrices pour un pt d'integ, correspondant à un type enuméré
		// peut-être surchargé pour des éléments particuliers 
		virtual int NbGrandeurGene(Enum_ddl enu) const =0;
		
	    // <<<<<< Pour les plaques et coques: >>>>>>> 
	 // indique si  l'élément fait partie des plaques, poutres ou coques ou aucun de ce types
	 Enum_PiPoCo PoutrePlaqueCoque() const {return TypePiPoCo(id_interpol,id_geom);};
		// ramène le nombre de points d'intégration de surface correspondant à un type énuméré
		// ramène 0 si l'élément n'est pas une plaque ou coque
		virtual int NbPtIntegSurface(Enum_ddl ) const {return 0;};
		// ramène le nombre de points d'intégration en épaisseur correspondant à un type énuméré
		// ramène 0 si l'élément n'est pas une plaque ou coque
		virtual int NbPtIntegEpaiss(Enum_ddl ) const {return 0;};
		// ramene l'element geometrique de surface correspondant au ddl passé en paramètre
		// ou null si ce n'est pas définie, dans ce cas si l'élément géométrique de surface est 2D
		// cela signifie qu'il faut se référer à l'élément générique: ElementGeometrie(...
		virtual ElemGeomC0* ElementGeometrieSurface(Enum_ddl  ) const {return NULL;};
		// ramene l'element geometrique d'épaisseur correspondant au ddl passé en paramètre
		// ou null si ce n'est pas définie, dans ce cas si l'élément géométrique de surface est 2D
		// cela signifie que tout est constant (identique) dans l'épaisseur
		virtual ElemGeomC0* ElementGeometrieEpaiss(Enum_ddl  ) const {return NULL;};
	    // <<<<<< fin Pour les plaques et coques: >>>>>>> 

  // calcul si un point est a l'interieur de l'element ou non
  // il faut que M est la dimension globale
  // les trois fonctions sont pour l'etude a t=0, t et tdt
  // retour : =0 le point est externe, =1 le point est interne , 
  //          = 2 le point est sur la frontière à la précision près 
  // coor_locales : s'il est différent de NULL, est affecté des coordonnées locales calculées,
  //                 uniquement précises si le point est interne
	 virtual int Interne_0(const Coordonnee& M,Coordonnee* coor_locales=NULL)  =0; 
	 virtual int Interne_t(const Coordonnee& M,Coordonnee* coor_locales=NULL)  =0; 
	 virtual int Interne_tdt(const Coordonnee& M,Coordonnee* coor_locales=NULL)  =0;
  
  // -- connaissances particulières sur l'élément
  // ramène  l'épaisseur de l'élément
  // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
  virtual double Epaisseurs(Enum_dure , const Coordonnee& ) =0;
  // ramène  l'épaisseur moyenne de l'élément (indépendante du point)
  // =0. si la notion d'épaisseurs ne veut rien dire pour l'élément
  virtual double EpaisseurMoyenne(Enum_dure ) =0;
  // ramène  la section de l'élément
  // =0. si la notion de section ne veut rien dire pour l'élément
  virtual double Section(Enum_dure , const Coordonnee& ) =0;
  // ramène  la section moyenne de l'élément (indépendante du point)
  // =0. si la notion de section ne veut rien dire pour l'élément
  virtual double SectionMoyenne(Enum_dure ) =0;

     // ======== sortie fichier de commande ====================================
  // ramène un tableau de pointeur  d'élément qui sont concerné
  // par la sortie des commandes 
  static Tableau <Element*> Info_commande_Element(UtilLecture * entreePrinc);
        
	 // affichage d'info en fonction de ordre
	 // ordre = "commande" : affichage d'un exemple d'entree pour l'élément
  virtual void Info_com_Element(UtilLecture * entreePrinc,string& ordre,Tableau<Noeud  *> * tabMaillageNoeud) = 0;
                         
     // ======== affichage ou récupération d'informations =============
  // affichage dans la sortie transmise, des variables duales "nom"
  // aux differents points d'integration
  // dans le cas ou nom est vide, affichage de "toute" les variables
  virtual void AfficheVarDual(ostream& sort, Tableau<string>& nom) = 0; 
        
		// retourne un numero d'ordre d'un point le plus près ou est exprimé la grandeur enum
		// par exemple un point d'intégration, mais n'est utilisable qu'avec des méthodes particulières
		// par exemple CoordPtInteg, ou Valeur_a_diff_temps
		// car le numéro d'ordre peut-être différent du numéro d'intégration au sens classique 
		// temps: dit si c'est à 0 ou t ou tdt
		virtual int PointLePlusPres(Enum_dure temps,Enum_ddl enu, const Coordonnee& M)  = 0;
		         
  // recuperation des coordonnées du point de numéro d'ordre iteg pour
  // la grandeur enu
		// temps: dit si c'est à 0 ou t ou tdt
  // si erreur retourne erreur à true
  virtual Coordonnee CoordPtInteg(Enum_dure temps,Enum_ddl enu,int iteg,bool& erreur)  = 0; 
  
  // recuperation des coordonnées du point d'intégration numéro = iteg pour
  // la face : face
  // temps: dit si c'est à 0 ou t ou tdt
  // si erreur retourne erreur à true
  virtual Coordonnee CoordPtIntFace(int face, Enum_dure temps,int iteg,bool& erreur) = 0;
  // recuperation des coordonnées du point d'intégration numéro = iteg pour
  // la face : face
  // temps: dit si c'est à 0 ou t ou tdt
  // si erreur retourne erreur à true
  virtual Coordonnee CoordPtIntArete(int arete, Enum_dure temps,int iteg,bool& erreur) = 0;

  // récupération des  valeurs au numéro d'ordre  = iteg pour
  // les grandeur enu: ici il s'agit de grandeurs scalaires
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual Tableau <double> Valeur_a_diff_temps
              (bool absolue,Enum_dure enu_t,const List_io<Ddl_enum_etendu>& enu,int iteg)  = 0;
  // récupération des valeurs au numéro d'ordre = iteg pour les grandeurs enu
  // ici il s'agit de grandeurs tensorielles, le retour s'effectue dans la liste
  // de conteneurs quelconque associée
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual void ValTensorielle_a_diff_temps(bool absolue,Enum_dure enu_t,List_io<TypeQuelconque>& enu,int iteg)  = 0;
  // récupération de grandeurs particulières au numéro d'ordre  = iteg  
  // celles-ci peuvent être quelconques
  // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual void Grandeur_particuliere (bool absolue,List_io<TypeQuelconque>& liTQ,int iteg)  = 0;
       
  // récupération de grandeurs particulières pour une face au numéro d'ordre  = iteg
  // celles-ci peuvent être quelconques
  // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual void Grandeur_particuliere_face (bool absolue,List_io<TypeQuelconque>& liTQ,int face, int iteg)  = 0;
 
  // récupération de grandeurs particulières pour une arête au numéro d'ordre  = iteg
  // celles-ci peuvent être quelconques
  // en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
  // absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
  virtual void Grandeur_particuliere_arete (bool absolue,List_io<TypeQuelconque>& liTQ,int arete, int iteg)  = 0;


		// --- transfert des grandeurs des points d'intégration aux noeuds 
		// transfert de ddl des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, on ne remplace pas)
		// les ddl doivent déjà exister aux noeuds sinon erreur
		// il doit s'agir du même type de répartition de pt d'integ pour toutes les grandeurs
        // tab_val(i)(j) : valeur associée au i ième pt d'integ et au j ième ddl_enum_etendu
		virtual void TransfertAjoutAuNoeuds(const List_io < Ddl_enum_etendu >& lietendu
                                     ,const Tableau <Tableau <double> > & tab_val,int cas) = 0; 
  // transfert de type quelconque des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, 
  // on ne remplace pas). Les types quelconques doivent déjà exister
  // un tableau dans tab_liQ  correspondent aux grandeurs quelconque pour tous les pt integ, 
  // tab_liQ(i) pour le pt d'integ i
	 // liQ_travail: est une liste de travail qui sera utilisée dans le transfert                        
  virtual void TransfertAjoutAuNoeuds(const Tableau <List_io < TypeQuelconque > >& tab_liQ
                                     ,List_io < TypeQuelconque > & liQ_travail,int cas) = 0;	  

  // accumulation aux noeuds de grandeurs venant des éléments vers leurs noeuds (exemple la pression appliquée)
	 // autres que celles aux pti classiques, mais directements disponibles
  // le contenu du conteneur stockées dans liQ est utilisé en variable intermédiaire
  virtual void Accumul_aux_noeuds(const List_io < Ddl_enum_etendu >& lietendu
                                  ,List_io < TypeQuelconque > & liQ,int cas) = 0;
        
    // ============ Calcul des frontieres de l'element================
    
  // tout d'abord une explication sur la terminologie
  //  on appelle frontières minimales de l'éléments les frontières naturelles c'est-à-dire
  //  pour les éléments 1D : les noeuds aux l'extrémitées en monde 1D 
  //                         sinon également l'élément en monde 2D et 3D
  //  pour les éléments 2D : les arrêtes de l'élément en monde 2D
  //                         sinon également la surface de l'élément en monde 2D et 3D
  //  pour les éléments 3D : les surfaces externes de l'élément
			
		// Calcul des frontieres minimales de l'element et retour d'un tableau tabb des frontières
		//  creation des elements frontieres et stockage dans l'element 
		//        si c'est la première fois sinon il y a seulement retour du tableau de ces elements
		//			a moins que le paramètre force est mis a true dans ce dernier cas seul les frontière effacées sont recréée
		virtual Tableau <ElFrontiere*> const & Frontiere(bool force = false) = 0;
		// 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
		// ramène 0 si i > tabb.Taille() ou < 1
		int Num_de_frontiere_dans_le_type(int i) const;
		
		// indique si oui ou non il existe  des éléments frontières
		bool Existe_frontiere()const {return tabb.Taille();};
		// suppression d'un élément frontière
		void SupprimeFront(ElFrontiere* elemFront);
        // suppression de tous les  éléments frontières
        // y compris les linéiques et surfaciques spécifiques éventuellement défini par les
        // fonctions Frontiere_lineique et par Frontiere_surfacique
		void SupprimeFront();

        // ------ cas particulier de frontières non spécifiquement défini -----
		// pour les éléments 3D les éléments frontières sont des surfaces qui contiennent
		// les arêtes. Les arêtes ne sont donc pas spécifiquement définies comme frontière
		// lorsque l'on veut spécifiquement les définir il faut le demander
		// idem pour les éléments 1D en monde 1D, et les surfaces pour les éléments 2D en monde
		// 2D
		// >>>> par contre pour les éléments 2D, la méthode Frontiere_lineique appel la  <<<
		// >>>> la méthode générale Frontiere, la création crée toutes les frontières de <<<
		// >>>> l'élément, la suppression est également équivalente à SupprimeFront()    <<<
		
		// ramène la frontière point
		// éventuellement création des frontieres points de l'element et stockage dans l'element 
		// si c'est la première fois  sinon il y a seulement retour de l'elements
		// a moins que le paramètre force est mis a true
		// dans ce dernier cas la frontière effacéee est recréée
		// num indique le numéro du point à créer (numérotation EF)
		virtual ElFrontiere* const  Frontiere_points(int num,bool force = false) = 0;
		
		// ramène la frontière linéique
		// éventuellement création des frontieres linéique de l'element et stockage dans l'element 
		// si c'est la première fois et en 3D sinon il y a seulement retour de l'elements
		// a moins que le paramètre force est mis a true
		// dans ce dernier cas la frontière effacéee est recréée
		// num indique le numéro de l'arête à créer (numérotation EF)
		virtual ElFrontiere* const  Frontiere_lineique(int num,bool force = false) = 0;
		
		// ramène la frontière surfacique
		// éventuellement création des frontieres surfacique de l'element et stockage dans l'element 
		// si c'est la première fois sinon il y a seulement retour de l'elements
		// a moins que le paramètre force est mis a true
		// dans ce dernier cas la frontière effacéee est recréée
		// num indique le numéro de la surface à créer (numérotation EF)
		virtual ElFrontiere* const  Frontiere_surfacique(int num,bool force = false) = 0;
		// pas de fonction "suppression" car en fait c'est une fonction frontière déguisée
		// il faut donc se servir de SupprimeFront()
		
		// ramene vrai si la surface numéro ns existe pour l'élément
		virtual bool SurfExiste(int ns) const =0;
		// ramene vrai si l'arête numéro na existe pour l'élément
		virtual bool AreteExiste(int na) const =0;
		// 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 Num_frontiere(const ElFrontiere& fronti, Enum_type_geom& type_front) const;
  
  // Calcul spécifiques des frontieres de l'element et retour d'un tableau tabb des frontières
  //  creation des elements frontieres et stockage dans l'element
  // la création n'a lieu qu'au premier appel
  // ou lorsque l'on force le paramètre force a true
  // dans ce dernier cas seul les frontière effacées sont recréée
  // cas :
  //  = 0 -> on veut toutes les frontières
  //  = 1 -> on veut uniquement les surfaces
  //  = 2 -> on veut uniquement les lignes
  //  = 3 -> on veut uniquement les points
  //  = 4 -> on veut les surfaces + les lignes
  //  = 5 -> on veut les surfaces + les points
  //  = 6 -> on veut les lignes + les points
//  virtual Tableau <ElFrontiere*> const & Frontiere_specifique(int cas, bool force = false) = 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()
  virtual const DeuxCoordonnees& Boite_encombre_element(Enum_dure temps);
  // récupération de la boite d'encombrement de l'élément (la dernière calculée selon Boite_encombre_element)
  const DeuxCoordonnees & RecupBoite_encombre_element() const {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 In_boite_emcombrement_elem(const Coordonnee& M,double depass = 0.) const; 

	// ========== calcul des seconds membres suivant les chargements =======
 
  // initialisation éventuelle, nécessaire avant d'appliquer l'ensemble des charges
  // par exemple des stockages intermédiaires
  virtual void Initialisation_avant_chargement() = 0;
 
	 // 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
	 // 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
	 // -> explicite à t 
  virtual Vecteur SM_charge_surfacique_E_t
	                  (const Coordonnee& force,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	 // -> explicite à tdt 
  virtual Vecteur SM_charge_surfacique_E_tdt
	                  (const Coordonnee& force,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	 // -> implicite, 
	 // pa: permet de déterminer si oui ou non on  calcul la contribution à la raideur 
	 // retourne le second membre et la matrice de raideur correspondant
  virtual ResRaid SMR_charge_surfacique_I
	               (const Coordonnee& force,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	  
	 // 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
	 // -> explicite à t
  // la fonction nD est utilisée que si elle ne dépend pas strictement de grandeurs globales
  virtual Vecteur SM_charge_pression_E_t
	             (double pression,Fonction_nD* pt_fonct, int numFace,const ParaAlgoControle & pa) ;
	 // -> explicite à tdt
  virtual Vecteur SM_charge_pression_E_tdt
	             (double pression,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	 // -> implicite, 
  // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur 
	 // retourne le second membre et la matrice de raideur correspondant
  virtual ResRaid SMR_charge_pression_I
	               (double pression,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;

	 // 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
	 // -> explicite à t 
  virtual Vecteur SM_charge_presUniDir_E_t
	                 (const Coordonnee& presUniDir,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	 // -> explicite à tdt 
  virtual Vecteur SM_charge_presUniDir_E_tdt
	               (const Coordonnee& presUniDir,Fonction_nD* pt_fonct,int numFace,const ParaAlgoControle & pa) ;
	 // -> implicite, 
	 // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur  
	 // retourne le second membre et la matrice de raideur correspondant
  virtual ResRaid SMR_charge_presUniDir_I
	            (const Coordonnee& presUniDir,Fonction_nD* pt_fonct,int numFace
	            ,const ParaAlgoControle & pa) ;

	 // cas d'un chargement lineique, sur les aretes frontières des éléments
	 // force indique la force lineique appliquée
	 // numarete indique le numéro de l'arete chargée
	 // retourne  le second membre résultant
	 // NB: il y a une définition par défaut pour les éléments qui n'ont pas 
	 // d'arete externe -> message d'erreur d'où le virtuel et non virtuel pur
	 // -> explicite à t 
  virtual Vecteur SM_charge_lineique_E_t
	                     (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete,const ParaAlgoControle & pa) ;
	 // -> explicite à tdt 
  virtual Vecteur SM_charge_lineique_E_tdt
	                     (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete,const ParaAlgoControle & pa) ;
	 // -> implicite, 
  // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur 
	 // retourne le second membre et la matrice de raideur correspondant
  virtual ResRaid SMR_charge_lineique_I
	              (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete,const ParaAlgoControle & pa) ;

	 // 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
	 // NB: il y a une définition par défaut pour les éléments qui n'ont pas 
	 // d'arete externe -> message d'erreur d'où le virtuel et non virtuel pur
	 // -> explicite à t 
  virtual Vecteur SM_charge_lineique_Suiv_E_t
	                        (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete,const ParaAlgoControle & pa) ;
	 // -> explicite à tdt 
  virtual Vecteur SM_charge_lineique_Suiv_E_tdt
	                          (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete,const ParaAlgoControle & pa) ;
	 // -> implicite, 
  // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur 
	 // retourne le second membre et la matrice de raideur correspondant
  virtual ResRaid SMR_charge_lineique_Suiv_I
	                        (const Coordonnee& force,Fonction_nD* pt_fonct,int numArete
	                        ,const ParaAlgoControle & pa) ;

	 // ---- cas d'un chargement en force volumique, 
	 // force indique la force volumique appliquée
	 // retourne  le second membre résultant
	 // -> explicite à t	   
  virtual Vecteur SM_charge_volumique_E_t
       (const Coordonnee& force,Fonction_nD* pt_fonct,const ParaAlgoControle & pa,bool sur_volume_finale_) ;
	 // -> explicite à tdt	   
  virtual Vecteur SM_charge_volumique_E_tdt
       (const Coordonnee& force,Fonction_nD* pt_fonct,const ParaAlgoControle & pa,bool sur_volume_finale_) ;
	 // -> 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
  virtual ResRaid SMR_charge_volumique_I
       (const Coordonnee& force,Fonction_nD* pt_fonct,const ParaAlgoControle & pa,bool sur_volume_finale_) ;
	    
	 // --- 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	   
	 virtual Vecteur SM_charge_hydrostatique_E_t(const Coordonnee& dir_normal_liquide,const double& poidvol
              ,int numFace,const Coordonnee& M_liquide,const ParaAlgoControle & pa,bool sans_limitation) ;
	 // -> explicite à tdt	   
	 virtual Vecteur SM_charge_hydrostatique_E_tdt(const Coordonnee& dir_normal_liquide,const double& poidvol
              ,int numFace,const Coordonnee& M_liquide,const ParaAlgoControle & pa,bool sans_limitation) ;
	 // -> 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
	 virtual ResRaid SMR_charge_hydrostatique_I(const Coordonnee& dir_normal_liquide,const double& poidvol
             ,int numFace,const Coordonnee& M_liquide,const ParaAlgoControle & pa,bool sans_limitation) ;

	 // 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	   
	 virtual Vecteur SM_charge_hydrodynamique_E_t(  Courbe1D* frot_fluid,const double& poidvol
	                                               ,  Courbe1D* coef_aero_n,int numFace,const double& coef_mul
	                                               ,  Courbe1D* coef_aero_t,const ParaAlgoControle & pa);
	 // -> explicite à tdt	   
	 virtual Vecteur SM_charge_hydrodynamique_E_tdt(  Courbe1D* frot_fluid,const double& poidvol
	                                                  ,  Courbe1D* coef_aero_n,int numFace,const double& coef_mul
	                                                  ,  Courbe1D* coef_aero_t,const ParaAlgoControle & pa);
	 // -> 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
  virtual ResRaid SMR_charge_hydrodynamique_I(  Courbe1D* frot_fluid,const double& poidvol
	                                              ,  Courbe1D* coef_aero_n,int numFace,const double& coef_mul
	                                              ,  Courbe1D* coef_aero_t,const ParaAlgoControle & pa) ;
	 
	//============= lecture écriture dans base info ==========
	 // cas donne le niveau de la récupération
  // = 1 : on récupère tout
  // = 2 : on récupère uniquement les données variables (supposées comme telles)
  // tabMaillageNoeud : contiend les noeuds du maillage de définition de l'élément
  virtual void Lecture_base_info
	        (istream& ent,const Tableau<Noeud  *> * tabMaillageNoeud, int cas) = 0;
  // cas donne le niveau de sauvegarde
  // = 1 : on sauvegarde tout
  // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
  virtual void Ecriture_base_info(ostream& sort, int cas) = 0;
	    
	//-------------- pour modification d'éléments --------------------------- 
	 // définition d'un conteneur pour la définition d'un type d'élément 
	 class Signature
	     { public: 
        // surcharge de l'operator d'ecriture
        friend ostream & operator << (ostream &, const Signature &) ;
	       // constructeur de création
	       Signature(Enum_interpol id_pol,Enum_geom om,EnumElemTypeProblem blem,string inf):
	         id_interpol(id_pol),id_geom(om),id_problem(blem),infos_annexes(inf) {};
	       Signature(const Signature& a):   // constructeur de copie
	         id_interpol(a.id_interpol),id_geom(a.id_geom),id_problem(a.id_problem),infos_annexes(a.infos_annexes) {};
	       Signature& operator = ( const Signature& a); // surcharge de l'affectation	         
	       bool operator == ( const Signature& a); // surcharge de l'égalité
	       bool operator != ( const Signature& a); // surcharge de non égalité
	       // données publiques car conteneur de base pour l'échange typée  	     
	       Enum_interpol id_interpol; // identificateur d'interpolation
		      Enum_geom id_geom; // identificateur de geometrie
		      EnumElemTypeProblem id_problem; // identificateur du type de problem
		      string infos_annexes; // infos annexes complémentaires permettant une distinction
		                      // plus fine entre plusieurs éléments identiques pour
		                      // les trois énumérations (par exemple n'ayant pas le même
		                      // nombre de pt d'integ 
	      };
	 // ramène la signature de l'élément
	 Signature Signature_element() const
	                 { Signature iter(id_interpol,id_geom,id_problem,infos_annexes); return iter;};
  // test si this et l'élément passé en paramètre sont identiques uniquement concernant la signature et la géométrie
  // par contre il peut y avoir des différences au niveau de la loi, de la matière etc.
  // les éléments peuvent être de maillages différents
  // ramène true s'il y a identité, false sinon
  bool Meme_signature_et_geometrie(const Element& elem)const;
	
     // ======== choix d'un element ====================================
	 // choix d'un element derive et affectation d'un pointeur d'element 
	 // en fonction du num de maillage, de id_geom, id_interpol, id_typede problem, et éventuellement d'une
	 // chaine de caractère discriminante
  // 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
  // dans le cas ou l'operation echoue, renvoi du pointeur null
  static Element* Choix_element(int num_mail,int num_elt,Enum_geom id_geom
                   ,Enum_interpol id_interpol,EnumElemTypeProblem  id_typeProb
                   ,const string& discriminant);                         
	 // idem en fonction de la signature
  static Element* Choix_element(int num_mail,int num_elt,Signature signa);
  // 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 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
  virtual list <Noeud *> Construct_from_imcomplet(const Element & elem,list <DeuxEntiers> & li_bornes, int nbnt);
  // 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
  virtual list <Noeud *> Construct_from_lineaire(const Element & elem,list <DeuxEntiers> & li_bornes, int nbnt);
  // réaffectation d'un pointeur de noeud
  // ramène faux si l'opération n'est pas possible
  bool Reaffectation_pointeur_noeud(Noeud * ancien, Noeud * nouveau);
  // création d'un élément de copie: utilisation de l'opérateur new et du constructeur de copie 
  virtual Element* Nevez_copie() const = 0;
        
	// ========================= variables protégées ===========================
	protected :

		int num_elt; // numero d'identification de l'element
		int num_maillage; // numéro de maillage
		Tableau<Noeud *> tab_noeud; // tableau de connexite des noeuds
		Enum_interpol id_interpol; // identificateur d'interpolation
		Enum_geom id_geom; // identificateur de geometrie
		EnumElemTypeProblem id_problem; // identificateur du type de problem
				// retourne les infos annexes éventuelles de l'éléments
		string infos_annexes; // infos annexes complémentaires permettant une distinction
		                      // plus fine entre plusieurs éléments identiques pour$
		                      // les trois énumérations (par exemple n'ayant pas le même
		                      // nombre de pt d'integ
  int sens_numerotation; // par defaut = 1, mais si tous les jacobiens sont inverses => sens = -1

		// --- cas de la puissance interne ---
		Vecteur * residu; // residu local 
		Mat_pleine * raideur; // raideur locale 
		// --- cas des efforts externes concernant les aretes ------
		Tableau <Vecteur *> * res_extA; // pour les résidus et second membres
		Tableau <Mat_pleine *> * raid_extA; // pour les raideurs
		// --- cas des efforts externes concernant les faces  ------
		Tableau <Vecteur *> * res_extS; // pour les résidus et second membres
		Tableau <Mat_pleine *> * raid_extS; // pour les raideurs
		// --- cas des efforts externes concernant les noeuds frontières  ------
		Tableau <Vecteur *> * res_extN; // pour les résidus et second membres
		Tableau <Mat_pleine *> * raid_extN; // pour les raideurs
		// --- cas de la dynamique ------
		Mat_pleine * mat_masse; // matrice masse 
		// --- géométrie -------
		double volume; // volume actuelle de l'élément: calculé dans les classes dérivées
		Coordonnee volumePlan; // volume entre l'élément et les plans de ref: yz, xz, xy, uniquement pour les éléments
		                        // 2D dans un espace 3D
 
  // --- cas des intégrales volumiques: définition du conteneur, il peut également s'agir d'une intégration temporelle en +
  // d'où la grandeur courante et celle à t
  // ces grandeurs sont renseignées uniquement par les classes dérivées
  // dans le cas où il n'y a pas d'intégrale -> les pointeurs sont NULL
  //  associé aux intégrale, il y a  une liste d'index qui est utilisable par les méthodes
  //  qui récupère les infos
  //  il y a un index par intégrale et ce numéro est unique et défini au moment de la définition des conteneurs
  // (*index_Integ_vol_typeQuel)(ii) contient alors le numéro de l'intégrale qui a été
  // demandé par l'utilisateur = le numéro d'apparition dans le .info
  // NB: si le numéro est négatif, cela veut dire que l'intégrale est figée, on n'intègre plus
  //    cela vient d'un restart par exemple, qui contenait l'ingégrale, mais l'utilisateur
  //    ne veut plus que l'intégration continue
 
  // enu_integ_vol_TQ : indique l'enum du conteneur pour la récupération
  // idem pour enu_integ_vol_t_TQ

  // 1) intégration de volume uniquement
  Tableau <TypeQuelconque>* integ_vol_typeQuel, * integ_vol_typeQuel_t;
  Tableau <int> * index_Integ_vol_typeQuel;
  Tableau <TypeQuelconque_enum_etendu > * enu_integ_vol_TQ;
  // 2) intégration de volume et en temps: donc on commule le delta
  Tableau <TypeQuelconque>* integ_vol_t_typeQuel, * integ_vol_t_typeQuel_t;
  Tableau <int> * index_Integ_vol_t_typeQuel;
  Tableau <TypeQuelconque_enum_etendu > * enu_integ_vol_t_TQ;


		Tableau <ElFrontiere*> tabb; // le tableau des elements frontieres
		int ind_front_lin; // entier qui permet de contrôler la création des frontières linéiques
		int ind_front_surf; // idem pour les éléments frontières de surface
		int ind_front_point; // idem pour les éléments frontières points
		// pour ces trois entiers ind_... , =0 pas de frontières, =1 toutes les frontières existent, 
		// =2 seules certaines frontières existent
		int posi_tab_front_lin; // indice du début -1 des éléments linéique dans tabb
		int posi_tab_front_point; // indice du début -1 des points dans tabb
		   // au niveau du stockage dans tabb, il y a les surfaces puis les lignes puis les points
		// boite d'encombrement: boite_encombre.Premier() -> les min de la boite, .Second() -> les maxi
		DeuxCoordonnees  boite_encombre;  // ceci suivant les axes du repère global
		
		// indicateur piloter par la méthode :  Drapeau_preparation_calcul_precis(..
		// qui vise à indiquer à l'élément de préparer ses paramètres internes pour un futur calcul suivant une précision donnée
		int prepa_niveau_precision; // precision = 0 : aucune précision demandée, precision >=0 : précision maximale demandée 
		
//-------------------------------------------------------------------------------------
// classes à usage interne ou par les éléments internes des classes dérivées 
//-------------------------------------------------------------------------------------
		// definition de la liste qui contiendra les donnees necessaires a la creation
		// de nouveaux elements
  public:
        class ConstrucElement
          { public:
             // les fonctions permettant de creer une nouvelle instance d'element
             virtual Element * NouvelElement(int num_mail,int num) = 0; // un nouvel élément sans rien
             // ramene true si la construction de l'element est possible en fonction
             // des variables globales actuelles: ex en fonction de la dimension	
             virtual bool Element_possible() = 0;	
           };  	
		class NouvelleTypeElement
		 { public :
		     // constructeur par défaut
		     NouvelleTypeElement();
		     // constructeur normal
		     NouvelleTypeElement(const Enum_geom id_g,const Enum_interpol id_in
		                         , const EnumElemTypeProblem id_type
		                         , ConstrucElement * el =NULL,string   discri="");
		     // constructeur de copie
		     NouvelleTypeElement(const NouvelleTypeElement& nvel);
		     // opérateur d'assigment
		     NouvelleTypeElement& operator= (const NouvelleTypeElement& elt);
		     // opérateur tests
		     bool operator == (const NouvelleTypeElement& elt);
		     bool operator != (const NouvelleTypeElement& elt);
		     bool MemeTypeElement(const NouvelleTypeElement& elt);
		     
           // données public
		     Enum_geom id_geom; // identificateur de geometrie
		     Enum_interpol id_interpol; // identificateur d'interpolation
		     EnumElemTypeProblem  id_typeProblem; // identificateur du type de problème géré par l'élément
		     string infos_annexes; // chaine de caractère qui permet de spécialisé un élément parmi un ensemble
		                          // d'une même famille : par exemple deux éléments avec un nombre de pt d'integ
		                          // différents
		     ConstrucElement * el; // qui permet la def de l'element specifique
		  }; 
		  
		   
// list de tous les éléments (donnés interne) mais que l'on doit mettre en public pour que tous les 
// éléments dérivés puissent l'utilisé sans que on l'ai déclare explicitement ici
        static list <NouvelleTypeElement> listTypeElement;
 
          
//=====================================================================================
// METHODES  PROTEGEES utilisables ou a renseigner par les classes derivees :
//=====================================================================================
	protected :
     
        // ajout du tableau specific de ddl des noeuds 
        // la procedure met a jour les ddl
        // des noeuds constituants l'element
  virtual void ConstTabDdl() = 0;
        
	    // affichage d'info en fonction de ordre
	    // ordre = "commande" : affichage d'un exemple d'entree pour l'élément
  void Info_com_El
          (int nbnoeu,UtilLecture * entreePrinc,string& ordre,Tableau<Noeud  *> * tabMaillageNoeud) ;
  // changement du type de problème
  inline void Change_TypeProblem(EnumElemTypeProblem new_id_problem)
		   {id_problem = new_id_problem; };

        	 
	// ---------------- 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 Lect_bas_inf_element
	    (istream& ent,const Tableau<Noeud  *> * tabMaillageNoeud,const int cas) ;
     // cas donne le niveau de sauvegarde
     // = 1 : on sauvegarde tout
     // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
	 void Ecri_bas_inf_element(ostream& sort,const int cas) ;

	// ---------------- concernant les frontières  ----------------

		// suppression des frontières linéiques éventuelles
		// num indique le numéro de l'arête à supprimer (numérotation EF)
		// si num = 0, indique qu'il faut supprimer toutes les frontières
		void SupprimeFront3D_lineique(int num = 0);
  // fonction a renseigner par les classes dérivées, concernant les répercutions
  // éventuelles due à la suppression de tous les  frontières
  // nums_i : donnent les listes de frontières supprimées
  virtual void Prise_en_compte_des_consequences_suppression_tous_frontieres() = 0;
  // idem pour une frontière (avant qu'elle soit supprimée)        
  virtual void Prise_en_compte_des_consequences_suppression_une_frontiere(ElFrontiere* elemFront) = 0;
		
public: 
// 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é
  static const double epaisseur_defaut;        // épaisseur par défaut
  static const double largeur_defaut;          // largeur par défaut
  static const double section_defaut;          // section par défaut
  static const double masse_volumique_defaut ; // masse_volumique par défaut
  
protected:       
// variable de travail pour la fonction Choix_element
  static bool premier_passage_Choix_element;       
				
};
/// @}  // end of group

#endif
