// FICHIER : Maillage.cp
// CLASSE : Maillage

// 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 "Maillage.h"
# include <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include <stdio.h>
#include <vector>
#include "List_io.h"
#include "CharUtil.h"

// au cas où pour la bufferisation des io
#include <string>       // std::string
#include <iostream>     // std::cout
#include <sstream>      // std::stringstream

//#ifndef SYSTEM_MAC_OS_X_unix
//   #include "Frontier.h"
//#endif
#include "ConstMath.h"
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "MvtSolide.h"
#include "TypeQuelconqueParticulier.h"
#ifdef UTILISATION_MPI
  #include <boost/mpi/environment.hpp>
  #include <boost/mpi/communicator.hpp>
  #include <boost/serialization/string.hpp>
  #include <boost/serialization/vector.hpp>
  #include <boost/mpi.hpp>
  namespace mpi = boost::mpi;
#endif

// CONSTRUCTEURS :
// pour tous les constructeurs: map < string, int , std::less <string> >* lisNomMail,
// est un tableau associatif nom <=> numéro de maillage, qui est utilisé par 
// les maillages, mais mis à jour par chaque maillage.
// nom_maill : est facultatif, s'il est différent de ".", il est pris en compte comme nom de maillage
		
// Constructeur par defaut
Maillage::Maillage (map < string, int , std::less <string> > & lisNomMail,int nmail,int dim
                    ,const string& nom_maill):
   listeNomMail(lisNomMail),nomDuMaillage(),idmail(nmail),dimension(dim)
   ,tab_noeud(),tab_element(),listFrontiere(),tab_noeud_front(),indice(),indice_NFr()
   , list_refIn(),list_refOut(),lesRefin(NULL),mitoyen_de_chaque_element()
   ,ddl_representatifs_des_physiques(),types_de_problemes()
   , ind_elem(),tab_sens_element() // tableaux internes utilisés par Orientation_elements_mitoyens_recursif
   ,detruire_les_noeuds_et_elements(true)
#ifdef UTILISATION_MPI
   ,buffer_ioBI_MPI() ,offset_maillage(),les_taille_buffer_ioBI_MPI()
   ,les_taille_buffer_ioBI_MPI_inter()
#endif

  {	if (nom_maill == ".")
     {// tout d'abord on donne un nom par défaut au maillage
      nomDuMaillage = "pas_de_nom";  
      while  (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
      { // on cherche un nom quelconque qui n'est pas déjà utilisé
        nomDuMaillage += '_';      
      };
     }
    else // le paramètre de nom de maillage est valide
     { nomDuMaillage = nom_maill;
     };
    // maintenant on associe le nom au numéro dans la map
    listeNomMail[nomDuMaillage]=idmail;
// #ifdef UTILISATION_MPI
//    tablcarI_O_gros = new char [taille_tablcarI_O_gros] ; // def du tableau de travail
// #endif

    
  };

// Constructeur fonction d'une dimension, du nombre de noeuds
//  du nombre d'elements, et d'un numero d'identification (le nb de maillage)
Maillage::Maillage (map < string, int , std::less <string> > & lisNomMail
                    ,int dim,int n_noeud,int n_elt,int nmail,const string& nom_maill):
// Constructeur utile quand la dimension, le nombre de noeuds
// et le nombre d'elements du maillage sont connus
   listeNomMail(lisNomMail),tab_noeud(n_noeud),tab_element(n_elt),listFrontiere(),tab_noeud_front()
   ,indice(),indice_NFr(),list_refIn(),list_refOut(),lesRefin(NULL),mitoyen_de_chaque_element()
   ,ddl_representatifs_des_physiques(),types_de_problemes()
   , ind_elem(),tab_sens_element() // tableaux internes utilisés par Orientation_elements_mitoyens_recursif
   ,detruire_les_noeuds_et_elements(true)
#ifdef UTILISATION_MPI
   ,buffer_ioBI_MPI(),offset_maillage(),les_taille_buffer_ioBI_MPI()
   ,les_taille_buffer_ioBI_MPI_inter()
#endif

{if (nmail <=0)
	 {	cout << "\nErreur : numero de maillage invalide !\n";
		  cout << "MAILLAGE::MAILLAGE(int ,int ,int,int ) \n";
		  Sortie(1);
	 };
 idmail = nmail;
 // traitement du nom de maillage
 if (nom_maill ==".")
   {// on donne un nom par défaut au maillage
    nomDuMaillage = "pas_de_nom";  
    while  (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
    { // on cherche un nom quelconque qui n'est pas déjà utilisé
      nomDuMaillage += '_';      
    };
   }
 else // le paramètre de nom de maillage est valide
   { nomDuMaillage = nom_maill;
   };
 // maintenant on associe le nom au numéro dans la map
 listeNomMail[nomDuMaillage]=idmail;
 
 if ( (dim<1) || (dim>3) )
	 {	cout << "\nErreur : dimension invalide !\n";
		  cout << "MAILLAGE::MAILLAGE(int ,int ,int ,int) \n";
		  Sortie(1);
	 };
	if ( n_noeud<=0 )
	 {	cout << "\nErreur : nombre de noeuds non valide !\n";
		  cout << "MAILLAGE::MAILLAGE(int ,int ,int ,int) \n";
		  Sortie(1);
	 };
	if ( n_elt<=0 )
	 {	cout << "\nErreur : nombre d'elements invalide !\n";
		  cout << "MAILLAGE::MAILLAGE(int ,int ,int,int ) \n";
		  Sortie(1);
	 };
	dimension=dim;
};
		
		
// Constructeur fonction de la plupart des informations (qui peuvent être vide
// mais doivent être cohérentes)
// *** il n'y a pas de création de nouveaux noeuds et de nouveaux éléments,
// ce sont les éléments et noeuds passés en paramètres qui sont ceux du maillage créé
Maillage::Maillage (map < string, int , std::less <string> > & lisNomMail
		          ,int dim,list <Noeud* >& li_noeud, list <Element* > li_element
		          ,int nmail,const string& nom_maill ):
   listeNomMail(lisNomMail),tab_noeud(),tab_element(),listFrontiere(),tab_noeud_front()
   ,indice(),indice_NFr(),list_refIn(),list_refOut(),lesRefin(NULL),mitoyen_de_chaque_element()
   ,ddl_representatifs_des_physiques(),types_de_problemes()
   , ind_elem(),tab_sens_element() // tableaux internes utilisés par Orientation_elements_mitoyens_recursif
   ,detruire_les_noeuds_et_elements(true)
#ifdef UTILISATION_MPI
   ,buffer_ioBI_MPI(),offset_maillage(),les_taille_buffer_ioBI_MPI()
   ,les_taille_buffer_ioBI_MPI_inter()
#endif

{  if (ParaGlob::NiveauImpression() >= 5)
        cout << " \n creation du maillage: " << nom_maill << endl;
   if (nmail <=0)
	   {	cout << "\nErreur2 : numero de maillage invalide !\n";
		    cout << "MAILLAGE::MAILLAGE( ) \n";
		    Sortie(1);
	   };
   // si le numéro de maillage est déjà utilisé, on signale que la place est prise
   for (std::map< string, int , std::less <string> >::iterator it=listeNomMail.begin();
        it!=listeNomMail.end(); ++it)
    { if ((it->second) == nmail)
       { cout << "\n *** erreur: le numero de maillage "<<nmail
              << " est deja utilise pour le maillage " << (it->first)
              << "\n constructeur: Maillage::Maillage (..."<< flush;
         Sortie(1);
       };
    };
   // sinon c'est ok
   idmail = nmail;
   // traitement du nom de maillage
   if (nom_maill ==".")
     {// on donne un nom par défaut au maillage
      nomDuMaillage = "pas_de_nom";  
      while  (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
      { // on cherche un nom quelconque qui n'est pas déjà utilisé
        nomDuMaillage += '_';      
      };
     }
   else // le paramètre de nom de maillage est valide
     { nomDuMaillage = nom_maill;
     };
   // maintenant on associe le nom au numéro dans la map
   listeNomMail[nomDuMaillage]=idmail;
   
   if ( (dim<1) || (dim>3) )
	   {	cout << "\nErreur2 : dimension invalide !\n";
		    cout << "MAILLAGE::MAILLAGE(... \n";
		    Sortie(1);
	   };
   dimension=dim;
   // récupération des noeuds
   int nbN = li_noeud.size();
   list <Noeud* >::iterator il,ilfin=li_noeud.end();
   Change_nb_noeud(nbN);
//   tab_noeud.Change_taille(nbN,NULL);
   // on vérifie que la numérotation est correcte pour les noeuds
   // c'est-à-dire que tous les numéros peuvent être rangés à suivre 
   bool numerotation_correcte = true;   
   for  (il=li_noeud.begin();il!=ilfin;il++)
     {int nb = (*il)->Num_noeud();
      if (nb<1 || nb > nbN)
     	{numerotation_correcte=false;
         break;
     	};
     };
   if (numerotation_correcte)  	
    {// on peut y aller sans vérif
     for  (il=li_noeud.begin();il!=ilfin;il++)
       tab_noeud((*il)->Num_noeud()) = *il;
    }
   else
    // on est obligé de changer la numérotation des noeuds
    {int nb=1;
     for  (il=li_noeud.begin();il!=ilfin;il++,nb++)
       {tab_noeud(nb) = *il;int nbinit=(*il)->Num_noeud();
        (*il)->Change_num_noeud(nb);
        if (ParaGlob::NiveauImpression() > 0)
          {cout << "\n warning : le numero initial du noeud " << nbinit << " est remplace par "
           		<< " le numero d'ordre attribue automatiquement par herezh " << nb
           		<< "\n seul ce dernier sera utilise par la suite ! " << endl;
           if (ParaGlob::NiveauImpression() > 5)
             cout << "\n  Maillage::Maillage (map < string, int ,.... " << endl;		
          };
       };
    };
   // récupération des éléments
   int nbE = li_element.size();
   list <Element* >::iterator ile,ilefin=li_element.end();
   Change_nb_element(nbE);
   // on vérifie que la numérotation est correcte pour les éléments (comme pour les noeuds)
   // c'est-à-dire que tous les numéros peuvent être rangés à suivre 
   numerotation_correcte = true;   
   for (ile=li_element.begin();ile!=ilefin;ile++)
     {int nb = (*ile)->Num_elt();
      if (nb<1 || nb > nbE)
     	{numerotation_correcte=false;
         break;
     	};
     };
   if (numerotation_correcte)  	
    {// on peut y aller sans vérif
     for (ile=li_element.begin();ile!=ilefin;ile++)
       tab_element((*ile)->Num_elt()) = *ile;
    }
   else
    // on est obligé de changer la numérotation des éléments
    {int nb=1;
     for (ile=li_element.begin();ile!=ilefin;ile++,nb++)
       {tab_element(nb) = *ile;int nbinit=(*ile)->Num_elt();
        (*ile)->Change_num_elt(nb);
        if (ParaGlob::NiveauImpression() > 0)
          {cout << "\n warning : le numero initial de l'element " << nbinit << " est remplace par "
           		<< " le numero d'ordre attribue automatiquement par herezh " << nb
           		<< "\n seul ce dernier sera utilise par la suite ! " << endl;
           if (ParaGlob::NiveauImpression() > 5)
             cout << "\n  Maillage::Maillage (map < string, int ,.... " << endl;		
          };
       };
    };
   // on modifie le numéro de maillage pour les noeuds et éléments
   int NBN_P1 = tab_noeud.Taille()+1;
   for (int nn=1;nn < NBN_P1;nn++)
     tab_noeud(nn)->Change_num_Mail(idmail);
   int NBE_P1 = tab_element.Taille()+1;
   for (int ne=1;ne < NBE_P1;ne++)
     tab_element(ne)->Change_num_maillage(idmail);
     
   if (ParaGlob::NiveauImpression() >= 5)
        cout << " \n fin creation du maillage: " << nom_maill << endl;
};

// Constructeur de copie, cependant ici il n'y a pas de création de noeud ni d'élément
// c'est seulement une création de nouveaux conteneurs de pointeurs 
// d'autre part le numéro de maillage et le nom de maillage n'est pas valide, il faut
// ensuite les définir
Maillage::Maillage (const Maillage& mail):
   listeNomMail(mail.listeNomMail),idmail(mail.idmail),nomDuMaillage(mail.nomDuMaillage),dimension(mail.dimension)
   ,tab_noeud(mail.tab_noeud),tab_element(mail.tab_element)
   ,listFrontiere(mail.listFrontiere),tab_noeud_front(mail.tab_noeud_front)
   ,indice(),indice_NFr(),list_refIn(),list_refOut(),lesRefin(NULL)
   ,mitoyen_de_chaque_element(mail.mitoyen_de_chaque_element)
   ,ddl_representatifs_des_physiques(mail.ddl_representatifs_des_physiques)
   ,types_de_problemes(mail.types_de_problemes)
   , ind_elem(),tab_sens_element() // tableaux internes utilisés par Orientation_elements_mitoyens_recursif
   ,detruire_les_noeuds_et_elements(true)
#ifdef UTILISATION_MPI
   ,buffer_ioBI_MPI(),offset_maillage(),les_taille_buffer_ioBI_MPI()
   ,les_taille_buffer_ioBI_MPI_inter()
#endif

  {	// tout d'abord on donne un nom par défaut au maillage
    nomDuMaillage = "pas_de_nom";  
    while  (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
      { // on cherche un nom quelconque qui n'est pas déjà utilisé
        nomDuMaillage += '_';      
      };
    // maintenant on associe le nom au numéro dans la map
    listeNomMail[nomDuMaillage]=idmail;
  };
		
// Constructeur de copie, avec création de nouveaux noeuds et éléments identiques à ceux passées
// en argument, nmail: donne le numéro du nouveau maillage créée, qui est donc a priori différent
// de celui de mail, idem pour le nom du maillage
// les frontières ne sont pas transmises ni calculées ! ni les normales,
// ni les infos concernant les intégrales (qui sont propres aux maillages existants)
Maillage::Maillage (map < string, int , std::less <string> > & lisNomMail
                    ,int nmail, const string& nomDu,const Maillage& mail):
   listeNomMail(lisNomMail),idmail(nmail),nomDuMaillage(nomDu),dimension(mail.dimension)
   ,tab_noeud(),tab_element(),listFrontiere(),tab_noeud_front()
   ,indice(),indice_NFr(),list_refIn(),list_refOut(),lesRefin(NULL)
   ,mitoyen_de_chaque_element()
   ,ddl_representatifs_des_physiques(mail.ddl_representatifs_des_physiques)
   ,types_de_problemes(mail.types_de_problemes)
   , ind_elem(),tab_sens_element() // tableaux internes utilisés par Orientation_elements_mitoyens_recursif
   ,detruire_les_noeuds_et_elements(true)
#ifdef UTILISATION_MPI
   ,buffer_ioBI_MPI(),offset_maillage(),les_taille_buffer_ioBI_MPI()
   ,les_taille_buffer_ioBI_MPI_inter()
#endif

{ // on vérifie que le nom de maillage fourni n'existe pas
  if (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
   { cout << "\n erreur, le nom de maillage demande existe deja : " << nomDuMaillage
          << "\n Maillage::Maillage (.....";
     Sortie(1);
   }; 
  // on vérifie que le numéro de maillage proposé est valide        
  if (idmail <=0)
	  {	cout << "\nErreur : numero de maillage invalide ! = "<< idmail <<"\n";
		   cout << "MAILLAGE::MAILLAGE(.... \n";
		   Sortie(1);
	  };
  // maintenant on associe le nom au numéro dans la map
  listeNomMail[nomDuMaillage]=idmail;
  // on s'occupe tout d'abord des noeuds
  int nbn = mail.tab_noeud.Taille();
  Change_nb_noeud(nbn);
  for (int ino=1;ino<= nbn;ino++)
    { tab_noeud(ino) = new Noeud(*(mail.tab_noeud(ino)));
      tab_noeud(ino)->Change_num_Mail(nmail);
     };
  // maintenant les éléments
  int nbe = mail.tab_element.Taille();
  Change_nb_element(nbe);
  for (int ie=1;ie<=nbe;ie++)
    { tab_element(ie) = mail.tab_element(ie)->Nevez_copie();
//debug
//tab_element(ie)->Affiche(1); cout << endl;
//fin debug
      // on réaffecte les noeuds du maillage
		    Tableau<Noeud *>& ttab = tab_element(ie)->Tab_noeud();  
      int ttabtaille=ttab.Taille();
      for (int ine=1;ine<=ttabtaille;ine++)
        ttab(ine)=tab_noeud(ttab(ine)->Num_noeud());
      // on change le numéro de maillage
      tab_element(ie)->Change_num_maillage(idmail); 
    };
  // dans le cas où mail.mitoyen_de_chaque_element n'est pas vide,
  // on construit le nouveau
  if (mail.mitoyen_de_chaque_element.Taille() != 0)
     Calcul_tous_les_front_et_leurs_mitoyens();    
};

Maillage::~Maillage()
// Destructeur
{  if ( detruire_les_noeuds_et_elements) // cas normal
    { for (int i=1;i<= tab_noeud.Taille();i++)
        delete tab_noeud(i);
      for (int i=1;i<= tab_element.Taille();i++)
        {delete tab_element(i);
        };
     };
   // pas de destruction de tab_noeud_front car ce sont des noeuds de tab_noeud, ils sont déjà détruit
 };


void   // lecture d'un maillage et def des references s'y rapportant
Maillage::LectureMaillage(UtilLecture * entreePrinc,LesReferences& lesRef)
{  if (ParaGlob::NiveauImpression() >= 5) cout << " debut de lecture de maillage "  << endl;
   if (ParaGlob::NiveauImpression() >= 6) cout << " lecture du nom de maillage "  << endl;
   // cas où il y a un nom de maillage
   if (strstr(entreePrinc->tablcar,"nom_maillage")!=NULL)
     {
//       // on commence par mettre à jour listeNomMail en supprimant le doublet nom <=> numéro existant
//       listeNomMail.erase(listeNomMail.find(nomDuMaillage));
// modif le 14 avril 2015
       // non c'est une mauvaise idée, il faut au contraire arrêter le programme et dire qu'il y a
       // deux fois le même nom, par contre si le nom de maillage c'est "pas_de_nom" il faut le supprimer
       if ((nomDuMaillage == "pas_de_nom") && (listeNomMail.find(nomDuMaillage) != listeNomMail.end()))
          listeNomMail.erase(listeNomMail.find(nomDuMaillage));
      
       string toto;
       *(entreePrinc->entree) >> toto >> nomDuMaillage;

       if (listeNomMail.find(nomDuMaillage) != listeNomMail.end())
         {cout << "\n erreur *** plusieurs maillages ont le meme nom : "<< nomDuMaillage
               << " \n revoir les noms de maillage !! " << endl;
          Sortie(1);
         };
       // maintenant on associe le nom au numéro dans la map
       listeNomMail[nomDuMaillage]=idmail;
       // ensuite lecture de l'entête des noeuds
       entreePrinc->NouvelleDonnee();
       if (strstr(entreePrinc->tablcar,"noeuds")==NULL)
         { cout << " *** erreur dans la lecture des noeuds " 
                << " \n LectureMaillage(...  " << endl;
           entreePrinc->MessageBuffer("** lecture de l'entete des noeuds **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         };
      }
   else 
   // on définit un nom apriori uniquement dans le cas d'un seul maillage
   // sinon c'est une erreur
       { if (idmail ==1)
           { // on commence par mettre à jour listeNomMail en supprimant le doublet nom <=> numéro existant
             listeNomMail.erase(listeNomMail.find(nomDuMaillage));
             nomDuMaillage  = "premier_maillage";
             // maintenant on associe le nom au numéro dans la map
             listeNomMail[nomDuMaillage]=idmail;
            } 
         else
           { cout << "\n Erreur dans la lecture du maillage " << idmail <<" ****** ";
             cout << "\n il n'y a pas de nom de maillage alors que c'est obligatoire !! " 
                  << " \n LectureMaillage(...  " << endl;
             entreePrinc->MessageBuffer("** lecture de l'entete des noeuds **");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie (1);
           };
       };

   //------------- lecture des noeuds -------------
    // lecture du nombre de noeud
   if (ParaGlob::NiveauImpression() >= 6) cout << " lecture des noeuds " << endl;   
   entreePrinc->NouvelleDonnee();
   if (ParaGlob::NiveauImpression() >= 8) cout << " lecture du nombre de noeud " << endl ; 
   int nbNoeud; // nombre de noeud
   *(entreePrinc->entree) >> nbNoeud; // lecture dans le flot memoire 
   if (ParaGlob::NiveauImpression() >= 8) cout << nbNoeud << endl ; 
   Change_nb_noeud(nbNoeud); // dimensionnement dynamique du tableau de noeud
   #ifdef ETUDIANT_LIMITATION
     if (nbNoeud > nb_maxi_noeud)
       { cout << "\n nombre maxi de noeud autorisé atteind " << nb_maxi_noeud;
         Sortie(1);
       };
   #endif       
   // lecture des noeuds
   Noeud * ptr; 
   for (int i=1; i<= nbNoeud; i++)
     { entreePrinc->NouvelleDonnee();
       ptr = new Noeud(i,dimension,idmail); // et attribution du numero de maillage
       if (ParaGlob::NiveauImpression() == 10) cout << "n:" << i << " " << flush ; 
       // lecture du noeud
       ptr->Lecture(entreePrinc);
       Affectation_noeud(*ptr);
     };
   // -------------- lecture des references se rapportant aux noeuds ---------
   entreePrinc->NouvelleDonnee();
   if (strstr(entreePrinc->tablcar,"elements")==NULL) 
     // cas où les références sont mises aprés les noeuds, dans ce cas c'est
     // des références de noeud
     { if (ParaGlob::NiveauImpression() >= 6) cout << " lecture des references de noeuds " << endl;   
       lesRef.Indic("noeud"); // indic que les prochaines references seront pour les noeuds
       lesRef.NbMaille(idmail); // indic le numéro de maillage aux références
       lesRef.Lecture(*entreePrinc);
      };

   // ------------ lecture des elements -----------
   // lecture du nombre d'element
   int nbElement=0; // nombre d'element null par défaut
   if (strstr(entreePrinc->tablcar,"elements")!=NULL) // cas avec element
      { if (ParaGlob::NiveauImpression() >= 6) cout << " lecture des elements du maillage " << endl ;   
        entreePrinc->NouvelleDonnee();
        if (ParaGlob::NiveauImpression() >= 8) cout << " lecture du nombre d'element " << endl ; 
        *(entreePrinc->entree) >> nbElement;
        if (ParaGlob::NiveauImpression() >= 8) cout << nbElement << endl ; 
        #ifdef ETUDIANT_LIMITATION
         if (nbElement > nb_maxi_element)
           { cout << "\n nombre maxi d'element autorise atteind " << nb_maxi_element;
             Sortie(1);
            };
        #endif       
        // dimensionnement dynamique du tableau d'elements 
        Change_nb_element(nbElement);
        // Lecture des elements
        Element * ptr;
        for (int i=1; i<= nbElement; i++)
         { // lecture geometrie et interpolation
           entreePrinc->NouvelleDonnee();
           if (ParaGlob::NiveauImpression() == 10) cout << "e:" << i << " " << flush ; 
           // def des énumérations de travail
           int num_elt = i; // numéro interne de l'élément
           int num_elt_lue; // numéro lue
           Enum_geom id_geom; Enum_interpol id_interpol;EnumElemTypeProblem  id_typeProb;
           // cas d'info annexe
           string str_precision(""); // stockage info annexe de choix, initié à rien par défaut
           // lectures des infos pour le choix d'un élément
           Lecture_info_1element(entreePrinc,num_elt_lue,id_geom,id_interpol,id_typeProb,str_precision);
           if (num_elt_lue != num_elt)
           	{ if (ParaGlob::NiveauImpression() > 0)
           		{cout << "\n warning : le numero de l'element lue  " << num_elt_lue << " est different du numero "
           		      << " d'ordre attribue automatiquement par herezh " << num_elt
           		      << "\n seul ce dernier sera utilise pour les resultats ! " << endl;
           		};
           	};
           // ======== choix de l'element =====================================
           // et affectation du 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
           ptr = Element::Choix_element(idmail,num_elt,id_geom,id_interpol,id_typeProb,str_precision);
           if (ptr == NULL)
             { // l'operation a echouee
               cout << "\n Erreur dans le choix d'element ****** ";
               cout << "\n l\'element : " << Nom_interpol(id_interpol) 
                    << " " << Nom_geom(id_geom)
                    << " n\'est pas present dans le programme ! " << endl;
               entreePrinc->MessageBuffer("** lecture d'un element **");
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie (1);
              };
           // lecture des infos particulieres a l'element
           Tableau<Noeud*> * pt = & tab_noeud;
           ptr->LectureDonneesParticulieres(entreePrinc,pt);
           Affectation_element(*ptr);
           // si c'est le premier élément du premier maillage on regarde s'il s'agit 
           // d'un élément axisymétrique et on adapte l'espace de travail en conséquence
           if ((i==1) && (idmail==1)) 
           	{ if (TestEnum_geom_axisymetrique(id_geom))
           		    ParaGlob::Change_en_AxiSymetrie();
           	}
           else
            {// dans le cas des autres éléments on vérifie qu'ils ne sont pas incohérent
             if (TestEnum_geom_axisymetrique(id_geom) != (ParaGlob::AxiSymetrie()))
             	{cout << "\n **** erreur en definition de l'element " << num_elt <<" du maillage " << idmail 
             	      << " nom= " <<  nomDuMaillage;
             	 if (ParaGlob::AxiSymetrie())     
             	 	cout << "\n incoherence : l'espace de travail n'est pas axisymetrique (definit par les precedents elements)"
             	 	      << " et l'element lu est axisymetrique !! ";      
             	 else
             	 	cout << "\n incoherence : l'espace de travail est axisymetrique (definit par les precedents elements)"
             	 	      << " et l'element lu n'est pas axisymetrique !! ";      
                 cout << endl;
                 Sortie (1);             		
             	};
            };	
         }
       }              
     else  
       { if (ParaGlob::NiveauImpression() >= 6)
            cout << " cas de la lecture d'un maillage SANS elements " << endl; // cas sans element
       };
  
  // -------------- lecture des references se rapportant aux elements ---------
  // ou aux arête ou aux faces et meme eventuellement à des noeuds
  if (ParaGlob::NiveauImpression() >= 6) cout << " lecture des references apres les elements " << endl ; 
  entreePrinc->NouvelleDonnee();
  lesRef.NbMaille(idmail); // indic le numéro de maillage aux références
  lesRef.Indic("rien_actuellement"); // indic que les prochaines references seront 
       // a déterminer en fonction du nom de la référence
  lesRef.Lecture(*entreePrinc);
  // -------------- ajout de références globales ---------------------
  // ----  création de la référence de tous les éléments si elle n'existe pas déjà
  string etout("E_tout");
  if (!lesRef.Existe(etout,idmail) && (nbElement != 0))
    { // on construit le tableau des numéros des éléments
      Tableau <int> tabE(nbElement); for (int i=1;i<=nbElement;i++) tabE(i)=i;          
      ReferenceNE*  retout = new ReferenceNE(tabE,idmail,2,etout);// construction de la référence
      lesRef.Ajout_reference(retout); // ajout de la ref, qui est maintenant géré par lesRef
    };
  // ----   dans tous les cas on ajoute la référence de tous les noeuds dans le cas où elle n'existe pas
  string ntout("N_tout");
  if (!lesRef.Existe(ntout,idmail))
    { // on construit le tableau des numéros de noeuds
      Tableau <int> tabN(nbNoeud); for (int i=1;i<=nbNoeud;i++) tabN(i)=i;          
      ReferenceNE*  rtout = new ReferenceNE(tabN,idmail,1,ntout);// construction de la référence
      lesRef.Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
    };
  if (ParaGlob::NiveauImpression() >= 5) cout << " fin lecture de maillage "  << endl;      
  // ----- on s'occupe maintenant de définir les types de pb gérés ------
  Mise_a_jour_type_pb_type_associe_ddl();
 
};
     
// lecture et application des opérations d'affinages sur le maillage: ex:déplacement solide
void Maillage::LectureEtApplicationAffinage(UtilLecture * entreePrinc,LesReferences& lesRef)
{
  if (ParaGlob::NiveauImpression() >= 5) cout << " lecture affinage maillage "  << endl;

  while (    (strstr(entreePrinc->tablcar,"def_mouvement_solide_initiaux_")!=NULL)
          || (strstr(entreePrinc->tablcar,"suppression_noeud_non_references_")!=NULL)
          || (strstr(entreePrinc->tablcar,"creation_ref_noeud_non_references_")!=NULL)
          || (strstr(entreePrinc->tablcar,"fusion_noeuds_proches_")!=NULL)
          || (strstr(entreePrinc->tablcar,"fusion_elements_superposes_")!=NULL)
          || (strstr(entreePrinc->tablcar,"suppression_elements_2noeuds_tres_proches_")!=NULL)
          || (strstr(entreePrinc->tablcar,"def_auto_ref_frontiere_")!=NULL)
          || (strstr(entreePrinc->tablcar,"renumerotation_des_noeuds_")!=NULL)
        )
      {
         // -------------- lecture éventuelle et application de mouvements rigides ------------------ 
         Lecture_des_mouvements_solides(entreePrinc);
  
         // --------------- suppression éventuelle des noeuds, non référencés par les éléments ------
         LectureEtSuppressionNoeudNonReferencer(entreePrinc,lesRef);

         // --------------- création éventuelle d'une référence sur les noeuds, non référencés par les éléments ------
         LectureEtCreationRefNoeudNonReferencer(entreePrinc,lesRef);
 
         // --------------- éventuellement collapse de noeuds proches ------------------------
         LectureEtCollapse_noeuds_proches(entreePrinc,&lesRef);
 
         // --------------- éventuellement collapse d'éléments supperposés -------------------
         LectureEtCollapse_element_superpose(entreePrinc,&lesRef);
       
         // -------------- éventuellement suppression  d'elements à 2 noeuds, de distances très proches
         LectureEtSup_Elem_noeudsConfondu(entreePrinc,&lesRef);
       
         //---------------- création automatique des références globales de frontière si demandé ----------
         CreationRefFrontiere(entreePrinc,lesRef);

//----- debug
//{  // on écrit la connection de l'élément 55
//  Element* el = tab_element(55);
//  const Tableau<Noeud *>& tabi = el->Tab_noeud_const();
//  cout << "\n *** connection de l'element 55: avant renumerotation ";
//  for (int i=1;i<=tabi.Taille();i++) cout << " "<<tabi(i)->Num_noeud();
//  cout << " Maillage::LectureMaillage () " << endl;
//}
//---fin debug
         // --------------- renumérotation éventuelle des noeuds ------------------------------------
         LectureEtRenumerotation(entreePrinc,lesRef);
////----- debug
//{  // on écrit la connection de l'élément 55
//  Element* el = tab_element(55);
//  const Tableau<Noeud *>& tabi = el->Tab_noeud_const();
//  cout << "\n *** connection de l'element 55: après renumerotation ";
//  for (int i=1;i<=tabi.Taille();i++) cout << " "<<tabi(i)->Num_noeud();
//  cout << " Maillage::LectureMaillage () " << endl;
//  Sortie(1);
//}
////---fin debug
      };
  
  // ----------------- vérification que toutes les références de noeuds, d'éléments, d'arêtes et de faces sont valides
  //                c-a-d se réfèrent à des éléments existants
  VerifReference(lesRef);
     
  if (ParaGlob::NiveauImpression() >= 5) cout << " fin lecture affinage maillage "  << endl;      
};
    
// affichage et definition interactive des commandes 
// cas = 1: interactif complet
// cas = 2: entrée uniquement de noms de fichier
// cas = 3: entrée uniquement de l'affinage
void Maillage::Info_commande_Maillages(UtilLecture * entreePrinc,LesReferences& lesRef, int cas)
{  ofstream & sort = *(entreePrinc->Commande_pointInfo()); // pour simplifier
	  string rep="o";
   if (cas == 2)
	   { cout << "\n# voulez-vous inclure un fichier ou continuer sur un exemple (rep o  ou ? ou f) ? ";
	     rep = lect_return_defaut(false,"f");
    };
  
	  if (((rep == "o") || (rep == "O") ||(rep == "0")) && (cas != 3))
	  { cout << "\n non du fichier .her (sans l'extension .her) a inclure ? ";
     rep = lect_chaine();
     sort << "\n\n # -- def maillage ";
		   sort << "\n < " << (rep+".her") ;
     cout << "\n un fichier .lis a inclure ? (o ou n (defaut)) ";
     rep = lect_return_defaut(false,"n");
     if (rep == "o")
      { cout << "\n non du fichier .lis (sans l'extension .lis) a inclure ? ";
        rep = lect_chaine();
		      sort << "\n < " << (rep+".lis") ;
      };
	  }
	  else if ((rep == "?") && (cas != 3))
	  { // sinon on continue sur un exemple de maillage
      sort << "\n # -- defintion du nom du maillage (facultatif pour le premier maillage "
        << "\n # -- qui s'appel par defaut : premier_maillage)"
        << "\n"
        << "\n nom_maillage plaque_troue     # exemple de nom de maillage"
        << "\n           noeuds ------------ # definition des noeuds";

      //------------- definition des noeuds -------------
      int dimen = ParaGlob::Dimension();
      #ifdef SYSTEM_MAC_OS_CARBON
		    int nbNoeud = pow(3,dimen); // nombre de noeud de l'exemple
      #else  
      int nbNoeud = ((int)pow((float)3,(int)dimen)); // nombre de noeud de l'exemple
      #endif  

      sort << "\n            "<< nbNoeud << "  NOEUDS         # definition du nombre de noeud"
           << "\n \n" 
           << "\n#---------------------------------------------------------------"
           << "\n#|NO DU|        X         |        Y         |          Z      |"
           << "\n#|NOEUD|                  |                  |                 |"
           << "\n#---------------------------------------------------------------";
        
      Change_nb_noeud(nbNoeud); // dimensionnement dynamique du tableau de noeud
      // définition d'une grille  générique de noeuds qui permettra de définir les éléments générique
      Tableau <Coordonnee*> tab_coo(nbNoeud);
      switch (dimen)
      { case 1:
         { for (int i=1;i<=3;i++) tab_coo(i) = new Coordonnee((double) i); break;}
        case 2:
         { int l=1; for (int i=1;i<=3;i++) for (int j=1;j<=3;j++,l++)
           tab_coo(l) = new Coordonnee((double) i,(double) j); break;}  
		      case 3:
         { int l=1; for (int i=1;i<=3;i++) for (int j=1;j<=3;j++) for (int k=1;k<=3;k++,l++)
           tab_coo(l) = new Coordonnee((double) i,(double) j,(double) k); break;} 
       };       
      // def des noeuds
      Noeud * ptr; 
      for (int i=1; i<= nbNoeud; i++)
      { ptr = new Noeud(i,dimension,1); // et attribution du numero de maillage
        // def du noeud
        ptr->Info_commande_Noeud(entreePrinc,*tab_coo(i),i);
        Affectation_noeud(*ptr);
      };
     
      // -------------- def d'exemples de references se rapportant aux noeuds ---------
      sort << "\n#     --- reference de noeuds ce trouvant apres la definition des noeuds ---"
           << "\n#    ( il est possible aussi de definir des references de noeud apres "
           << "\n#      la definition des elements)  "
           << "\n#   NB: !! une reference de noeud doit commencer par N suivi d'une chaine de caracteres \n"; 
      lesRef.Indic("noeud"); // indic que les prochaines references seront pour les noeuds
      lesRef.NbMaille(idmail); // indic le numéro de maillage aux références
      lesRef.Info_commande_lesRef(nbNoeud,0,entreePrinc,1); // def d'exemple des divers refs de noeuds

      // ------------ def d'exemple d'elements -----------
   
      int nbElement = 0; // nombre d'element
      bool choix_valide=false;  
      // affichage des types d'élément actuellement disponible selon la dimension
      // creation d'un tableau d'éléments
      Tableau <Element *> tab_el = Element::Info_commande_Element(entreePrinc);
      int nbele = tab_el.Taille(); 
      Tableau <bool> chooi(nbele,false); // tableau de travail
      cout << "\n Donner le type d'element que vous souhaitez utiliser: ?  ";
      string rep;int num;
      while (!choix_valide)
      {
       try 
       { // affichage des éléments possibles
        // on balaie le tableau des elements enregistre
        int undeux=0;
        cout << "\n (0) fin \n";
        for (int i=1;i<=nbele;i++)
         { cout << " (" << i << ") " << tab_el(i)->Geometrie() <<" "<< tab_el(i)->Interpolation()
                <<"  ";
           undeux++;
           if (undeux==2) {cout << "\n";undeux=0;}
          };
        rep = lect_return_defaut(false,"0");
        if (rep == "fin_prog") Sortie(1);
        num = ChangeEntier(rep);  
        choix_valide=false;  
        if (num == 0) 
         { choix_valide=true;}
        else // sinon
         { if ((num > 0)&&(num<=nbele)) 
            {if (chooi(num))
               cout << "\n type d'element deja choisit, recommencer";
             else    
              chooi(num) = true;
            }
           else { cout << "\n Erreur on attendait un entier entre 0 et "<< nbele <<" !!, "
                       << "\n redonnez une bonne valeur"
                       << "\n ou taper fin_prog pour arreter le programme"; 
                }
          }      
        }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
       {   cout << "\n Erreur on attendait un entier entre 0 et "<< nbele <<" !!, "
                    << "\n redonnez une bonne valeur"
                      << "\n ou taper fin_prog pour arreter le programme"; 
			  choix_valide=false;
        }
       } //-- fin du while 
      // on definit le maillage d'essai
      // 1- def du nombre d'élément
      int ielmax=0;
      for (int ie=1;ie<=nbele;ie++)
      if (chooi(ie)) ielmax++;
      Change_nb_element(ielmax);
      // 2- remplissage du tableau d'élément
      int iel=1;  
      for (int ie=1;ie<=nbele;ie++)
        if (chooi(ie)) 
         {tab_element(iel)=tab_el(ie); 
          tab_element(iel)->Change_num_elt(iel);
          tab_el(ie)=NULL;
          iel++;
          }
      //  on affiche les éléments
      sort << "\n # les elements \n"
            << "\n elements ----------";
      sort << "\n    " << ielmax << "  ELEMENTS";

      sort << "\n #----------------------------------------------------------------------";
      sort << "\n #| NO  |                           |                                  |";
      sort << "\n #|ELTS |     type element          |       Noeuds                     |";
      sort << "\n #----------------------------------------------------------------------";
      string ord= "commande";
      Tableau<Noeud*> * pt = & tab_noeud;
      for (int i=1;i<=ielmax;i++)
        tab_element(i)->Info_com_Element(entreePrinc,ord,pt);
      sort << "\n \n" ;  

      // -------------- def des references se rapportant aux elements ---------
      // ou aux arête ou aux faces et meme eventuellement à des noeuds
      sort << "\n#     --- reference  ce trouvant apres la definition des elements ---"
           << "\n#   NB: !! une reference de noeud doit commencer par N suivi d'une chaine de caracteres "
           << "\n#   une reference d'element commence par E suivi d'une chaine de caracteres "
           << "\n#   une reference de face commence par F et une reference d'arrete commence par A  \n"; 
        
      lesRef.NbMaille(idmail); // indic le numéro de maillage aux références
      lesRef.Info_commande_lesRef(nbNoeud,ielmax,entreePrinc,2); // def d'exemple des divers refs de noeuds
  
      // effacement des éléments qui ne servent plus
      for (int i=1;i<=ielmax;i++)
        if (tab_el(i) != NULL) delete tab_el(i);
	}; // fin de l'exemple de maillage	   
     
   // ---------- définition des affinages éventuelles ---------- 
// while (    (strstr(entreePrinc->tablcar,"def_mouvement_solide_initiaux_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"suppression_noeud_non_references_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"creation_ref_noeud_non_references_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"fusion_noeuds_proches_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"fusion_elements_superposes_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"suppression_elements_2noeuds_tres_proches_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"def_auto_ref_frontiere_")!=NULL)
//          || (strstr(entreePrinc->tablcar,"renumerotation_des_noeuds_")!=NULL)
   //On va proposer un menu
   while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
      {
       try 
        { 
        cout 
           << "\n (0 ou f defaut)  (fin)               "
           << "\n (1)  mouvement solide     "
           << "\n (2)  suppression des noeuds non reference "              
           << "\n (3)  collapse de noeuds proches "
           << "\n (4)  collapse d'elements superposes "
           << "\n (5)  creation de references frontieres " 
           << "\n (6)  renumerotation "
           << "\n (7)  creation d'une ref sur les noeuds non references "
           << "\n (8)  suppression des petits elements a 2 ou 3 noeuds 2D "
           << "\n (9 ou ? ) informations  "
           << "\n  ";
        rep = lect_return_defaut(false,"f");
        if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
          break;
        int num = ChangeEntier(rep);
        if (Minuscules(rep) == "?")
          num = 9;
        bool choix_valide=false;
        if ((num >= 0)&&(num<=9))
             { choix_valide=true; }
        else { cout << "\n Erreur on attendait un entier entre 0 et 9 !!, "
                    << "\n redonnez une bonne valeur"
                    << "\n ou taper f ou 0 pour arreter le programme"; 
               choix_valide=false;
             }
        switch (num)
         { case 0:  // sortie
             { break;} // normalement cela a déjà été filtré avant
           case 1:  // mouvement solide
             { MvtSolide mvt; // un mouvement par défaut
               sort << "\n\n def_mouvement_solide_initiaux_ \n";
               mvt.Info_commande_MvtSolide(sort);
               break;}
           case 2:  // suppression des noeuds non reference
             { sort << "\n suppression_noeud_non_references_ ";
               break;}
           case 3:  // collapse de noeuds proches
             { sort << "\n fusion_noeuds_proches_ ";
               cout << "\n donner la distance en dessous de laquelle on fusionne (un reel) ? ";
               double rayon=0.;
               rayon = lect_double(); cout << " valeur lue "<< rayon;
               sort << rayon << " ";
               break;}
           case 4:  // collapse d'elements superposes
             { sort << "\n fusion_elements_superposes_ ";
               break;}
           case 5:  // creation de references frontieres
             { sort << "\n def_auto_ref_frontiere_ ";
               break;}
           case 6:  // creation de references frontieres
             { sort << "\n renumerotation_des_noeuds_ ";
               break;}
           case 7:  // creation d'une ref sur les noeuds non reference
             { sort << "\n creation_ref_noeud_non_references_ ";
               break;}
           case 8:  // suppression des petits elements a 2 ou 3 noeuds 2D
             { sort << "\n suppression_elements_2noeuds_tres_proches_ ";
               cout << "\n donner la distance entre deux noeuds de l'element en dessous de laquelle on supprime (un reel) ? ";
               double rayon=0.;
               rayon = lect_double(); cout << " valeur lue "<< rayon;
               sort << rayon << " ";
               break;}
           case 9:  // informations
             { cout << "\n en dehors de la signification intuitive des differents ordres"
                    << " pour des informations plus precise il est preferable de se rapporter a la documentation "
                    << " d'Herezh++, car c'est differents ordres recouvrent des procedures difficiles a "
                    << " decrire en quelques lignes. ";
               break;}
           default:
             cout << "\n le cas "<<rep<<" n'est pas encore traite !!, mais cela devrait ce faire sans tarder ";
          };
        }    
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots clés proposés !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
      }; //-- fin du while
          
};
		

// Affiche l'ensemble des donnees du maillage
void Maillage::Affiche () const
{cout << "\n\t\t*** DONNEES DU MAILLAGE ***\n\n";
	cout << "\n nom du maillage : " << nomDuMaillage << " , ";
	cout << "Dimension : " << dimension << "\n";
 // les types de problèmes associés
// {list <EnumElemTypeProblem>::const_iterator il,ilfin=types_de_problemes.end();
//  cout <<"\n types_de_problemes: " << types_de_problemes.size() ;
//  for (il=types_de_problemes.begin();il != ilfin;il++)
//     NomElemTypeProblem(*il);
// };
 {int tail = types_de_problemes.Taille();
  cout <<"\n types_de_problemes: " << tail ;
  for (int i=1;i<=tail;i++)
    cout << " "<< NomElemTypeProblem(types_de_problemes(i));
 };

// // les ddl associés
// {list <Enum_ddl>::const_iterator il,ilfin=ddl_representatifs_des_physiques.end();
//  cout <<"\n type_de_ddl_associes: " << ddl_representatifs_des_physiques.size();
//  for (il=ddl_representatifs_des_physiques.begin();il != ilfin;il++)
//     Nom_ddl(*il);
// };
 {int tail = ddl_representatifs_des_physiques.Taille();
  cout <<"\n type_de_ddl_associes: " << tail;
  for (int i=1;i<=tail;i++)
    cout << " "<< Nom_ddl(ddl_representatifs_des_physiques(i));
 };
 
 //	cout << "Nombre de degres de liberte : " << Nombre_ddl() << "\n";
	cout << "Nombre de noeuds : " << Nombre_noeud() << "\n";
	cout << "Nombre d'elements : " << Nombre_element() << "\n\n";
	for (int i=1;i<=Nombre_noeud();i++)
	// boucle sur les noeuds
	{
		cout << "\nNoeud " << i << " :\n";
		tab_noeud(i)->Affiche();
	};
	cout << "\n";
	for (int i=1;i<=Nombre_element();i++) 
	// boucle sur les elements
	{
		cout << "\nElement " << i << " :\n"; 
		tab_element(i)->Affiche(ParaGlob::NiveauImpression());
	};
	cout << "\n"; 
	// renseignement concernant les frontières
 int nbmaxiElement = (int) listFrontiere.size();
 cout << "nombre d'element frontiere : " << nbmaxiElement;
 cout << "liste : \n";
 LaLIST <Front>::const_iterator ip;int ne;
 for (ne=1,ip = listFrontiere.begin();ip != listFrontiere.end(); ip++,ne++)
     { // écriture de l'élément courant
       cout << ne << "  " ;  // le numéro
       const ElemGeomC0 & geom = (*ip).Eleme()->ElementGeometrique();
       cout << Nom_geom(geom.TypeGeometrie()) << "  " ; // la géométrie
       cout << Nom_interpol(geom.TypeInterpolation()) << "  " ; // l'interpolation
       // les noeuds
       Tableau <Noeud *> tabnoeud = (*ip).Eleme()->TabNoeud();
       int taille = tabnoeud.Taille();
       for (int ine = 1; ine<=taille; ine++)
         cout << tabnoeud(ine)->Num_noeud() << " ";
       cout << "\n";
     };
	// la liste des noeuds de la frontières, on ne sort que les numéros
	cout << " \n liste des numeros de noeud de la frontiere"; 
	int taal = tab_noeud_front.Taille();
	for (int i=1;i<= taal;i++)
	  cout << tab_noeud_front(i)->Num_noeud() << " ";
	cout << "\n";	
};

/*void
Maillage::Affiche (char* nom_fichier)
// Affiche les donnees du maillage dans le fichier nom_fichier
// au format du fichier d'entree ".her"
{
	FILE* fichier;
	// ouverture du fichier nom_fichier
	if ( (fichier=fopen(nom_fichier,"w"))==NULL )
	{
		cout << "ERREUR D'OUVERTURE DU FICHIER :"; 
		cout << nom_fichier << "\n";
		Sortie(1);
	};
	fprintf(fichier,"\n nom_maillage ",nomDuMaillage.c_str());
	fprintf(fichier,"\n\nnoeuds --------\n\n");
	fprintf(fichier,"\t\t%d NOEUDS\n\n",Nombre_noeud());
	// affichage des noeuds :
	switch (dimension)
	{
		case 1 : // cas unidimensionnel
			for (int i=1;i<=Nombre_noeud();i++)
			{
				fprintf(fichier,"\t%d\t%lf\n",Noeud_mail(i).Num_noeud(),
											Noeud_mail(i).Coord0()(1));
			};
			break;
		case 2 : // cas bidimensionnel
			for (int i=1;i<=Nombre_noeud();i++)
			{
				fprintf(fichier,"\t%d\t\t",Noeud_mail(i).Num_noeud());
				fprintf(fichier,"%lf\t%lf\n",Noeud_mail(i).Coord0()(1),
											Noeud_mail(i).Coord0()(2));
			};
			break;
		case 3 : // cas tridimensionnel
			for (int i=1;i<=Nombre_noeud();i++)
			{
				fprintf(fichier,"\t%d\t\t",Noeud_mail(i).Num_noeud());
				fprintf(fichier,"%lf\t%lf\t%lf\n",Noeud_mail(i).Coord0()(1),
						Noeud_mail(i).Coord0()(2),Noeud_mail(i).Coord0()(3));
			};
			break;
		default :
			cout << "Erreur de dimension\n";
			cout << "MAILLAGE::AFFICHE(char* ) \n";
			Sortie(1);
	};
	fprintf(fichier,"\n\nelements --------\n\n");
	fprintf(fichier,"\t\t%d ELEMENTS\n\n",Nombre_element());
	// affichage des elements
	for (int i=1;i<=Nombre_element();i++)
	{
		fprintf(fichier,"\t%d\t",Element_mail(i).Num_elt());
		fprintf(fichier,"%s\t%s\t\t",Element_mail(i).Geometrie(),
								Element_mail(i).Interpolation());
		for (int j=1;j<=Element_mail(i).Nombre_noeud();j++)
			fprintf(fichier,"%d\t",Element_mail(i).Num_noeud(j));
		fprintf(fichier,"\n");
	};
	fprintf(fichier,"\n\n");
	
};
*/	

Maillage& 
Maillage::operator= (Maillage& mail)
// Surcharge de l'operateur = : realise l'egalite entre deux maillages
// cependant le numéro de maillage et le nom de maillage n'est pas valide, il faut
// ensuite les définir
{   dimension=mail.dimension;
    //nomDuMaillage = mail.nomDuMaillage;
    tab_noeud=mail.tab_noeud;
    tab_element=mail.tab_element;
    listFrontiere=mail.listFrontiere;
    tab_noeud_front = mail.tab_noeud_front;
    ddl_representatifs_des_physiques = mail.ddl_representatifs_des_physiques;
    types_de_problemes = mail.types_de_problemes;
    return (*this);
};

// test si toutes les informations des maillages sont completes
// = true -> complet
// = false -> incomplet
bool Maillage::Complet()
  { bool res = true;
    int tab_noeudTaille = tab_noeud.Taille();
    for ( int i=1; i<= tab_noeudTaille;i++)
      { // res = res && tab_noeud(i)->TestComplet();
        if(!(tab_noeud(i)->TestComplet()))
          { cout << " \n pb au niveau du test  du noeud " << tab_noeud(i)->Num_noeud();
            res = false;
          };
       };
    int tab_elemTaille = tab_element.Taille();  
    for ( int i=1; i<= tab_elemTaille;i++)
      {//res = res && tab_element(i)->TestComplet(); 
       if(!(tab_element(i)->TestComplet()))
         {cout << "\n pb au niveau du test de l'element " << tab_element(i)->Num_elt();
          res = false;
         };
      };
    // les parties frontières ne sont pas obligatoires        
    return res;
  };
	    
// ramene la demi largeur de bande en ddl et la largeur de bande
void Maillage::Largeur_Bande(int& demi, int& total,const Nb_assemb& casAss)
  {  demi = 0;
     int nb_ass = casAss.n;
     int tab_elemTaille = tab_element.Taille();  
     for (int ne=1;ne<=tab_elemTaille;ne++)
       {int tab_eleNbNoeud = tab_element(ne)->Nombre_noeud();
        for (int noe=1; noe<= tab_eleNbNoeud;noe++)
//  bug, voic remarque qui suit         for ( int no=noe+1; no<=tab_eleNbNoeud;no++)
           // l'idée est bonne de commencer à noe+1, mais en fait lorsque l'on a un seul noeud, cela conduit
			  // a avoir une largeur de bande nulle, donc il faut commencer à noe, et dans ce cas c'est ok
			  // mais pour les éléments avec plus d'un noeud, on a une boucle supp
           for ( int no=noe; no<=tab_eleNbNoeud;no++)
            { Noeud & nne = tab_element(ne)->Noeud_elt(noe);
              Noeud & nno = tab_element(ne)->Noeud_elt(no);
              int di;
              if (nne.PosiAssemb(nb_ass) >= nno.PosiAssemb(nb_ass))
                 di = nne.PosiAssemb(nb_ass) - nno.PosiAssemb(nb_ass) 
                      + nne.NB_ddl_actif_casAssemb(nb_ass);
              else
                 di = nno.PosiAssemb(nb_ass) - nne.PosiAssemb(nb_ass) 
                       + nno.NB_ddl_actif_casAssemb(nb_ass);   
              if ( di > demi)  demi = di;
            };
         };
     total = demi * 2 -1;
     demi = demi;  
  };

// test pour savoir si tous les coordonnées des noeuds d'un maillage sont imposé
// ramène 1 si tout est fixé, 0 sinon
int Maillage::Tous_Xi_fixes(const Nb_assemb& casAss) const
  {  int retour = 1;
     int nb_ass = casAss.n;
     // on va parcourir les noeuds
     int tab_noeud_taille= tab_noeud.Taille();
     int dim = ParaGlob::Dimension();
     switch(dim)
       {case 3:
          {for (int i=1;i<=tab_noeud_taille;i++)
            { Noeud& noe = *tab_noeud(i); // pour simplifier
              if (!( noe.Ddl_fixe(X3) && noe.Ddl_fixe(X2) && noe.Ddl_fixe(X1)))
                {retour=0; break;};
            };
           break;
          }
        case 2:
          {for (int i=1;i<=tab_noeud_taille;i++)
            { Noeud& noe = *tab_noeud(i); // pour simplifier
              if (!( noe.Ddl_fixe(X2) && noe.Ddl_fixe(X1)))
                {retour=0; break;};
            };
           break;
          }
        case 1:
          {for (int i=1;i<=tab_noeud_taille;i++)
            { Noeud& noe = *tab_noeud(i); // pour simplifier
              if (!( noe.Ddl_fixe(X1)))
                {retour=0; break;};
            };
           break;
          }
       };
//  --- idem mais plus long a priori car contient un switch
//     for (int i=1;i<=tab_noeud_taille;i++)
//       { Noeud& noe = *tab_noeud(i); // pour simplifier
//         switch(dim)
//          {case 3:  if (!(noe.Ddl_fixe(X3))) {retour=0; break;};
//           case 2:  if (!(noe.Ddl_fixe(X2))) {retour=0; break;};
//           case 1:  if (!(noe.Ddl_fixe(X1))) {retour=0; break;};
//          };
//         if (!retour) break;
//       };
     return retour;
  };

// création pour chaque noeud de la liste des éléments qui contiennent le noeud
void Maillage::Calcul_indice()
{   //  création du tableau indice : pour chaque noeud on regarde quel élément contiend ce noeud
/// les 3/ sont pour la version vector qui marche bien aussi     
///    vector <vector <Element*> > indice(tab_noeud.Taille());
    int tab_noeud_taille= tab_noeud.Taille();
    indice.Change_taille(tab_noeud_taille);
    // au cas où le tableau existait auparavant on initialise les éléments du tableau
    for (int i=1;i<= tab_noeud_taille;i++)
      indice(i).clear();
    // maintenant on passe en revue les éléments
    int tabelTaille = tab_element.Taille();
    // indice(i) contiend les numéros d'élément contenant le noeud i
    for (int i22 = 1; i22 <= tabelTaille; i22++)
       { Element * elem1 = tab_element(i22); // recup de l'element
         // récup de son tableau de noeud
         Tableau<Noeud *>& tabn = elem1->Tab_noeud();
         int tabntaille = tabn.Taille();
         for (int ij=1;ij<= tabntaille;ij++)
           {// on balaie ses noeuds  
///            indice[(tabn(ij)->Num_noeud())-1].push_back(elem1);
            indice((tabn(ij)->Num_noeud())).push_back(elem1);
           };
       };
	   // on supprime les doublons
	   for (int i=1;i<=tab_noeud_taille;i++)
	     { list<Element*>& intertab = indice(i); // pour allèger l'écriture
		      intertab.sort(); // on ordonne
			     intertab.unique(); // on supprime les doublons
/*//-- debug
//{cout << "\n noeud " << i << " taille indice(i) " << intertab.size() ;
// list<Element*>::iterator ina,infin;
// infin = intertab.end();
// for (ina = intertab.begin();ina!=infin;ina++)
//  {Element * elem2 = *ina; // recup de l'element
//	cout << " element " << elem2->Num_elt() << " ";
//	};
// cout << "\n";
// };
//-- debug
//{cout << "\n debug ** Maillage::Calcul_indice() ";
// int numnoeud = 104;
// list<Element*>& intertab = indice(numnoeud);
// list<Element*>::iterator ina,infin;
// infin = intertab.end();
// for (ina = intertab.begin();ina!=infin;ina++)
//  {Element * elem2 = *ina; // recup de l'element
//	  cout << " element-- " << elem2->Num_elt() << " ";
//  };
// cout << "\n"<<endl ;
//};
//--fin debug*/
			   }; 

};

// création pour chaque noeud de la liste des éléments frontières qui contiennent le noeud
void Maillage::Calcul_indice_NFr()
{ // le tableau indice_NFr (indice des noeuds frontières) va permettre une recherche plus rapide
  //  on le construit:
  int tab_noeud_taille= tab_noeud.Taille();
  indice_NFr.Change_taille(tab_noeud_taille);
  // au cas où le tableau existait auparavant on initialise les éléments du tableau
  for (int i=1;i<= tab_noeud_taille;i++)
    indice_NFr(i).clear();

  // indice_NFr contiend les front succeptible d'avoir des frontières géométriques communes
  LaLIST <Front>::iterator iF;
  LaLIST <Front>::iterator iFfin = listFrontiere.end();
  for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      ElFrontiere * efem1 = fro->Eleme(); // recup de l'element géométrique qui a créé la frontière
      // récup de son tableau de noeud
      Tableau<Noeud *>& tabn = efem1->TabNoeud();
      int tabntaille = tabn.Taille();
      for (int ij=1;ij<= tabntaille;ij++)
          // on balaie ses noeuds
           indice_NFr((tabn(ij)->Num_noeud())).push_back(fro);
    };
  // on supprime les doublons
  for (int i=1;i<=tab_noeud_taille;i++)
    { List_io <Front*>& intertab = indice_NFr(i); // pour allèger l'écriture
      intertab.sort(); // on ordonne
      intertab.unique(); // on supprime les doublons
    };
};


// calcule des normales aux noeuds: dans le cas d'éléments finis 1D ou 2D
// et aussi pour les frontières (qui sont normalement de type 1D ou 2D)
// a priori le calcul s'effectue par une moyenne des normales des éléments qui
// entourent le noeud.
// init -> calcul des normales à t=0
//         et ajout conteneur aux noeuds des normales à t = 0 et t
//         init par défaut des valeurs à t == celle à t=0
void Maillage::InitNormaleAuxNoeuds()
 { // on va parcourir les noeuds et on n'intervient que si le noeud
   // appartient à un élément 1D et/ou 2D
   int nbNoeud = tab_noeud.Taille();
   int dima = ParaGlob::Dimension();
   int borne_max_nbNoeud = nbNoeud+1;
   Coordonnee coor_inter; //  coordonnée de travail
   Coordonnee premiere_normale;// idem
   {
    Grandeur_coordonnee grandCoordonnee_0(ParaGlob::Dimension()); // un type courant
    TypeQuelconque typQ4_0(NN_SURF_t0,EPS11,grandCoordonnee_0);
    Grandeur_coordonnee grandCoordonnee_t(ParaGlob::Dimension()); // un type courant
    TypeQuelconque typQ4_t(NN_SURF_t,EPS11,grandCoordonnee_t);

    // on commence  par ajouter les conteneurs
    // on  fait un conteneur particulier pour  tous  les  noeuds,  donc 2 boucles
    // car cela permet d'optimiser l'utilisation de la  méthode  AjoutUnTypeQuelconque de Noeud
    
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
      {// on regarde si le conteneur de la normale existe au noeud et création éventuelle
       Noeud & noe = *tab_noeud(ine); // pour simplifier
       if (!noe.Existe_ici(NN_SURF_t0))
         noe.AjoutUnTypeQuelconque(typQ4_0);
      };
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
      {// on regarde si le conteneur de la normale existe au noeud et création éventuelle
       Noeud & noe = *tab_noeud(ine); // pour simplifier
       if (!noe.Existe_ici(NN_SURF_t))
         noe.AjoutUnTypeQuelconque(typQ4_t);
      };

    // maintenant on s'occupe du  contenu
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
      {Noeud & noe = *tab_noeud(ine); // pour simplifier
       
       // on récupère le  conteneur de la normale
       TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(NN_SURF_t0);
       Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
       Coordonnee& normale = *gr.ConteneurCoordonnee();
       normale.Zero(); // init
       // calcul éventuel du tableau Indice
       this->Indice();

       List_io < Element*>& li_elem = indice(ine);// la liste des éléments qui contiennent le noeud
       List_io < Element*>::iterator il,ilfin = li_elem.end();
       // on balaie les éléments
       int nb_normale=0; // le nombre de normales trouvées
       for (il = li_elem.begin(); il != ilfin; il++)
        {Element& elem = *(*il);
         Enum_type_geom enutygeom =  Type_geom_generique(elem.Id_geometrie());
 //        if ((enutygeom == LIGNE) || (enutygeom == SURFACE))
         if ((enutygeom == SURFACE) // dans une première étape on ne s'occupe que des surfaces en 3D
              && (dima == 3) // si surface en 2D, ce sera les éléments frontières qui détermineront les normales
            )
          {int cas = elem.CalculNormale_noeud(TEMPS_0,*tab_noeud(ine),coor_inter);
           if (cas == 0)
            {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
                  << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
                  << " du maillage " << tab_noeud(ine)->Num_Mail()
                  << " par rapport  a l'element "<< elem.Num_elt()
                  << " du maillage " << elem.Num_maillage()
                  << "\n Maillage::MiseAjourNormaleAuxNoeuds() ";
             Sortie(1);
            }
           else if (cas == 2)
            {// le calcul n'est pas licite, mais ce n'est pas une erreur
             // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
            }
           else // sinon c'est ok
            {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
             // conduire à une somme nulle, pour éviter cela, on regarde le produit scalaire
             // s'il est négatif on utilise l'inverse de la normale
             // donc en définitif on gardera globalement la direction précédente
             if ((normale * coor_inter) > 0.)
               {normale += coor_inter;}
             else
               {normale -= coor_inter;};
             nb_normale++;
            };
          };
        };
       if (nb_normale != 0)
         {normale /= nb_normale;
          // enfin on normalise la normale
 ////------ debug
 //if (normale.Norme() == 0.)
 // {
 //       for (il = li_elem.begin(); il != ilfin; il++)
 //        {Element& elem = *(*il);
 //         Enum_type_geom enutygeom =  Type_geom_generique(elem.Id_geometrie());
 // //        if ((enutygeom == LIGNE) || (enutygeom == SURFACE))
 //         if (enutygeom == SURFACE) // pour l'intant on ne traite que les surfaces
 //          {elem.CalculNormale_noeud(TEMPS_0,*tab_noeud(ine),coor_inter);
 //           if (coor_inter.Dimension() == 0)
 //            {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
 //                  << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
 //                  << " du maillage " << tab_noeud(ine)->Num_Mail()
 //                  << " par rapport  a l'element "<< elem.Num_elt()
 //                  << " du maillage " << elem.Num_maillage()
 //                  << "\n Maillage::MiseAjourNormaleAuxNoeuds() ";
 //             Sortie(1);
 //            }
 //           else // sinon c'est ok
 //            {normale += coor_inter;
 //             nb_normale++;
 //            };
 //          };
 //        };
 //
 // }
 //
 //// end debug
          normale.Normer();
          // ce qui fini la mise à jour de la normale au noeud
         };
      };
   }
     
   // on fait de même pour les éléments frontières minimals
   // calcul éventuel du tableau indice_NFr
   this->Indice_NFr();
   {Grandeur_coordonnee grandCoordonnee_0(ParaGlob::Dimension()); // un type courant
    TypeQuelconque typQ4_0(N_FRONT_t0,EPS11,grandCoordonnee_0);
    Grandeur_coordonnee grandCoordonnee_t(ParaGlob::Dimension()); // un type courant
    TypeQuelconque typQ4_t(N_FRONT_t,EPS11,grandCoordonnee_t);
    
    //  à t=0
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
     {Noeud & noe = *tab_noeud(ine); // pour simplifier
      // on regarde si le conteneur de la normale à un noeud frontière existe au noeud et création éventuelle
      if (!noe.Existe_ici(N_FRONT_t0))
        noe.AjoutUnTypeQuelconque(typQ4_0);
     };
    // on fait la même chose à t ce qui évitera de tester à la mise à jour
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
     {Noeud & noe = *tab_noeud(ine); // pour simplifier
      // on regarde si le conteneur de la normale à un noeud frontière existe au noeud et création éventuelle
      if (!noe.Existe_ici(N_FRONT_t))
        noe.AjoutUnTypeQuelconque(typQ4_t);
     };
    //  on s'occupe du contenu
    for (int ine =1; ine < borne_max_nbNoeud;ine++ )
     {Noeud & noe = *tab_noeud(ine); // pour simplifier

      // on  récupère le conteneur au noeud
      TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t0);
      Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
      Coordonnee& normale = *gr.ConteneurCoordonnee();
      normale.Zero(); // init
      
      // si on est en dimension 1, la normale est directement déterminé
      if (dima == 1)
       {normale(1) = 1.;
       }
      else
       {// ici dima > 1, les éléments ont une métrique car ils sont différents des éléments points
        List_io <Front*>& li_elem = indice_NFr(ine);// la liste des Front qui contiennent le noeud
        List_io <Front*>::iterator il,ilfin = li_elem.end();
        // on balaie les éléments
        int nb_normale=0; // le nombre de normales trouvées
        for (il = li_elem.begin(); il != ilfin; il++)
         {Front& elem = *(*il);
          Enum_type_geom enutygeom = elem.Eleme_const()->Type_geom_front();
          int cas = elem.Eleme()->CalculNormale_noeud(TEMPS_0,*tab_noeud(ine),coor_inter);
  //        //------ debug
  //        if ((noe.Num_noeud() == 6) && (noe.Num_Mail()==2))
  //         { cout << "\n debug Maillage::InitNormaleAuxNoeuds():"
  //                << " noe "<< noe.Num_noeud() << " N= "; coor_inter.Affiche();
  //         };
  //        // ----- end debug
          
          if (cas == 0)
           {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
                 << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
                 << " du maillage " << tab_noeud(ine)->Num_Mail()
                 << " par rapport  a l'element de frontiere ";
            elem.Affiche(1);
            cout << "\n Maillage::InitNormaleAuxNoeuds() ";
            Sortie(1);
           }
          else if (cas == 2)
           {// le calcul n'est pas licite, mais ce n'est pas une erreur
            // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
           }
          else // sinon c'est ok
           {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
            // conduire à une somme nulle,
            double intens_normale = normale.Norme(); // l'intensité actuelle
            Coordonnee inter_co = normale + coor_inter;
  //          if ((intens_normale > ConstMath::unpeupetit) && (inter_co.Norme() < ConstMath::petit))
  //           // normalement ne devrait pas arriver
  //           {
  //
  //           }
  
             //pour éviter cela, on pourrait regarder le produit scalaire
             // s'il est négatif on utilise l'inverse de la normale
             // donc en définitif on gardera globalement la direction précédente
             if ((intens_normale > ConstMath::unpeupetit) && (inter_co.Norme() < ConstMath::petit))
               {normale -= coor_inter;} //  cas où la somme s'annulle
             else // sinon cas normale
 //              if ((normale * coor_inter) > 0.)
                 {normale += coor_inter;}
                 
//                 {normale += coor_inter; }// ici cela me semble plus juste: on ne doit pas avoir de pb d'inversion de normale

            nb_normale++;
           };
        };
        if (nb_normale != 0)
         {normale /= nb_normale;
          // enfin on normalise la normale
          normale.Normer();
          // ce qui fini la mise à jour de la normale au noeud
  //        //------ debug
  //        if ((noe.Num_noeud() == 6) && (noe.Num_Mail()==2))
  //         { cout << "\n debug Maillage::InitNormaleAuxNoeuds():"
  //                << " noe "<< noe.Num_noeud() << " N= "; normale.Affiche();
  //         };
  //        // ----- end debug
         };
       };
     };
   }
 #ifndef UTILISATION_MPI // la vérif est intractable en MPI, pour des grands maillage
                         // on neutralise pour l'instant (le pb c'est les noeuds qui appartiennent qu'à
                         // des poutres en 3D et donc qui n'ont pas d'orientation, donc pas de normale)
                         // ça posera pb pour le contact
   #ifdef MISE_AU_POINT
   // on vérifie que tous les noeuds des frontières possèdent une normales
   {LaLIST <Front>::iterator il,ilfin = listFrontiere.end();
    for (il = listFrontiere.begin(); il != ilfin; il++)
     { Front& elem = (*il); // pour simplifier
       ElFrontiere* elfro = elem.Eleme();
       Tableau <Noeud *>& tabNFront = elfro->TabNoeud();
       int nbnoefront_et1 = 1+tabNFront.Taille();
       for (int inoe = 1; inoe<nbnoefront_et1; inoe++)
        {Noeud & noe = *tabNFront(inoe); // pour simplifier
         // on  récupère le conteneur au noeud après création éventuelle
         TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t0);
         Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
         Coordonnee& normale = *gr.ConteneurCoordonnee();
         if(Dabs(normale.Norme()) == 0.)
           // cela veut qu'aucune normale n'est disponible, c'est bizarre
           { cout << "\n *** attention le noeud "<<noe.Num_noeud()
           << " du maillage " << noe.Num_Mail()
           << " n'a pas de normale moyenne definie a t0";
           };
           
////------ debug
//if ((noe.Num_noeud() == 1708) && (noe.Num_Mail()==2))
// { cout << "\n debug Maillage::InitNormaleAuxNoeuds():"
//        << " noe "<< noe.Num_noeud() << " N à t = "; normale.Affiche();
// };
//// ----- end debug
        };
     };
   };
   #endif
 #endif
   // on initialise à t par défaut
   {LaLIST <Front>::iterator il,ilfin = listFrontiere.end();
    for (il = listFrontiere.begin(); il != ilfin; il++)
     { Front& elem = (*il); // pour simplifier
       ElFrontiere* elfro = elem.Eleme();
       Tableau <Noeud *>& tabNFront = elfro->TabNoeud();
       int nbnoefront_et1 = 1+tabNFront.Taille();
       for (int inoe = 1; inoe<nbnoefront_et1; inoe++)
        {Noeud & noe = *tabNFront(inoe); // pour simplifier
         // on  récupère le conteneur au noeud après création éventuelle
         TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t0);
         Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
         Coordonnee& normale = *gr.ConteneurCoordonnee();
         // on  récupère le conteneur au noeud après création éventuelle
         TypeQuelconque& tiq_t = noe.ModifGrandeur_quelconque(N_FRONT_t);
         Grandeur_coordonnee& gr_t= *((Grandeur_coordonnee*) (tiq_t.Grandeur_pointee()));
         Coordonnee& normale_t = *gr_t.ConteneurCoordonnee();
         normale_t = normale;
        };
     };
   };

 };

// calcule des normales aux noeuds: dans le cas d'éléments 1D ou 2D
// et aussi pour les frontières (qui sont normalement de type 1D ou 2D)
// a priori le calcul s'effectue par une moyenne des normales des éléments qui
// entourent le noeud.
// mise à jour -> mise à jour des normales à t

void Maillage::MiseAjourNormaleAuxNoeuds()
 { // on va parcourir les noeuds et on n'intervient que si le noeud
   // appartient à un élément 1D et/ou 2D
   int nbNoeud = tab_noeud.Taille();
   int dima = ParaGlob::Dimension();
   int borne_max_nbNoeud = nbNoeud+1;
   Coordonnee coor_inter; //  coordonnée de travail
   for (int ine =1; ine < borne_max_nbNoeud;ine++ )
     {Noeud & noe = *tab_noeud(ine); // pour simplifier
      // on récupère la normale au noeud
      TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(NN_SURF_t);
      Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
      Coordonnee& normale = *gr.ConteneurCoordonnee();
      normale.Zero(); // init
      // calcul éventuel du tableau Indice
      this->Indice();
      int dima = ParaGlob::Dimension();

      // si on est en dimension 1, la normale est directement déterminé
      if (dima == 1)
       {normale(1) = 1.;
       }
      else
       {// ici dima > 1, les éléments ont une métrique car ils sont différents des éléments points
        List_io < Element*>& li_elem = indice(ine);// la liste des éléments qui contiennent le noeud
        List_io < Element*>::iterator il,ilfin = li_elem.end();
        // on balaie les éléments
        int nb_normale=0; // le nombre de normales trouvées
        for (il = li_elem.begin(); il != ilfin; il++)
         {Element& elem = *(*il);
          Enum_type_geom enutygeom =  Type_geom_generique(elem.Id_geometrie());
          //        if ((enutygeom == LIGNE) || (enutygeom == SURFACE))
          if ((enutygeom == SURFACE) // dans une première étape on ne s'occupe que des surfaces en 3D
               && (dima == 3) // si surface en 2D, ce sera les éléments frontières qui détermineront les normales
             )
           {int cas = elem.CalculNormale_noeud(TEMPS_t,*tab_noeud(ine),coor_inter);
            if (cas == 0)
             {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
                   << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
                   << " du maillage " << tab_noeud(ine)->Num_Mail()
                   << " par rapport  a l'element "<< elem.Num_elt()
                   << " du maillage " << elem.Num_maillage()
                   << "\n Maillage::MiseAjourNormaleAuxNoeuds() ";
              Sortie(1);
             }
            else if (cas == 2)
             {// le calcul n'est pas licite, mais ce n'est pas une erreur
              // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
             }
            else // sinon c'est ok
             {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
              // conduire à une somme nulle, pour éviter cela, on regarde le produit scalaire
              // s'il est négatif on utilise l'inverse de la normale
              // donc en définitif on gardera globalement la direction précédente
              if ((normale * coor_inter) > 0.)
                {normale += coor_inter;}
              else
                {normale -= coor_inter;};
//             {normale += coor_inter;
              nb_normale++;
             };
           };
         };
        if (nb_normale != 0)
          {normale /= nb_normale;
           // enfin on normalise la normale
           normale.Normer();
          };
        };
      // ce qui fini la mise à jour de la normale au noeud
     };
     
   // on fait de même pour les éléments frontières minimals
   // calcul éventuel du tableau indice_NFr
   this->Indice_NFr();
   for (int ine =1; ine < borne_max_nbNoeud;ine++ )
    {Noeud & noe = *tab_noeud(ine); // pour simplifier
     // on récupère la normale au noeud
     TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t);
     Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
     Coordonnee& normale = *gr.ConteneurCoordonnee();
     normale.Zero(); // init

     // si on est en dimension 1, la normale est directement déterminé
     if (dima == 1)
      {normale(1) = 1.;
      }
     else
      {// ici dima > 1, les éléments ont une métrique car ils sont différents des éléments points
       List_io <Front*>& li_elem = indice_NFr(ine);// la liste des Front qui contiennent le noeud
       List_io <Front*>::iterator il,ilfin = li_elem.end();
       // on balaie les éléments
       int nb_normale=0; // le nombre de normales trouvées
       for (il = li_elem.begin(); il != ilfin; il++)
        {Front& elem = *(*il);
         Enum_type_geom enutygeom = elem.Eleme_const()->Type_geom_front();
         int cas = elem.Eleme()->CalculNormale_noeud(TEMPS_t,*tab_noeud(ine),coor_inter);
         if (cas == 0)
          {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
                << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
                << " du maillage " << tab_noeud(ine)->Num_Mail()
                << " par rapport  a l'element de frontiere ";
           elem.Affiche(1);
           cout << "\n Maillage::InitNormaleAuxNoeuds() ";
           Sortie(1);
          }
         else if (cas == 2)
          {// le calcul n'est pas licite, mais ce n'est pas une erreur
           // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
          }
         else // sinon c'est ok
          {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
           // conduire à une somme nulle, pour éviter cela, on regarde le produit scalaire
           // s'il est négatif on utilise l'inverse de la normale
           // donc en définitif on gardera globalement la direction précédente
           if ((normale * coor_inter) > 0.)
             {normale += coor_inter;}
           else
             {normale -= coor_inter;};
           nb_normale++;
          };
         };
       if (nb_normale != 0)
        {normale /= nb_normale;
         // enfin on normalise la normale
         normale.Normer();
        };
       };
     // ce qui fini la mise à jour de la normale au noeud
    };
#ifndef UTILISATION_MPI // la vérif est intractable en MPI, pour des grands maillage
                        // on neutralise pour l'instant (le pb c'est les noeuds qui appartiennent qu'à
                        // des poutres en 3D et donc qui n'ont pas d'orientation, donc pas de normale)
                        // ça posera pb pour le contact
   #ifdef MISE_AU_POINT
   // on vérifie que tous les noeuds des frontières possèdent une normales
   {LaLIST <Front>::iterator il,ilfin = listFrontiere.end();
    for (il = listFrontiere.begin(); il != ilfin; il++)
     { Front& elem = (*il); // pour simplifier
       ElFrontiere* elfro = elem.Eleme();
       Tableau <Noeud *>& tabNFront = elfro->TabNoeud();
       int nbnoefront_et1 = 1+tabNFront.Taille();
       for (int inoe = 1; inoe<nbnoefront_et1; inoe++)
        {Noeud & noe = *tabNFront(inoe); // pour simplifier
         // on  récupère le conteneur au noeud après création éventuelle
         TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t);
         Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
         Coordonnee& normale = *gr.ConteneurCoordonnee();
         if(Dabs(normale.Norme()) == 0.)
           // cela veut qu'aucune normale n'est disponible, c'est bizarre
           { cout << "\n *** attention le noeud "<<noe.Num_noeud()
           << " du maillage " << noe.Num_Mail()
           << " n'a pas de normale moyenne definie a t ";
           };
        };
     };
   };
   #endif
#endif

 };
 
// mise à jour -> mise à jour des normales à t
// mais ici, on calcule les normales à tdt, et on transfert à t
// cette méthode est utile si on veut utiliser des normales à t pour une valeur
// particulière (transitoire) de la géométrie à tdt
// cf: l'algo non dyna par exempel
void  Maillage::MiseAjourNormaleAuxNoeuds_de_tdt_vers_T()
{ // on va parcourir les noeuds et on n'intervient que si le noeud
  // appartient à un élément 1D et/ou 2D
  int nbNoeud = tab_noeud.Taille();
  int dima = ParaGlob::Dimension();
  int borne_max_nbNoeud = nbNoeud+1;
  Coordonnee coor_inter; //  coordonnée de travail
  for (int ine =1; ine < borne_max_nbNoeud;ine++ )
    {Noeud & noe = *tab_noeud(ine); // pour simplifier
     // on récupère la normale au noeud
     TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(NN_SURF_t);
     Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
     Coordonnee& normale = *gr.ConteneurCoordonnee();
     normale.Zero(); // init
     // calcul éventuel du tableau Indice
     this->Indice();

     List_io < Element*>& li_elem = indice(ine);// la liste des éléments qui contiennent le noeud
     List_io < Element*>::iterator il,ilfin = li_elem.end();
     // on balaie les éléments
     int nb_normale=0; // le nombre de normales trouvées
     for (il = li_elem.begin(); il != ilfin; il++)
      {Element& elem = *(*il);
       Enum_type_geom enutygeom =  Type_geom_generique(elem.Id_geometrie());
       //        if ((enutygeom == LIGNE) || (enutygeom == SURFACE))
       if ((enutygeom == SURFACE) // dans une première étape on ne s'occupe que des surfaces en 3D
            && (dima == 3) // si surface en 2D, ce sera les éléments frontières qui détermineront les normales
          )
        {// ici contrairement à la méthode: MiseAjourNormaleAuxNoeuds
         // on demande à l'élément de calculer la normale avec la géométrie à tdt
         int cas = elem.CalculNormale_noeud(TEMPS_tdt,*tab_noeud(ine),coor_inter);
         if (cas == 0)
          {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
                << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
                << " du maillage " << tab_noeud(ine)->Num_Mail()
                << " par rapport  a l'element "<< elem.Num_elt()
                << " du maillage " << elem.Num_maillage()
                << "\n Maillage::MiseAjourNormaleAuxNoeuds_de_tdt_vers_T() ";
           Sortie(1);
          }
         else if (cas == 2)
          {// le calcul n'est pas licite, mais ce n'est pas une erreur
           // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
          }
         else // sinon c'est ok
          {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
           // conduire à une somme nulle, pour éviter cela, on regarde le produit scalaire
           // s'il est négatif on utilise l'inverse de la normale
           // donc en définitif on gardera globalement la direction précédente
           if ((normale * coor_inter) > 0.)
             {normale += coor_inter;}
           else
             {normale -= coor_inter;};
//          {normale += coor_inter;
           nb_normale++;
          };
        };
      };
     if (nb_normale != 0)
       {normale /= nb_normale;
        // enfin on normalise la normale
        normale.Normer();
       };
     // ce qui fini la mise à jour de la normale au noeud
    };
    
  // on fait de même pour les éléments frontières minimals
  // calcul éventuel du tableau indice_NFr
  this->Indice_NFr();

  for (int ine =1; ine < borne_max_nbNoeud;ine++ )
   {Noeud & noe = *tab_noeud(ine); // pour simplifier
    // on récupère la normale au noeud
    TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t);
    Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
    Coordonnee& normale = *gr.ConteneurCoordonnee();
    normale.Zero(); // init

    // si on est en dimension 1, la normale est directement déterminé
    if (dima == 1)
     {normale(1) = 1.;
     }
    else
     {// ici dima > 1, les éléments ont une métrique car ils sont différents des éléments points
      // la norme est nulle, on continue
      List_io <Front*>& li_elem = indice_NFr(ine);// la liste des Front qui contiennent le noeud
      List_io <Front*>::iterator il,ilfin = li_elem.end();
      // on balaie les éléments
      int nb_normale=0; // le nombre de normales trouvées
      for (il = li_elem.begin(); il != ilfin; il++)
       {Front& elem = *(*il);
        Enum_type_geom enutygeom = elem.Eleme_const()->Type_geom_front();
        // ici contrairement à la méthode: MiseAjourNormaleAuxNoeuds
        // on demande à l'élément de calculer la normale avec la géométrie à tdt
        int cas = elem.Eleme()->CalculNormale_noeud(TEMPS_tdt,*tab_noeud(ine),coor_inter);
        if (cas == 0)
         {cout << "\n *** erreur, le calcul de la normale n'est pas possible "
               << " pour le noeud "<<tab_noeud(ine)->Num_noeud()
               << " du maillage " << tab_noeud(ine)->Num_Mail()
               << " par rapport  a l'element de frontiere ";
          elem.Affiche(1);
          cout << "\n Maillage::InitNormaleAuxNoeuds() ";
          Sortie(1);
         }
        else if (cas == 2)
         {// le calcul n'est pas licite, mais ce n'est pas une erreur
          // simplement, l'élément n'est pas rusé pour ce noeud, on ne fait rien
         }
        else // sinon c'est ok
         {// on peut avoir des directions très proches mais de sens inverse ... ce qui va
          // conduire à une somme nulle, pour éviter cela, on regarde le produit scalaire
          // s'il est négatif on utilise l'inverse de la normale
          // donc en définitif on gardera globalement la direction précédente
          if ((normale * coor_inter) > 0.)
            {normale += coor_inter;}
          else
            {normale -= coor_inter;};
          nb_normale++;
         };
        };
      if (nb_normale != 0)
       {normale /= nb_normale;
        // enfin on normalise la normale
        normale.Normer();
       };
      };
    // ce qui fini la mise à jour de la normale au noeud
   };
 #ifndef UTILISATION_MPI // la vérif est intractable en MPI, pour des grands maillage
                         // on neutralise pour l'instant (le pb c'est les noeuds qui appartiennent qu'à
                         // des poutres en 3D et donc qui n'ont pas d'orientation, donc pas de normale)
                         // ça posera pb pour le contact

  #ifdef MISE_AU_POINT
  // on vérifie que tous les noeuds des frontières possèdent une normales
  {LaLIST <Front>::iterator il,ilfin = listFrontiere.end();
   for (il = listFrontiere.begin(); il != ilfin; il++)
    { Front& elem = (*il); // pour simplifier
      ElFrontiere* elfro = elem.Eleme();
      Tableau <Noeud *>& tabNFront = elfro->TabNoeud();
      int nbnoefront_et1 = 1+tabNFront.Taille();
      for (int inoe = 1; inoe<nbnoefront_et1; inoe++)
       {Noeud & noe = *tabNFront(inoe); // pour simplifier
        // on  récupère le conteneur au noeud après création éventuelle
        TypeQuelconque& tiq = noe.ModifGrandeur_quelconque(N_FRONT_t);
        Grandeur_coordonnee& gr= *((Grandeur_coordonnee*) (tiq.Grandeur_pointee()));
        Coordonnee& normale = *gr.ConteneurCoordonnee();
        if(Dabs(normale.Norme()) == 0.)
          // cela veut qu'aucune normale n'est disponible, c'est bizarre
          { cout << "\n *** attention le noeud "<<noe.Num_noeud()
          << " du maillage " << noe.Num_Mail()
          << " n'a pas de normale moyenne definie a t";
          };
       };
    };
  };
  #endif
#endif

    
};

// creation des elements frontiere
// il s'agit ici des frontière minimales permettant de représenter toute la frontière
// Ainsi:
// en 1D on retrouve:
//    - des points uniquement
// en 2D on retrouve :
//    - des segments dans le cas d'une surface  (les noeuds sont exclus car intégrés aux lignes)
//    - points et segment pour les lignes
// en 2D axi, on retrouve :
//    - des segments dans le cas d'une surface  (les noeuds sont exclus car intégrés aux lignes)
//    - points et segment pour les lignes
// en 3D, on retrouve
//    - des faces pour les éléments volumique (noeuds et lignes sont exclus)
//    - une face et des lignes pour les éléments 2D (pas de noeuds)
void Maillage::CreeElemFront()
{
  // 0- on supprime la liste existante
  listFrontiere.erase(listFrontiere.begin(),listFrontiere.end());
  // 1- tout d'abord on crée les éléments frontière dans chaque élément
  int tabelTaille = tab_element.Taille();
  // on boucle sur les elements 
  for (int i2 = 1; i2 <= tabelTaille; i2++)
      // création des éléments frontières (on force)
      tab_element(i2)->Frontiere(true);
      
   int nb_init_frontiere=0;
 #ifdef MISE_AU_POINT
   {for (int i1 = 1; i1 <= tabelTaille; i1++)
     {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
      int tab1Taille = tab1.Taille();
      for (int i=1;i<= tab1Taille;i++)
       if (tab1(i) != NULL)
          nb_init_frontiere++;
     }
//  cout << "\n au début : après création des frontières dans les elements ->"<<nb_front_enreg<<" frontières " << flush;
   };
 #endif
  // -- fin debug
  // 2- maintenant on va créé des tableaux permettant d'accélérer l'algorithme final
  // pour chaque noeud on regarde quel élément contiend ce noeud
	 Calcul_indice();
  int tab_noeud_taille= tab_noeud.Taille();
  // indice contiend les numéros d'élément succeptible d'avoir des frontières
  // communes
 
  // 3- maintenant on va de nouveau boucler sur les éléments en regardant
  // pour chaque frontière si elle est effectivement recevable c-a-d si
  // il n'y a pas deux frontières identiques     
  Front lili; // un element de référence de frontière courant
  // des indicateurs pour la sortie de message
  int nb_cas_I=0; int nb_cas_II=0; int nb_cas_courant=0;

//    for (int i1 = 1; i1 <= tabelTaille-1; ++i1)
  for (int i1 = 1; i1 <= tabelTaille; i1++)
   {Element * elem1 = tab_element(i1); // recup de l'element
    // récup du type des éléments finis :-> POINT_G , LIGNE , SURFACE, VOLUME
    Enum_type_geom typ1_element = Type_geom_generique(elem1->Id_geometrie());

    const Tableau <ElFrontiere*>&  tab1 = elem1->Frontieres_Actuelles(); // et de ses frontières
    int tab1Taille = tab1.Taille();      // frontières
      
/* //------- debug
   {int nb_front_enreg=0;
    cout << "\n === début === on regarde les frontieres ("<<tabelTaille << ") de l'element "<<elem1->Num_elt() << " type " << Nom_type_geom(typ1_element);
    for (int i1 = 1; i1 <= tabelTaille; i1++)
    {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
     int tab1Taille = tab1.Taille();
     for (int i=1;i<= tab1Taille;i++)
      if (tab1(i) != NULL)
         nb_front_enreg++;
    }
    cout << "\n   actuellement: dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
   }
//---- fin debug */

		// on boucle sur les frontière, qui doivent être repérée par un pointeur non nulle
    for (int j1=1;j1<= tab1Taille;j1++)
    // on essaie de voir si l'élément j1 est recevable, c-a-d pointeur non nulle
		// sinon cela veut dire que la frontière a été supprimer car en double
    {ElFrontiere * elfr = tab1(j1); // pour simplifier
     // on ne continue que si le pointeur est non nul
     if (elfr != NULL)
      { Enum_type_geom typ1_frontiere = elfr->Type_geom_front();
        bool res = false; 
        // si deux éléments frontières sont identiques alors tous leurs noeuds
        // sont identiques. En particulier le premier noeud de *elfr est commum
        // avec tous les éléments succeptibles de contenir un élément frontière
        // identique. On va donc utiliser la liste indice qui contiend cette liste
        int numnoeud = (elfr->TabNoeud())(1)->Num_noeud();
        list<Element*>::iterator ina,infin;
        list<Element*>& intertab = indice(numnoeud); // pour allèger l'écriture
        infin = intertab.end();
/* //-- debug
        cout << "\n element1 "<<elem1->Num_elt() << " cas de la frontière "<<j1 << " type " << Nom_type_geom(typ1_frontiere)
             << " : nb candidat -> "<< intertab.size() << " on parcours les candidats: ";
        {if (  ((elem1->Num_elt() == 10) && (j1==3))
             || ((elem1->Num_elt() == 12) && (j1==4))
            )
         { cout << "\n elem1 "<< elem1->Num_elt() << ", frontière "<< j1;
           Tableau <Noeud *>& taa = elfr->TabNoeud();
           cout << "\n les num des noeuds de la frontière : ";
           for (int  i=1; i<= taa.Taille();i++)
             cout << taa(i)->Num_noeud() << " ";
           cout << "\n la liste des elem contenant le premier noeud ";
          list<Element*>::iterator ina,infin = intertab.end();
          for (ina = intertab.begin();ina!=infin;ina++)
            cout << (*ina)->Num_elt() << " ";
         }
        }
//--fin debug */
        int type_ajout = 0; // pour le debug
        // on balaie les élément succeptibles d'avoir des frontières communes
        for (ina = intertab.begin();ina!=infin;ina++)
         {Element * elem2 = *ina; // recup de l'element
          // récup du type des éléments finis :-> POINT_G , LIGNE , SURFACE, VOLUME
          Enum_type_geom typ2_element = Type_geom_generique(elem2->Id_geometrie());


/* //-- debug
          cout << "\n candidat element: "<< elem2->Num_elt() << " type " << Nom_type_geom(typ2_element);
//--fin debug */
          // on ne fait la recherche que pour les éléments différents de elem1
		        bool res_ina = false; // init d'un indicateur interne à la boucle j2 qui suit, 
          if (elem2 != elem1)
            {
              const Tableau <ElFrontiere*>&  tab2 = elem2->Frontieres_Actuelles(); // et des éléments
              int tab2Taille = tab2.Taille();      // frontières
              for (int j2=1;j2<= tab2Taille;++j2)
               { // dans le cas où l'élément frontière existe, c'est-à-dire
                 // qu'il n'a pas été supprimé par un précédent passage
                 // on le compare
                 ElFrontiere* tab2j2 = tab2(j2); // pour simplifier
                 
                 if (tab2j2 != NULL)
                  {Enum_type_geom typ2_frontiere = tab2j2->Type_geom_front();
/* //-- debug
                   cout << "\n element 2 "<<elem2->Num_elt() << " cas de la frontière "<<j2 << " type " << Nom_type_geom(typ2_frontiere);
//--fin debug */

                  
//  // pb dans le calcul de l'opposé ou due à l'utilisation de p ??                 ElFrontiere* p = tab2j2->Oppose(); // variable transitoire
//                   if ((*elfr) == (*p))
                   if ((*elfr) == (*tab2j2))
                    // on a trouve un element qui annule
                    // cependant il y a un cas particulier:
                    // I - on a la supperposition de 2 mêmes frontières mais pour des éléments finis de tailles différentes
                    //   1) on a la supperposition d'une surface d'un élément fini 2D avec une facette d'un élément 3D
                    //   2)   ou la supperposition d'une ligne d'un élément fini 1D avec une arête d'un élément 3D ou 2D
                    // dans ces là, ces  ElFrontiere peuvent quand même représenter une vrai frontière mais
                    // elles font double emploi, du coup on fait le choix de garder l'élément frontière de dim inférieur
                     {
                     
                      // modif
                      // on ne continue que s'il s'agit du même type d'élément
                      if (typ1_element == typ2_element)
                         {res = res_ina = true;// on met les indicateurs
                          // pour sortie de la boucle sur j2
                          // suppression de l'élément dans la liste
                           if (elem2->SupprimeFront(tab2j2))
                             nb_cas_courant++;
                          };

                     
//                       if (typ1_element != typ2_element) // là il faut regarder de plus près:
//                       // pour les types, il s'agit d'un enuméré avec:  POINT_G = 1 , LIGNE , SURFACE, VOLUME, RIEN_TYPE_GEOM
//                       {
//                        if (typ1_element > typ2_element) // on va supprimer le 1 et garder le 2
//                         {res = res_ina = true;// on met l'indicateur
//                         }
//                        else // c'est forcément l'inverse: on va supprimer le 2 et garder le 1
//                         // suppression de l'élément dans la liste
//                         // mais on ne met pas l'indicateur, donc la frontière d'elem1 ne sera pas supprimé, d'une part
//                         // et on continue les boucles sur j2 et au dessus sur ina
//                         {
/* //------- debug
  // on passe en revue la liste des frontières enregistrées, normalement on ne devrait pas supprimer une frontière déjà enregistrée
  {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      ElFrontiere* elfli = fro->Eleme();
      if (((*elfli)==(*tab2j2)) && (elem2->Num_elt() == fro->PtEI()->Num_elt()))
        {cout << "\n erreur1 la frontière est déjà enregistrée, on ne devrait pas avoir à la supprimer ?? " << flush;
        }
    }
  }
//---- fin debug */
//                          if (elem2->SupprimeFront(tab2j2))
//                           {nb_cas_I++;
/* //------- debug
  {int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
   {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
    int tab1Taille = tab1.Taille();
    for (int i=1;i<= tab1Taille;i++)
     if (tab1(i) != NULL)
        nb_front_enreg++;
   }
   cout << "\n suppression frontière elem2 (cas_I): actuellement dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
  }
  // on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
  {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      Element * elem = fro->PtEI();
      if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
       {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
        cout << " n'existe plus dans l'élément finis " << flush;
        Sortie(1);
       }
    }
  }
//---- fin debug */
//                          };
//                         }
//                       }
//                      else
//
//
//                      // II - on a la supperposition de 2 mêmes frontière pour des éléments de même taille
//                      //   1)   mais si on est en 3D et qu'il s'agit d'une frontière 2D d'un élément 2D, il s'agit d'élément 2D qui peuvent
//                      //      définir une frontière, on fait le choix de garder une des deux frontières et de supprimer l'autre
//                       { if ((ParaGlob::Dimension() == 3) && (typ2_frontiere ==3))
//                          // on va supprimer le 2 et garder le 1
//                          // mais on ne met pas l'indicateur, donc la frontière d'elem1 ne sera pas supprimé
//                          // et on continue les boucles sur j2 et au dessus sur ina
//                          {
/* //------- debug
  // on passe en revue la liste des frontières enregistrées, normalement on ne devrait pas supprimer une frontière déjà enregistrée
  {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      ElFrontiere* elfli = fro->Eleme();
      if (((*elfli)==(*tab2j2)) && (elem2->Num_elt() == fro->PtEI()->Num_elt()))
        {cout << "\n erreur2 la frontière est déjà enregistrée, on ne devrait pas avoir à la supprimer ?? " << flush;
        }
    }
  }
cout << "\n avant suppression frontière elem2";
// on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
{LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
 for (iF = listFrontiere.begin();iF!=iFfin; iF++)
  { Front* fro = &(*iF);
    Element * elem = fro->PtEI();
    if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
     {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
      cout << " n'existe plus dans l'élément finis " << flush;
      Sortie(1);
     }
  }
}
//---- fin debug */
//                           if (elem2->SupprimeFront(tab2j2))
//                             {nb_cas_II++;
/* //------- debug
  {int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
   {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
    int tab1Taille = tab1.Taille();
    for (int i=1;i<= tab1Taille;i++)
     if (tab1(i) != NULL)
        nb_front_enreg++;
   }
   cout << "\n suppression frontière elem2 (cas_II): actuellement dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
   // on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
   {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
    for (iF = listFrontiere.begin();iF!=iFfin; iF++)
     { Front* fro = &(*iF);
       Element * elem = fro->PtEI();
       if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
        {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
         cout << " n'existe plus dans l'élément finis " << flush;
         Sortie(1);
        }
     }
   }
  }
//---- fin debug */
//                            };
//                          }
//                         else // autre cas -> c-a-d hors cas particulier
//                          // cas où on a le même type, on va supprimer les deux frontières
//                          {res = res_ina = true;// on met les indicateurs
//                           // pour sortie de la boucle sur j2
//                           // suppression de l'élément dans la liste
/* //------- debug
  {cout << "\n on va supprimer : la frontiere " << tab2j2->Type_geom_front() <<" de num dans le type "<< elem2->Num_de_frontiere_dans_le_type(j2)
       << " de l'element fini "<< elem2->Num_elt() << " type "<< Nom_type_geom(typ2_element) << flush;
   // on passe en revue la liste des frontières enregistrées, normalement on ne devrait pas supprimer une frontière déjà enregistrée
   LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      ElFrontiere* elfli = fro->Eleme();
      if (((*elfli)==(*tab2j2)) && (elem2->Num_elt() == fro->PtEI()->Num_elt()))
        {cout << "\n erreur3 la frontière est déjà enregistrée, on ne devrait pas avoir à la supprimer ?? " << flush;
        }
    }
  }
cout << "\n avant (2) suppression frontière elem2";
// on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
{LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
 for (iF = listFrontiere.begin();iF!=iFfin; iF++)
  { Front* fro = &(*iF);
    Element * elem = fro->PtEI();
    if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
     {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
      cout << " n'existe plus dans l'élément finis " << flush;
      Sortie(1);
     }
  }
}
//---- fin debug */
//                           if (elem2->SupprimeFront(tab2j2))
//                              {nb_cas_courant++;
/* //------- debug
  {int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
   {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
    int tab1Taille = tab1.Taille();
    for (int i=1;i<= tab1Taille;i++)
     if (tab1(i) != NULL)
        nb_front_enreg++;
   }
   cout << "\n suppression frontière elem2 (cas_courant): actuellement dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
   // on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
   {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
    for (iF = listFrontiere.begin();iF!=iFfin; iF++)
     { Front* fro = &(*iF);
       Element * elem = fro->PtEI();
       if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
        {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
         cout << " n'existe plus dans l'élément finis " << flush;
         Sortie(1);
        }
     }
   }
  }
//---- fin debug */
//                              }
//                          };
//                       };
                     };
//                   delete p; // suppression de l'element p transitoire
                   }
                    // si il y a eu suppression de l'élément frontière on sort de la boucle sur j2
                 if (res_ina)   break; // on sort de la boucle si pas élément de frontière
               };
              // si l'on a détecté une égalité on arête également cette boucle
              // après avoir supprimé l'élément frontière 
      //             non, car on pourrait avoir une frontière qui soit commune à plus de 2 éléments
      //             pour l'instant ce n'est pas le cas, mais par exemple des arrêtes pour les volumes ??
      //          if (res)  
      //           { elem1->SupprimeFront(elfr);
      //             elfr=NULL;
      //             break;
      //            }  
            };
         };
        // en sortie on sauvegarde uniquement si c'est un élément frontière
        if (!res)
              {// on doit ajouter,
					          int num_dans_le_type = elem1->Num_de_frontiere_dans_le_type(j1);
/* //------- debug
  // on vérifie que la frontière existe toujours dans l'élément
  if (tab1(j1) == NULL)
    {cout << "\n erreur: on devrait toujours avoir la frontière non détruite ??? "<< flush;
    }
//--fin debug */

               listFrontiere.push_back(Front(*elfr,elem1,num_dans_le_type));
             #ifdef MISE_AU_POINT
               if (ParaGlob::NiveauImpression()>6)
                 {cout << "\n ajout frontiere " << num_dans_le_type << " (dans le type) c-a-d de num global "<< j1 << "\n";
                  LaLIST <Front>::iterator iFfin = listFrontiere.end();
                  iFfin--;
                  (*iFfin).Affiche(1);
                 };
             #endif

               
/* //------- debug
  {cout << "\n ajout d'une frontière d'elem1 dans la liste ";
   int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
   {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
    int tab1Taille = tab1.Taille();
    for (int i=1;i<= tab1Taille;i++)
     if (tab1(i) != NULL)
        nb_front_enreg++;
   }
   cout << "\n actuellement: dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
   // on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
   {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
    for (iF = listFrontiere.begin();iF!=iFfin; iF++)
     { Front* fro = &(*iF);
       Element * elem = fro->PtEI();
       if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
        {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
         cout << " n'existe plus dans l'élément finis " << flush;
         Sortie(1);
        }
     }
   }
  }
//---- fin debug */
              }
        else // sinon la frontière est commune avec au moins une autre, on l'a supprime
           {
/* //------- debug
  // on passe en revue la liste des frontières enregistrées, normalement on ne devrait pas supprimer une frontière déjà enregistrée
  {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
    { Front* fro = &(*iF);
      ElFrontiere* elfli = fro->Eleme();
      if (((*elfli)==(*elfr)) && (elem1->Num_elt() == fro->PtEI()->Num_elt()))
        {cout << "\n erreur4 la frontière est déjà enregistrée, on ne devrait pas avoir à la supprimer ?? " << flush;
        }
    }
  }
//---- fin debug */
            if (elem1->SupprimeFront(elfr))
              {nb_cas_courant++;
/* //------- debug
  {int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
   {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
    int tab1Taille = tab1.Taille();
    for (int i=1;i<= tab1Taille;i++)
     if (tab1(i) != NULL)
        nb_front_enreg++;
   }
   cout << "\n suppression frontière d'elem1 (cas_courant): actuellement dans les elements ->"<<nb_front_enreg<<" frontières, dans la liste -> "<<listFrontiere.size() << flush;
   // on passe en revue la liste des frontières enregistrées, et on vérifie que toutes les frontières correspondent à des frontières d'éléments toujours licites
   {LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
    for (iF = listFrontiere.begin();iF!=iFfin; iF++)
     { Front* fro = &(*iF);
       Element * elem = fro->PtEI();
       if (elem->Frontieres_Actuelles()(elem->Num_global_frontiere(fro->Num_frontiere(), fro->Eleme()->Type_geom_front())) == NULL)
        {cout << "\n *** erreur de cohérence liste<=>éléments finis, la frontière "; fro->Affiche(1);
         cout << " n'existe plus dans l'élément finis " << flush;
         Sortie(1);
        }
     }
   }
  }
//---- fin debug  */
              };
           };
/* //-- debug
        cout << "\n element1 "<<elem1->Num_elt() << " fin du cas de la frontière "<<j1 << " type " << Nom_type_geom(typ1_frontiere) << endl;
//--fin debug */

      }; // fin du test if (elfr != NULL)
    }; // fin de la boucle sur les frontières de elem1
   }// fin de la boucle externe des éléments
   
     
/* // cas du dernier élément, ses éléments frontières non nuls sont forcément bons
non finalement, cela semble poser des pb sur le dernier élément vu que l'on a mis une procédure d'accélération 
pour le calcul des frontières donc on met en stand by pour l'instant, si pas de pb qui apparaissent on supprime
  { Element * elem1 = tab_element(tabelTaille); // recup de l'element
    const Tableau <ElFrontiere*>&  tab1 = elem1->Frontiere(); // et des éléments
    int tab1Taille = tab1.Taille();      // frontières
    for (int j1=1;j1<= tab1Taille;++j1)
      // on essaie de voir si l'élément j1 est recevable
     { ElFrontiere * elfr = tab1(j1); // pour simplifier
       if (elfr != NULL)
         {//lili.Eleme() =elfr; lili.numMail = idmail; lili.ptEl = elem1;
          listFrontiere.push_back(Front(elfr,elem1));
          }
       }   
    } 
	 */
    
//Sortie(1);

////------- debug
//cout << "\n debug ** Maillage::CreeElemFront() ";
//cout << " nb frontière avant sort = " << listFrontiere.size() << endl;
////---- fin debug

 // on classe les front de manière ensuite à faire des recherches rapide et supprime les doublons
 listFrontiere.sort();
 // normalement arrivée ici les frontières sont uniques, mais en non rapide on vérifie
 #ifdef MISE_AU_POINT
 { int nb_front_initial = listFrontiere.size();
   listFrontiere.unique(egal_font);
   if (nb_front_initial != listFrontiere.size())
     {cout << "\n *** sans doute un pb: la liste de frontiere initialement cree avait pour taille "
           << nb_front_initial << " front , apres passage dans listFrontiere.unique(egal_font) sa nouvelle"
           << " taille est " << listFrontiere.size() << " !!!"
           << "\n Maillage::CreeElemFront() " << endl;
     };
   // vérif de cohérence entre les frontières enregistrées dans les éléments et celles stockées dans la liste
   int nb_front_enreg=0;
   for (int i1 = 1; i1 <= tabelTaille; i1++)
    {const Tableau <ElFrontiere*>&  tab1 = tab_element(i1)->Frontieres_Actuelles();
     int tab1Taille = tab1.Taille();
     for (int i=1;i<= tab1Taille;i++)
      if (tab1(i) != NULL)
         nb_front_enreg++;
    }
   if (nb_front_enreg != listFrontiere.size())
     { cout << "\n *** erreur on a dans les elements ->"<<nb_front_enreg<<" frontieres, et dans la liste -> "<<listFrontiere.size()
            << " on devrait avoir le meme nombre !! "
            << "\n Maillage::CreeElemFront() " << flush;
       Sortie(1);
     }
   if (ParaGlob::NiveauImpression() > 4)
    {cout << "\n creation d'elements frontieres: ";
     if (nb_cas_I) cout << "\n suppression d'au moins  "<<nb_cas_I<<" frontieres qui font double emploi ";
     if (nb_cas_II) cout << "\n suppression de "<<nb_cas_II<<" frontieres 2D d'éléments finis 3D, et on garde une frontiere 2D d'un element 2D equivalent ";
     if (nb_cas_courant) cout << "\n suppression de "<<nb_cas_courant<<" frontieres internes (donc en double) ";
     cout << "\n il reste "<< nb_front_initial << " frontieres finales pour" <<  tabelTaille << " elements finis c-a-d "
          << nb_init_frontiere << " frontieres internes initiales ";
    };
 }
 #endif
 
 
 // effacement du contenu du tableau indice
 indice.Libere (); 
 
 //// ---- debug -----
 // vérification que l'on a bien les frontières bien connectées
// cout << " \n debug: Maillage::CreeElemFront()";
//{ LaLIST <Front>::iterator iF;
//  LaLIST <Front>::iterator iFfin = listFrontiere.end();
//  cout << "\n liste des frontières: \n ";
//  for (iF = listFrontiere.begin();iF!=iFfin; iF++)
//    { Front* elfront = &(*iF);
//	   Enum_type_geom type_front; // va être modifier par Num_frontiere
//	   cout	 << " frontière: " << elfront->Num_frontiere() << " " << elfront->Eleme()->Type_geom_front()
//                 << " de l'element " << elfront->PtEI()->Num_elt() << " du maillage "
//					  << elfront->PtEI()->Num_maillage() << " \n ";
//     };
//};
 
// // vérif particulière (a commenter !)
//{ LaLIST <Front>::iterator iF; 
//  LaLIST <Front>::iterator iFfin = listFrontiere.end();
//  int nbf = 1;
//  for (iF = listFrontiere.begin();iF!=iFfin; iF++)
//    { Front* fro = &(*iF);
//      ElFrontiere * efem1 = fro->Eleme(); // recup de l'element géométrique qui a créé la frontière
//      // récup de son tableau de noeud
//      Tableau<Noeud *>& tabn = efem1->TabNoeud();
//      int tabntaille = tabn.Taille();
//	   if (fro->PtEI()->Id_geometrie() == HEXAEDRE)
//         {cout << "nbf= " << nbf << ",  ele= " << fro->PtEI()->Num_elt() << " : ";
//			 for (int ij=1;ij<= tabntaille;ij++)
//				// on balaie ses noeuds  
//				cout <<  tabn(ij)->Num_noeud() << " ";
//			 cout << endl ;
//			 nbf++;
//			 };
//     };
//
//} 
// 
 //// ---- fin debug -----
 
  
 // definition des elements frontières mitoyens aux elements de frontiere
 MitoyenFront();
 
 #ifdef MISE_AU_POINT
 { // on vérifie que tous les éléments frontières ont au moins un voisin, sinon c'est pas courant d'avoir un seul élément
   // donc on met un warning
   LaLIST <Front>::iterator iF,iFfin = listFrontiere.end();
   for (iF = listFrontiere.begin();iF!=iFfin; iF++)
     { Front* fro = &(*iF);
       const Tableau <Front*>* tabmitoyen = fro->TabMitoyen();
       if (tabmitoyen == NULL)
        {cout << "\n *** warning: ";
         fro->Affiche(1);
         cout << "  pas d'element mitoyen ";
         if (ParaGlob::NiveauImpression() > 5)
           cout << "\n Maillage::CreeElemFront() " << endl;
        };
     };
 }
 #endif

 
 
 
 // ==== définition du tableau des noeuds frontières =====
 // 1) on définit un tableau de numéro de noeuds qui sont utilisés
 Tableau <int> t_noe(tab_noeud_taille,0); // tous les éléments sont nul
 // 2) on balaie les éléments frontières
 LaLIST <Front>::iterator li,li_end=listFrontiere.end();
 for (li=listFrontiere.begin();li!=li_end;li++)
   { Tableau <Noeud *> & tt = (*li).Eleme()->TabNoeud();
     int tt_taille=tt.Taille();
     for (int i=1;i<=tt_taille;i++)
       (t_noe(tt(i)->Num_noeud()))++;   
   };
 // 3) on récupère le nombre de noeud frontière
 int nb_n_f=0;
 for (int ii=1;ii<= tab_noeud_taille;ii++)
   if (t_noe(ii)!=0) nb_n_f++;
 // 4) def du tableau final
 tab_noeud_front.Change_taille(nb_n_f);
 nb_n_f=0; // on se ressert du numéro
 for (int ii=1;ii<= tab_noeud_taille;ii++)
   {if (t_noe(ii)!=0) {nb_n_f++;tab_noeud_front(nb_n_f)=tab_noeud(ii);};};
 
 // dans le cas où les éléments frontières sont des lignes, on les ordonnes 
 // de manière à former une ligne continue
// OrdonancementDesLigne();
};


// création forcée en 3D de toutes les frontières lignes (non traités par CreeElemFront())
// qui appartiennent à la frontière globales, ceci uniquement pour les éléments volumiques
// - Ces frontières ne sont pas intégrées dans la liste de frontière minimale
// - une même ligne peut appartenir à plusieurs éléments finis, elle n'est donc pas ici
//   définit de manière unique (contrairement aux frontières minimales)
void Maillage::CreeListFrontiere_ligne_3D()
 { // on n'intervient qu'en 3D
   if ((ParaGlob::Dimension() == 3) && !(ParaGlob::AxiSymetrie()))
    { // au cas où ... si la liste des frontières est vide on crée les frontières
      if (listFrontiere.size() == 0)
        CreeElemFront();
      // maintenant on efface la liste existante de front segment au cas où
      listFrontiere_ligne_3D.erase(listFrontiere_ligne_3D.begin(),listFrontiere_ligne_3D.end());
      // on crée les éléments frontière segment pour  chaque élément de la frontière minimale
      LaLIST <Front>::iterator il,ilfin = listFrontiere.end();
      for (il = listFrontiere.begin(); il != ilfin; il++)
       { // on vérifie que c'est un élément volumique
         Enum_type_geom enutygeom =  Type_geom_generique((*il).PtEI()->Id_geometrie());
         if (enutygeom == VOLUME)
           {// on construit et on récupère les frontières segments,
            // récup de l'élément géométrique
            ElemGeomC0& el = (*il).PtEI()->ElementGeometrique();
            int tail_ar = el.NbSe(); // nombre potentiel d'arêtes
            for (int ifront = 1; ifront <= tail_ar; ifront++)
               {ElFrontiere* const  elfr = (*il).PtEI()->Frontiere_lineique(ifront,true);
                // ajout après création, de la frontière front
                // dans front il y a une création d'un ElFrontiere qui est == à *elfr
                // mais c'est un élément frontière autonome (indépendant de celui de l'élément)
                listFrontiere_ligne_3D.push_back(Front(*elfr,(*il).PtEI(),ifront));
               };
           };
       };
      // on classe et supprime les doublons
      listFrontiere_ligne_3D.sort();
      listFrontiere_ligne_3D.unique(egal_font);
   };
 };
        
// change le nom et le numéro du maillage
void Maillage::ChangeNomNumeroMaillage(const string & nom,int num)
   { // on vérifie que le nom de maillage fourni n'existe pas 
     if (listeNomMail.find(nom) != listeNomMail.end())
      { cout << "\n erreur, le nom de maillage demande existe deja : " << nom
             << "\n Maillage::ChangeNomNumeroMaillage(.....";
        Sortie(1);
      };
     // on met à jour listeNomMail en supprimant le doublet nom <=> numéro existant
     listeNomMail.erase(listeNomMail.find(nomDuMaillage));
     nomDuMaillage = nom; // on enregistre le nouveau nom   
     // on vérifie que le numéro de maillage proposé est valide        
     if (num <=0)
	      {	cout << "\nErreur : numero de maillage invalide ! = "<< num <<"\n";
		       cout << "Maillage::ChangeNomNumeroMaillage(.... \n";
		       Sortie(1);
	      };
	    idmail=num; // on enregistre le nouveau numéro 
     // maintenant on peut associer le nom au numéro dans la map
     listeNomMail[nomDuMaillage]=idmail;
   };  
        
// ramène le numéro du noeud le plus proche du point donné à t=0 
int Maillage::Noeud_le_plus_proche_0(const Coordonnee& M)
 { // tout d'abord si le maillage n'a pas de noeud on ramène 0
   int tail_mail = tab_noeud.Taille();
   if (tail_mail == 0) return 0;
   // sinon initialisation de la recherche
   int num_rech = 1; // choix du premier noeud
   // distance avec le noeud
   double dist = (tab_noeud(1)->Coord0() - M).Norme();
   // on boucle sur les noeuds
   for (int i=2;i<=tail_mail;i++)
    { double dista = (tab_noeud(i)->Coord0() - M).Norme();
      if (dista <= dist)
       { dist = dista; num_rech = i;};
    };
   // retour
   return num_rech;
  };
// ramène le numéro du noeud le plus proche du point donné à t=t 
int Maillage::Noeud_le_plus_proche_t(const Coordonnee& M)
 { // tout d'abord si le maillage n'a pas de noeud on ramène 0
   int tail_mail = tab_noeud.Taille();
   if (tail_mail == 0) return 0;
   // sinon initialisation de la recherche
   int num_rech = 1; // choix du premier noeud
   // distance avec le noeud
   double dist = (tab_noeud(1)->Coord1() - M).Norme();
   // on boucle sur les noeuds
   for (int i=2;i<=tail_mail;i++)
    { double dista = (tab_noeud(i)->Coord1() - M).Norme();
      if (dista <= dist)
       { dist = dista; num_rech = i;};
    };
   // retour
   return num_rech;
  };
// ramène le numéro du noeud le plus proche du point donné à t=tdt 
int Maillage::Noeud_le_plus_proche_tdt(const Coordonnee& M)
 { // tout d'abord si le maillage n'a pas de noeud on ramène 0
   int tail_mail = tab_noeud.Taille();
   if (tail_mail == 0) return 0;
   // sinon initialisation de la recherche
   int num_rech = 1; // choix du premier noeud
   // distance avec le noeud
   double dist = (tab_noeud(1)->Coord2() - M).Norme();
   // on boucle sur les noeuds
   for (int i=2;i<=tail_mail;i++)
    { double dista = (tab_noeud(i)->Coord2() - M).Norme();
      if (dista <= dist)
       { dist = dista; num_rech = i;};
    };
   // retour
   return num_rech;
  };

        
// ramène le numéro de l'élément qui contiend un point donné et le numéro du point
// d'intégration le plus proche  pour les ddl de la liste, (ddl spécifique à l'élément c'est-a-dire
// hors des ddl des noeuds de l'éléments)
// si pas de numéro d'élément ramène un numéro d'élément nulle
// si les numéros de point d'intégration ne sont pas identique pour l'ensemble
// des ddl, pb !!, le numéro du pt integ de retour est alors négatif
// enu_temps: dit si les coordonnées du point M sont à 0 ou t ou tdt
Maillage::NBelemEtptInteg Maillage::Element_le_plus_proche
            (Enum_dure enu_temps,const List_io <Ddl_enum_etendu>& list_enu
            ,const Coordonnee& M)
 { Maillage::NBelemEtptInteg ret;
   // tout d'abord si le maillage n'a pas d'élément on ramène 0
   int tail_mail = tab_element.Taille();ret.nbElem=0;ret.nbPtInteg=0;
   if (tail_mail == 0) { return ret;}
   // sinon initialisation de la recherche
   // on boucle sur les éléments  pour trouver celui qui contiend M
   // M peut également être sur la surface de l'élément ce qui est ok également   
   for (int i=1;i<=tail_mail;i++)
    { bool trouve = false;
      switch (enu_temps)
       { case TEMPS_0 : if(tab_element(i)->Interne_0(M)) trouve = true; break;
         case TEMPS_t : if(tab_element(i)->Interne_t(M)) trouve = true; break;
         case TEMPS_tdt : if(tab_element(i)->Interne_tdt(M)) trouve = true; break;
        };
     if(trouve)
       {// on a trouvé un élément on recherche le point le plus près ou est exprimé la grandeur
        ret.nbElem = i;
        List_io <Ddl_enum_etendu>::const_iterator ii,iide= list_enu.begin();
        List_io <Ddl_enum_etendu>::const_iterator iifin= list_enu.end();
        ret.nbPtInteg = tab_element(i)->PointLePlusPres(enu_temps,(*iide).Enum(),M);
        // on vérifie que tous les ddl sont disponibles au pt d'integ
        for (ii = iide;ii != iifin; ii++)
          if (!(tab_element(i)->Existe_pt_integ (ret.nbPtInteg,(*ii).Enum())))
            { ret.nbPtInteg = -1; return ret;} 
        // retour normal
        return ret;
/* ancienne vérif, pas bonne        
        // on vérifie que tous les ddl sont de la même famille sinon erreur
        for (ii = iide;ii != iifin; ii++)
          if (!Meme_famille((*ii).Enum(),(*iide).Enum())) 
            { ret.nbPtInteg = -1; return ret;} 
        // retour normal
        return ret;
 */
        };
     };
   // retour dans le cas où l'on n'a pas trouvé d'élément 
   ret.nbElem = 0;
   ret.nbPtInteg = 0;   
   return ret;
  };


// ramène le numéro de l'élément dont le centre de gravité à t = enu_temps est le plus proche d'un point donné
// Le point peut être n'importe où, en particulier à l'extérieur de la matière
// si pb retour de null
const Element* Maillage::Centre_de_Gravite_Element_le_plus_proche(Enum_dure enu_temps,const Coordonnee& M)
{ Element * el_retour=NULL;
  double distance = ConstMath::tresgrand;
  int nbelem = tab_element.Taille();
  Coordonnee G(ParaGlob::Dimension());
  // on balaie les éléments
  for (int ine = 1; ine <= nbelem; ine++)
   {// on commence par calculer le centre de gravité
    G.Zero();
    Tableau <Noeud *> taN = tab_element(ine)->Tab_noeud();
    int nbn = taN.Taille();
    switch (enu_temps)
     { case TEMPS_0:
        for (int inn = 1;inn<=nbn;inn++)
         {Noeud* noe = taN(inn);
          G += noe->Coord0();
         };
        break;
       case TEMPS_t:
        for (int inn = 1;inn<=nbn;inn++)
         {Noeud* noe = taN(inn);
          G += noe->Coord1();
         };
        break;
       case TEMPS_tdt:
        for (int inn = 1;inn<=nbn;inn++)
         {Noeud* noe = taN(inn);
          G += noe->Coord2();
         };
        break;
     };
    G /= nbn;
    double new_distance = (M-G).Norme();
    if (new_distance < distance)
      {el_retour = tab_element(ine);
       distance = new_distance;
      };
   };

 // retour de l'élément
 return el_retour;
};

        
// ramène le maximum de variation de coordonnée entre t et tdt de tous les noeuds du maillage
double Maillage::Max_var_dep_t_a_tdt() const
  { int nbn = tab_noeud.Taille(); double ret=0.;
    for (int i=1;i<=nbn;i++) ret=MaX(tab_noeud(i)->Max_var_coor_t_a_tdt(),ret);
    return ret;  
  };
	  
// ramène le minimum de la distance entre deux noeuds de l'ensemble des éléments 
double Maillage::Min_dist2Noeud_des_elements(Enum_dure temps) const
{ double retour=ConstMath::tresgrand; // init
  // on balaie les éléments
  int taille_elem = tab_element.Taille();
  for (int i=1; i<=taille_elem;i++)
    {  const Tableau<Noeud *>& tab_N_el = tab_element(i)->Tab_noeud();
			    int nbn_loc = tab_N_el.Taille();
			    switch (temps)
				    { case TEMPS_0 :
					      { for (int in = 1;in<=nbn_loc;in++)
					         {const Coordonnee& Ci = tab_N_el(in)->Coord0();
					          for (int jn = in+1;jn<=nbn_loc;jn++)
						          {const Coordonnee& Cj = tab_N_el(jn)->Coord0();
							          retour = MiN(retour,(Ci-Cj).Max_val_abs());
							         };
						        };	
					        break;
					      } 
				      case TEMPS_t :
					      { for (int in = 1;in<=nbn_loc;in++)
			           {const Coordonnee& Ci = tab_N_el(in)->Coord1();
			            for (int jn = in+1;jn<=nbn_loc;jn++)
						          {const Coordonnee& Cj = tab_N_el(jn)->Coord1();
							          retour = MiN(retour,(Ci-Cj).Max_val_abs());
							         };
						        };	
					        break;
					      } 
				      case TEMPS_tdt :
					      { for (int in = 1;in<=nbn_loc;in++)
			           {const Coordonnee& Ci = tab_N_el(in)->Coord2();
			            for (int jn = in+1;jn<=nbn_loc;jn++)
						          {const Coordonnee& Cj = tab_N_el(jn)->Coord2();
							          retour = MiN(retour,(Ci-Cj).Max_val_abs());
							         };
						        };	
					        break;
					      } 
				      default :
					       cout << "\nErreur : valeur incorrecte du type Enum_dure !\n";
					       cout << "Maillage::Min_dist2Noeud_des_elements(... \n";
					       Sortie(1);
			     };
		  };
  return retour;
};

//----- lecture écriture de base info -----
//   lecture base info
// = 1 : on récupère tout
// = 2 : on récupère uniquement les données variables (supposées comme telles)
void Maillage::Lecture_base_info(istream& entr, int cas)
{
 #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
   // === première partie commune à tous les proc
   // normalement tous les buffers ont été rempli, on se contente de rediriger les flux
 #endif

   int nbElement = tab_element.Taille();
   int dime; string toto; int idmail_n; string nomDuMaillage_n;
   bool mono_proc_on_lit_un_BI_multiProc = false;
   Element * pte;
   switch (cas)
    {case 1 : // ------- on récupère tout -------------------------
      {
     #ifdef UTILISATION_MPI
       {// on crée le flux sur le premier buffer:
        istrstream * entrons = new istrstream(buffer_ioBI_MPI(1).c_str(),buffer_ioBI_MPI(1).size()) ;
        istream& entr = *entrons; // on redéfinit entr
     #endif
        entr >> toto ; // entête
        // dans le cas où on lit un fichier créé avec MPI io, et que l'on n'est pas
        // en MPI, on passe les offsets et tailles
      #ifndef UTILISATION_MPI
        if (toto == "buf0_Maillages")
         {for (int i=0;i<3;i++) //
           {toto.clear();
            std::getline(entr, toto);
           };
          mono_proc_on_lit_un_BI_multiProc = true;
         };
      #endif
      
        if (mono_proc_on_lit_un_BI_multiProc) // cas de la lecture en mono
         {entr >>  toto >> idmail_n >> nomDuMaillage_n >> toto >> dime ;}   // d'un fichier créé en multi proc
        else // cas d'une lecture en mono d'un fichier mono
             // ou cas d'une lecture multi d'un fichier créé en multi proc
         {entr >> idmail_n >> nomDuMaillage_n >> toto >> dime;}; //  on a déjà lue toto

//        // l'id et le nom du maillage et la dimension
//        entr >>  toto >> idmail_n >> nomDuMaillage_n >> toto >> dime ;
        // les types de problèmes associés
   //     { types_de_problemes.clear(); int nb=0; // init
   //       entr >> toto >> nb ; string type;
   //       for (int i=1;i<=nb;i++)
   //         {entr >> type;types_de_problemes.push_back(Id_nom_ElemTypeProblem(type));};
   //     };
        { int nb=0; // init
          entr >> toto >> nb ; string type;
          types_de_problemes.Change_taille(nb);
          for (int i=1;i<=nb;i++)
            {entr >> type;types_de_problemes(i)=(Id_nom_ElemTypeProblem(type));};
        };
        // les ddl associés
   //     { ddl_representatifs_des_physiques.clear(); int nb=0; // init
   //       entr >> toto >> nb ; string ddl;
   //       for (int i=1;i<=nb;i++)
   //         {entr >> ddl;ddl_representatifs_des_physiques.push_back(Id_nom_ddl(ddl));};
   //     };
        { int nb=0; // init
          entr >> toto >> nb ; string type;
          ddl_representatifs_des_physiques.Change_taille(nb);
          for (int i=1;i<=nb;i++)
            {entr >> type;ddl_representatifs_des_physiques(i)=(Id_nom_ddl(type));};
        };
        
        // si le nom de maillage lu est différent de celui existant,
        // on supprime le doublet dans la map de gestion et on met à jour
        if (nomDuMaillage != nomDuMaillage_n)
          { listeNomMail.erase(listeNomMail.find(nomDuMaillage));
            nomDuMaillage = nomDuMaillage_n;
            listeNomMail[nomDuMaillage] = idmail_n;
            idmail = idmail_n;
           }
        else
         { // sinon on vérifie quand même que le numéro n'a pas changé
           if (idmail != idmail_n)
             { listeNomMail[nomDuMaillage] = idmail_n;
               idmail = idmail_n;
              };
         };
        if (dime != dimension)
         cout << "\nErreur : valeur de la dimension non coherente avec "
              << " l'espace de travail!\n"
              << "Maillage::Lecture_base_info(istream& sort,int cas)"
              << endl;
        cout << " === lecture du maillage " << nomDuMaillage << " nb " << idmail << "\n" ;
        //------------- lecture des noeuds -------------
        cout << " lecture des noeuds " ;
        // le nombre de noeud
        int nbNoeud = tab_noeud.Taille();
        entr >> nbNoeud >> toto;
        // normalement ici on ne doit pas avoir déjà de noeud
        Change_nb_noeud(nbNoeud); // dimensionnement dynamique du tableau de noeud
        // lecture des noeuds
        Noeud * ptr;
        for (int i=1; i<= nbNoeud; i++)
         { ptr = new Noeud(i,dimension,idmail); // et attribution du numero de maillage
           ptr->Lecture_base_info(entr,cas);
           Affectation_noeud(*ptr);
         };
        // ------------ les elements finis -----------
        cout << ", lecture des elements \n" ;
        entr >> toto;
        // lecture du nombre d'element
        int nbElement;
        entr >> toto >> nbElement;
        // dimensionnement dynamique du tableau d'elements
        Change_nb_element(nbElement);
     #ifdef UTILISATION_MPI
        }; // fin lecture premier buffer
     #endif
        // Lecture des elements
     #ifndef UTILISATION_MPI
        // cas d'un calcul uni-CPU
        for (int i=1; i<= nbElement; i++)
     #else
      // cas d'un calcul //
      if (proc_en_cours != 0) // seules les proc i gèrent les éléments
       {// on récupère la distribution d'éléments concernant le cpu en cours
        const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
        // le nombre d'élément spécifiquement pour le CPU
//        int nbElement_cpu = list_elem_cpu.size();
//        int inter; // le nombre stocké sur le .BI
//        entr >> toto >> inter;
//        // on vérifie que c'est le bon
//        if (inter != nbElement_cpu)
//          { cout << "\nErreur : le nombre d'element a lire: " << nbElement_cpu
//                 << " est different de celui stocke sur le .BI: " << inter
//                 << "\n cas d'un calcul parallele avec lecture initiale du .BI, cpu nb:"
//                 << ParaGlob::Monde()->rank() << " !! "
//                 << "\n Maillage::Lecture_base_info(istream& sort,int cas)"
//                 << endl;
//            Sortie (1);
//          };
        // lecture des éléments
        // on balaie les éléments nécessaires
        list <int >::const_iterator il,ilfin=list_elem_cpu.end();
        for (il = list_elem_cpu.begin();il != ilfin;il++)
         {int i = (*il);
          // pour chaque élément il y a un buffer particulier, d'où un flux particulier
          istrstream * entrons = new istrstream(buffer_ioBI_MPI(1+i).c_str(),les_taille_buffer_ioBI_MPI[i-1]) ;
          istream& entr = *entrons; // redéfinition

     #endif
          { // lecture geometrie et interpolation
            Enum_geom id_geom; Enum_interpol id_interpol;
            EnumElemTypeProblem  id_typeProb;string str_precision;
            int num_elt; // donnee dont on ne se sert pas
            entr >>  toto >> num_elt  >> id_geom >> id_interpol >> id_typeProb;
            // on regarde  le prochain caractère sans changer le flot
            /////int cr=entr.peek();
            //--- début du remplacement du peek
            char car = Picococar(entr); // = flot.peek();
            // on recupère l'entier correspondant au caractère
            int cr = int(car);
            //--- fin du remplacement du peek
            // on regarde s'il y a une chaine discriminante
            if (cr == int('_')) entr >> str_precision;
            // ======== choix de l'element =====================================
            // et affectation du 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
            pte = Element::Choix_element(idmail,num_elt,id_geom,id_interpol,id_typeProb,str_precision);
            if (pte == NULL)
                { // l'operation a echouee
                  cout << "\n Erreur dans le choix d'element ****** ";
                  cout << "\n l\'element : " << Nom_interpol(id_interpol)
                       << " " << Nom_geom(id_geom)
                       << " n\'est pas present dans le programme ! "
                       << "\n Maillage::Lecture_base_info(..." << endl;
                  Sortie (1);
                };
            // lecture des infos particulieres a l'element
            Tableau<Noeud*> * pt = & tab_noeud;
            pte->Lecture_base_info(entr,pt,cas);
            Affectation_element(*pte);
            // si c'est le premier élément du premier maillage on regarde s'il s'agit
            // d'un élément axisymétrique et on adapte l'espace de travail en conséquence
            if ((i==1) && (idmail==1))
               { if (TestEnum_geom_axisymetrique(id_geom))
                    ParaGlob::Change_en_AxiSymetrie();
               }
            else
               {// dans le cas des autres éléments on vérifie qu'ils ne sont pas incohérent
                if (TestEnum_geom_axisymetrique(id_geom) != (ParaGlob::AxiSymetrie()))
                 {cout << "\n **** erreur en definition de l'element " << num_elt <<" du maillage " << idmail
                       << " nom= " <<  nomDuMaillage;
                  if (ParaGlob::AxiSymetrie())
                   cout << "\n incoherence : l'espace de travail n'est pas axisymetrique (definit par les precedents elements)"
                         << " et l'element lu est axisymetrique !! ";
                  else
                   cout << "\n incoherence : l'espace de travail est axisymetrique (definit par les precedents elements)"
                         << " et l'element lu n'est pas axisymetrique !! ";
                    cout << endl;
                    Sortie (1);
                 };
               };
           }
      #ifdef UTILISATION_MPI
         };
        }; // fin cas d'un calcul //
       {// on crée le flux sur le dernier buffer:
          istrstream * entrons = new istrstream(buffer_ioBI_MPI(2+nbElement).c_str(),buffer_ioBI_MPI(2+nbElement).size()) ;
          istream& entr = *entrons; // redéfinition
      #endif
        entr >> toto; // lecture de "---fin_maillage---"
#ifdef MISE_AU_POINT
        if (toto != "---fin_maillage---")
          { cout << "\nErreur : on a lue: "<< toto <<", alors que l'on attendait ---fin_maillage--- !\n";
            cout << "Maillage::Lecture_base_info(istream& sort,int cas)"
                 << " cas= " << cas << endl;
            Sortie(1);
          };
#endif
      #ifdef UTILISATION_MPI
       }; // fin dernier buffer
      #endif

        // ------------ les elements frontières -----------
        // il sont créé par ailleurs si il y en a besoin
        break;
       }
       case  2 : // ----------- lecture uniquement de se qui varie --------------------
       {// le nom du maillage pour vérification
   //    cout << "\n debug **** Maillage::Lecture_base_info\n"
   //         << "\n entr.rdstate() " << entr.rdstate() << flush;
   //entr.clear();
     #ifdef UTILISATION_MPI
       {// on crée le flux sur le premier buffer:
        istrstream * entrons = new istrstream(buffer_ioBI_MPI(1).c_str(),buffer_ioBI_MPI(1).size()) ;
        istream& entr = *entrons; // redéfinition
     #endif
        string inter,nomDuMail;
//        entr >> inter >> nomDuMail ;
        
        entr >> inter ; // entête
        // dans le cas où on lit un fichier créé avec MPI io, et que l'on n'est pas
        // en MPI, on passe les offsets et tailles
      #ifndef UTILISATION_MPI
        if (inter == "buf0_Maillages")
         {for (int i=0;i<3;i++) //
           {inter.clear();
            std::getline(entr, inter);
           };
          mono_proc_on_lit_un_BI_multiProc = true;
         };
      #endif
        if (mono_proc_on_lit_un_BI_multiProc) // cas de la lecture en mono
         {entr >> inter >> nomDuMail;}   // d'un fichier créé en multi proc
        else // cas d'une lecture en mono d'un fichier mono
             // ou cas d'une lecture multi d'un fichier créé en multi proc
         {entr >> nomDuMail;}; //  on a déjà lue toto

        if (nomDuMail != nomDuMaillage)
         { cout << "\nErreur : le nom du maillage lu (" << nomDuMail << ") n'est pas identique avec celui en cours ("
                << nomDuMaillage << ") !! "
                << "\n Maillage::Lecture_base_info(istream& sort,int cas)"
                << endl;
           Sortie (1);
         };
        //------------- les noeuds -------------
        // le tableau doit être déjà dimensionné
        int nbNoeud = tab_noeud.Taille();
        for (int i=1; i<=nbNoeud;i++)
          tab_noeud(i)->Lecture_base_info(entr,cas);
    #ifdef UTILISATION_MPI
       }; // fin lecture premier buffer
    #endif
        // ------------ les elements finis -----------
        Tableau<Noeud*> * pt = & tab_noeud;
        int nb;string toto;
      #ifndef UTILISATION_MPI
        // cas d'un calcul uni-CPU
        for (int j=1;j<=nbElement;j++)
      #else
      // cas d'un calcul //
      if (proc_en_cours != 0) // seules les proc i gèrent les éléments
       {// on récupère la distribution d'éléments concernant le cpu en cours
        const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
        // le nombre d'élément spécifiquement pour le CPU
        int nbElement_cpu = list_elem_cpu.size();
//        int intera; // le nombre stocké sur le .BI
//        entr >> toto >> intera;
//        // on vérifie que c'est le bon
//        if (intera != nbElement_cpu)
//          { cout << "\nErreur : le nombre d'element a lire: " << nbElement_cpu
//                 << " est different de celui stocke sur le .BI: " << inter
//                 << "\n cas d'un calcul parallele avec lecture courante du .BI, cpu nb:"
//                 << ParaGlob::Monde()->rank() << " !! "
//                 << "\n Maillage::Lecture_base_info(istream& sort,int cas)"
//                 << endl;
//            Sortie (1);
//          };
        // lecture des éléments
        // on balaie les éléments nécessaires
        list <int >::const_iterator il,ilfin=list_elem_cpu.end();
        for (il = list_elem_cpu.begin();il != ilfin;il++)
         {int j = (*il);
          // pour chaque élément il y a un buffer particulier, d'où un flux particulier
          istrstream * entrons = new istrstream(buffer_ioBI_MPI(1+j).c_str(),les_taille_buffer_ioBI_MPI[j-1]) ;
          istream& entr = *entrons;

      #endif
           {entr >> toto >> nb; // le numéro de l'élément
            tab_element(j)->Lecture_base_info(entr,pt,cas);
           };
      #ifdef UTILISATION_MPI
         // fin cas d'un calcul //
         };
       }; // fin cas d'un calcul //
       {// on crée le flux sur le dernier buffer:
          istrstream * entrons = new istrstream(buffer_ioBI_MPI(2+nbElement).c_str(),buffer_ioBI_MPI(2+nbElement).size()) ;
          istream& entr = *entrons; // redéfinition
      #endif

        entr >> toto; // lecture de "---fin_maillage---"
#ifdef MISE_AU_POINT
        if (toto != "---fin_maillage---")
          { cout << "\nErreur : on a lue: "<< toto <<", alors que l'on attendait ---fin_maillage--- !\n";
            cout << "Maillage::Lecture_base_info(istream& sort,int cas)"
                 << " cas= " << cas << endl;
            Sortie(1);
          };
#endif
      #ifdef UTILISATION_MPI
       }; // fin dernier buffer
      #endif
        // ------------ les elements frontières -----------
        // il sont créé par ailleurs si il y en a besoin
        break;
       }
       default :
        { cout << "\nErreur : valeur incorrecte du type de lecture !\n";
          cout << "Maillage::Lecture_base_info(istream& sort,int cas)"
               << " cas= " << cas << endl;
          Sortie(1);
        };
     };
};
        
//   écriture base info   
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Maillage::Ecriture_base_info(ostream& sort, int cas)
{
 // le nombre d'élément total
 int nbElement = tab_element.Taille();
#ifdef UTILISATION_MPI
 int proc_en_cours = ParaGlob::Monde()->rank();
 // 1) dans le cas d'un proc 0 ou i, on redéfinit le flux de sortie, pour bufferiser les infos en sortie
 // qui sont ensuite sortie via MPI i-o à l'aide de la méthode Ecriture_base_info_MPI_IO
 // les récupérations et les sorties sont effectuées de manière asynchrone par rapport aux autres proc
 // 2) seul le proc 0 sort l'entête et les noeuds
 // 3) seules les proc i sortent les éléments
 
 // dimensionnement, si les tailles sont inchangées, aucune action
 les_taille_buffer_ioBI_MPI.resize(nbElement);
 les_taille_buffer_ioBI_MPI.assign(nbElement,0); // init

 int taille_buffer_ioBI_MPI =  nbElement + 2; // cf. le .h
 buffer_ioBI_MPI.Change_taille(taille_buffer_ioBI_MPI); // si c'est la bonne taille aucune action

#endif

 switch (cas)
  { case 1 : // ------- on sauvegarde tout -------------------------
    {
  #ifdef UTILISATION_MPI
     
     if (proc_en_cours == 0) // première partie dédié proc 0
       {std::ostringstream sort; // redéfinition de sort
  #endif
        // l'id et le nom du maillage et la dimension
        sort << "\n num= " << idmail <<"  "<< nomDuMaillage <<" "
             << "dim= " << dimension;
        // les types de problèmes associés
        {int tail = types_de_problemes.Taille();
         sort <<"\n types_de_problemes: " << tail ;
         for (int i=1;i<=tail;i++)
           sort << " "<< NomElemTypeProblem(types_de_problemes(i));
        };
     
        // les ddl associés
        {int tail = ddl_representatifs_des_physiques.Taille();
         sort <<"\n type_de_ddl_associes: " << tail;
         for (int i=1;i<=tail;i++)
           sort << " "<< Nom_ddl(ddl_representatifs_des_physiques(i));
        };
     
        sort <<"\n";
        //------------- les noeuds -------------
        // le nombre de noeud
        int nbNoeud = tab_noeud.Taille();
        sort << nbNoeud << " noeuds \n";
        // sorti des noeuds
        for (int i=1; i<=nbNoeud;i++)
          tab_noeud(i)->Ecriture_base_info(sort,cas);
        // ------------ les elements finis -----------
        sort << "\n --les_elements-- ";
        sort <<"\n nombre_total_element " << nbElement ;
  #ifdef UTILISATION_MPI
        sort << "\n ";
        buffer_ioBI_MPI(1) = sort.str(); // on sauvegarde
     }
  #endif

     
     // écriture des éléments
  #ifndef UTILISATION_MPI
     // cas d'un calcul uni-CPU
     for (int j=1;j<=nbElement;j++)
      {
  #else
     if (proc_en_cours != 0) // seules les proc i gèrent les éléments
       {// on récupère la distribution d'éléments concernant le cpu en cours
        const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
        // écriture des éléments
        // on balaie les éléments nécessaires
        list <int >::const_iterator il,ilfin=list_elem_cpu.end();
        for (il = list_elem_cpu.begin();il != ilfin;il++)
         {int j = (*il);
          std::stringstream sort; // redéfinition de sort
  #endif
            { // tout d'abord les données de différentiation
              // numéro geometrie et interpolation
               sort << "\n\n element: " << tab_element(j)->Num_elt() << " "
                    << tab_element(j)->Id_geometrie() << " "
                    << tab_element(j)->Interpolation() << " "
                    << tab_element(j)->TypeProblem() << " "
                    << tab_element(j)->Infos_annexe() << "\n";
               // puis les données de l'élément
               tab_element(j)->Ecriture_base_info(sort,cas);
             };
  #ifdef UTILISATION_MPI
          buffer_ioBI_MPI(j+1) = sort.str(); // on sauvegarde
          //les_taille_buffer_ioBI_MPI[0] -> donne la première partie donc [i] donne l'élément i
          les_taille_buffer_ioBI_MPI[j-1] = buffer_ioBI_MPI(j+1).size();
         };
       }
     else // cas du proc 0
       {// sortie du retour à la ligne
        std::stringstream sort; // redéfinition de sort
        sort << "\n ---fin_maillage--- \n";
        buffer_ioBI_MPI(2+nbElement) = sort.str(); // on sauvegarde
       } ;
  #endif
   
  #ifndef UTILISATION_MPI
      };
     sort << "\n ---fin_maillage--- \n";
//     sort << "\n ";
  #endif
     // ------------ les elements frontières -----------
     // ne sont pas sauvegardé car reconstruit à la demande
	    break;
    }
    case  2 : // ----------- sauvegarde uniquement de se qui varie --------------------
    {
  #ifdef UTILISATION_MPI
     if (proc_en_cours == 0) // première partie dédié proc 0
       {std::ostringstream sort; // redéfinition de sort
  #endif
        // le nom du maillage pour vérification en lecture
        sort << "\nnomDuMail= " <<  nomDuMaillage << "\n";
        //------------- les noeuds -------------
        int nbNoeud = tab_noeud.Taille();
        // sorti des noeuds
        for (int i=1; i<=nbNoeud;i++)
          tab_noeud(i)->Ecriture_base_info(sort,cas);
       
  #ifdef UTILISATION_MPI
        sort << "\n ";
        buffer_ioBI_MPI(1) = sort.str(); // on sauvegarde
       };
  #endif
       
     // ------------ les elements finis -----------
     int nbElement = tab_element.Taille();
  #ifndef UTILISATION_MPI
     // cas d'un calcul uni-CPU
     for (int j=1;j<=nbElement;j++)
  #else
     if (proc_en_cours != 0) // seules les proc i gèrent les éléments
      {// on récupère la distribution d'éléments concernant le cpu en cours
       const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
       // écriture des éléments
       // on balaie les éléments nécessaires
       list <int >::const_iterator il,ilfin=list_elem_cpu.end();
       int indice_buffer_ioBI_MPI=2;
       for (il = list_elem_cpu.begin();il != ilfin;il++,indice_buffer_ioBI_MPI++)
        {int j = (*il);
         std::stringstream sort; // redéfinition de sort pour chaque élément
  #endif
         {sort << "\n\n element_nb: " << tab_element(j)->Num_elt() << " ";
          tab_element(j)->Ecriture_base_info(sort,cas);
         };
  #ifdef UTILISATION_MPI
         buffer_ioBI_MPI(j+1) = sort.str(); // sauvegarde particulière pour l'élément
         les_taille_buffer_ioBI_MPI[j-1] = buffer_ioBI_MPI(j+1).size();
        }; // fin boucle éléments
      }
     else // cas du proc 0
      {// sortie du retour à la ligne
       std::stringstream sort; // redéfinition de sort
       sort << "\n ---fin_maillage--- \n";
       buffer_ioBI_MPI(2+nbElement) = sort.str(); // on sauvegarde
      } ;
  #endif

  #ifndef UTILISATION_MPI
     sort << "\n ---fin_maillage--- \n";
//     sort << "\n ";
  #endif
      // ------------ les elements frontières -----------
      // ne sont pas sauvegardé car reconstruit à la demande
     
     break;
    }
    default :
	    { cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n";
       cout << "Maillage::Ecriture_base_info(ostream& sort,int cas)"
			         << " cas= " << cas << endl;
	      Sortie(1);
	    };
  };
  
 #ifdef UTILISATION_MPI
 
  // on transmet à proc 0 les tailles de buffer (concerne uniquement les éléments),
  // il faut de toute manière que proc 0 centralise toutes les tailles
  // avant de pouvoir calculer les offsets qu'il transmet ensuite à proc i, il faut faire une transmission avec accusé de réception
  if (proc_en_cours != 0)
   { mpi::request reqs2 = ParaGlob::Monde()->isend(0, 9867, les_taille_buffer_ioBI_MPI);
     reqs2.wait();
   }
  else // récup des buffers par le proc 0
   { int nb_proc_terminer = 0; // permettra de terminer
     les_taille_buffer_ioBI_MPI_inter.resize(nbElement);
     // on initialise les_taille_buffer_ioBI_MPI
     les_taille_buffer_ioBI_MPI.assign(nbElement,0);
     while (nb_proc_terminer < (ParaGlob::Monde()->size()-1)) // gérer par les valeurs de tyfront
       { // on récupère un résultat de cpu i
         mpi::request reqs2 = ParaGlob::Monde()->irecv(mpi::any_source, 9867, les_taille_buffer_ioBI_MPI_inter);
         reqs2.wait(); // on attend que le conteneur soit rempli
//         mpi::status  stat = reqs2.wait(); // on attend que le conteneur soit rempli
//         int source = stat.source(); // récupération du numéro de la source
//         // on récupère la distribution d'éléments concernant le cpu en cours
//         const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
//         // écriture des éléments
//         // on balaie les éléments nécessaires
//         list <int >::const_iterator il,ilfin=list_elem_cpu.end();
//         int indice_buffer_ioBI_MPI=2;
//         for (il = list_elem_cpu.begin();il != ilfin;il++,indice_buffer_ioBI_MPI++)
//          {int j = (*il);
//           les_taille_buffer_ioBI_MPI[j-1] = les_taille_buffer_ioBI_MPI_inter[j-1];
//          };
//

         nb_proc_terminer++; //  on prend en compte que l'on a récupéré un conteneur
         // on met à jour
         for (int i=0;i< nbElement;i++)
           les_taille_buffer_ioBI_MPI[i] += les_taille_buffer_ioBI_MPI_inter[i];
       };
   };
   
  // on synchronise les proc pour éviter qu'un proc travaille sur un maillage différent d'un autre
  // au niveau du passage d'info
  ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process

 #endif
};

#ifdef UTILISATION_MPI
   
// retour de la taille globale des sorties retardées gérées par par LesMaillages
// concernant les sorties sur .BI
// seul le retour de proc 0 est licite
MPI_Offset Maillage::Taille_buffer_sortie_BI()
  { MPI_Offset taille = 0; // init
    int proc_en_cours = ParaGlob::Monde()->rank();
    int nb_element = tab_element.Taille();
    if (proc_en_cours == 0)
     { MPI_Offset taille_entete = 38 + (nb_element+3)*21+27; // cf. Maillage::Ecriture_base_info_MPI_IO
       taille += buffer_ioBI_MPI(1).size() + taille_entete;
       taille += buffer_ioBI_MPI(2+nb_element).size();
     }
    else // cas des proc i != 0
     { for (int i=1;i<= nb_element;i++)
         taille += buffer_ioBI_MPI(i+1).size();
     };
    // il faut sommer sur tous les proc
    MPI_Offset taille_totale= 0; // init
    // la somme s'effectue vers le proc 0
    reduce(*ParaGlob::Monde(), taille, taille_totale, std::plus<MPI_Offset>(), 0);
//    if (proc_en_cours == 0)
//     { cout << "\n Maillage::Taille_buffer_sortie_BI() taille_totale = "<<taille_totale << endl;
//     };
    // retour
    return taille_totale; // seul le retour de proc 0 est licite
  };
  
// récupération de l'offset global sur .BI pour la classe
// et mise à jour des offsets de classes dérivées si besoin
void Maillage::Mise_a_jour_Offset_BI_ecriture(MPI_Offset offset,const int cas)
 {
  int proc_en_cours = ParaGlob::Monde()->rank();
  int nb_element = tab_element.Taille();
  offset_maillage.resize(3+nb_element); // d'où de [0] à [2+nb_element]
  if (proc_en_cours == 0)
   {// on commence par prendre en compte l'offset général
    offset_maillage[0] = offset;
    // puis on intègre la taille de l'ensemble des offsets:
    MPI_Offset taille_entete = 38 + (nb_element+3)*21+27; // cf. Maillage::Ecriture_base_info_MPI_IO
    offset_maillage[1] = offset + taille_entete + buffer_ioBI_MPI(1).size(); // position pour le premier élément
    // on calcule l'offset spécifique pour chaque élément
    // NB: les_taille_buffer_ioBI_MPI_inter de chaque proc, ont été transmises des proc i vers
    //     proc 0 à la fin de la méthode: Ecriture_base_info
    MPI_Offset offset_courant = offset_maillage[1]; // init
    for(int ne=1; ne <= nb_element; ne++)
      {// les_taille_buffer_ioBI_MPI[k-1] -> donne la taille du buffer pour l'élément k
       offset_courant += les_taille_buffer_ioBI_MPI[ne-1]; // taille du buffer de ne
       offset_maillage[ne+1] = offset_courant;   // position pour l'élément ne+1 sauf pour le dernier
          // on a pour le dernier offset_maillage[nb_element+1]  correspond au début du second buffer
          // propre
      };
    // puis les 2 dernier offsets qui servent en fait que pour le proc 0
    // offset_maillage[nb_element+1] viens d'être calculé
    // buffer_ioBI_MPI(k+1) : élément k (k== numéro d'ordre de l'élément dans le tableau tab_element)
    offset_maillage[nb_element+2] = offset_maillage[nb_element+1]+buffer_ioBI_MPI(2+nb_element).size();
    // offset_maillage[nb_element+2] correspond à la fin
   };
  // le proc 0 transmet les tailles et les offsets des éléments à tous les proc
  broadcast(*ParaGlob::Monde(), les_taille_buffer_ioBI_MPI, 0); // peut-être pas nécessaire ??
  broadcast(*ParaGlob::Monde(), offset_maillage, 0);

 };
// idem en lecture, mais là il s'agit uniquement de la mise à jour
// de l'offset seul puis c'est la classe qui s'en débrouille
void Maillage::Mise_a_jour_Offset_BI_lecture(MPI_Offset offset,const int cas)
  {MPI_Offset taille_offset = tab_element.Taille()+3;
   offset_maillage.resize(taille_offset);
   offset_maillage[0] = offset;
  };

// Lecture des offsets MPI des infos bufferisées
void Maillage::Lecture_offset_base_info_MPI_IO
           (//MPI_Offset offset_gene,
           MPI_File * ent_MPI,const int cas)
 {
  int proc_en_cours = ParaGlob::Monde()->rank();
  // tous les proc lisent
  int nb_element = tab_element.Taille();
//  // on initialise tous les offsets
//  int ierr = MPI_File_seek_shared(*ent_MPI,offset_gene,MPI_SEEK_SET);


  // 1) ==== la taille de l'ensemble des offsets
  MPI_Offset taille_buf = 0; // init
  // on encapsule pour ré-utiliser la même trame
  { char * buffer_car = new char [38] ; // def du tableau de travail
    MPI_Status status;
    int ierr = MPI_File_read_all(*ent_MPI, buffer_car, 38, MPI_CHAR, &status);
    if (ierr)
      {cout << "\n *** erreur d'acces a MPI_File_read_all: code " << ierr << " , stop Herezh "
            << "\n proc "<<proc_en_cours << ", lecture  de la taille de l'ensemble des offsets "
            << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
       Sortie(1);
      };
    // on crée un flux sur le tableau de caractères:
    istrstream * ent_inter = new istrstream(buffer_car,38) ;
    // lecture de l'entête
    string toto;
    (*ent_inter) >> toto;
    if (toto != "buf0_Maillages" )
      {cout << "\n **** erreur on devait lire : 'buf0_Maillages' "
            << " et on lue "<< toto << " la suite n'est pas possible -> arret !! "
            << "\n Maillage::Lecture_offset_base_info_MPI_IO(... "<<endl;
       Sortie(1);
      };
    // on lit la taille de buf2
    (*ent_inter)  >> taille_buf;
  };
  
  // 2) ==== lecture des offsets
  { char * buffer_car = new char [taille_buf] ; // def du tableau de travail
    MPI_Status status;
    int ierr = MPI_File_read_all(*ent_MPI, buffer_car, taille_buf, MPI_CHAR, &status);
    if (ierr)
      {cout << "\n *** erreur d'acces a MPI_File_read_all: code " << ierr << " , stop Herezh "
            << "\n proc "<<proc_en_cours << ", lecture   des offsets "
            << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
       Sortie(1);
      };
    // on crée un flux sur le tableau de caractères:
    istrstream * ent_inter = new istrstream(buffer_car,taille_buf) ;
    // lecture de l'entête
    string toto;
    (*ent_inter) >> toto;
    if (toto != "offset_base_info_MPI_IO" )
      {cout << "\n **** erreur on devait lire : 'offset_base_info_MPI_IO' "
            << " et on lue "<< toto << " la suite n'est pas possible -> arret !! "
            << "\n Maillage::Lecture_offset_base_info_MPI_IO(... "<<endl;
       Sortie(1);
      };
    // on lit les offsets
    MPI_Offset taille_offset = nb_element+3;
    offset_maillage.resize(taille_offset);
    for (MPI_Offset i=0;i<taille_offset;i++)
      (*ent_inter) >>  offset_maillage[i];
  };
  
  // 3) ==== on dimensionne  les_taille_buffer_ioBI_MPI
  // on initialise les_taille_buffer_ioBI_MPI
  les_taille_buffer_ioBI_MPI.resize(nb_element);

  for (int ne = 1;ne<=nb_element;ne++)
     les_taille_buffer_ioBI_MPI[ne-1] = offset_maillage[ne+1] - offset_maillage[ne];

 };

// lecture MPI des infos bufferisées
void Maillage::Lecture_base_info_MPI_IO(MPI_File * ent_MPI,const int cas)
 {
  int proc_en_cours = ParaGlob::Monde()->rank();
  // on lit tout d'abord les offsets
  Maillage::Lecture_offset_base_info_MPI_IO(ent_MPI,cas);
  int nb_element = tab_element.Taille();
  buffer_ioBI_MPI.Change_taille(nb_element+2);

  // tous les proc lisent l'entête et les noeuds ce qui correspond au premier buffer de proc 0
  {//premier buffer
   MPI_Offset taille_entete = 38 + (nb_element+3)*21+27; // cf. Maillage::Ecriture_base_info_MPI_IO
   MPI_Offset taille_buf = offset_maillage[1] - (offset_maillage[0]+taille_entete);
   char *  buffer_car = new char [taille_buf] ; // def du tableau de travail
   MPI_Status status;
   int ierr = MPI_File_read_all(*ent_MPI, buffer_car, taille_buf, MPI_CHAR, &status);
   if (ierr)
     {cout << "\n *** erreur d'acces a MPI_File_read_all: code " << ierr << " , stop Herezh "
           << "\n proc "<<proc_en_cours << ", lecture  buffer1 "
           << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
      Sortie(1);
     };
   buffer_ioBI_MPI(1).resize(taille_buf);
   buffer_ioBI_MPI(1).replace(0,taille_buf,buffer_car);
//   buffer_ioBI_MPI(1).copy(buffer_car,taille_buf);
  }; // fin premier buffer
  
  // chaque proc i lit ses propres buffers
  if (proc_en_cours != 0)
   { // pour chaque éléments:
     // 1) on se positionne sur l'offset associé
     // 2) on lit le buffer
     
     // on récupère la distribution d'éléments concernant le cpu en cours
     const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
     // le nombre d'élément spécifiquement pour le CPU
     int nbElement_cpu = list_elem_cpu.size();
     // on balaie les éléments nécessaires
     list <int >::const_iterator il,ilfin=list_elem_cpu.end();
     MPI_Offset indice_buffer_ioBI_MPI=2;
     for (il = list_elem_cpu.begin();il != ilfin;il++,indice_buffer_ioBI_MPI++)
      {int j = (*il);
       MPI_Offset offset = offset_maillage[j]; // récup de l'offset
       int ierr = MPI_File_seek(*ent_MPI, offset, MPI_SEEK_SET); // positionnement
       if (ierr) // traitement erreur éventuelle
           {cout << "\n *** erreur de positionnement MPI_File_seek: code " << ierr << " , stop Herezh "
                 << "\n proc: "<<proc_en_cours
                 << ", pour l'element " << j << " "
                 << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
            Sortie(1);
           };
       MPI_Offset taille_buf = les_taille_buffer_ioBI_MPI[j-1];
       char *  buffer_car = new char [taille_buf] ; // def du tableau de travail
       MPI_Status status;
       ierr = MPI_File_read(*ent_MPI,buffer_car,taille_buf,MPI_CHAR,&status);
       if (ierr) // traitement erreur éventuelle
           {cout << "\n *** erreur de lecture MPI_File_read: code " << ierr << " , stop Herezh "
                 << "\n proc: "<<proc_en_cours
                 << ", lecture buffer de l'element " << j << " "
                 << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
            Sortie(1);
           };
       buffer_ioBI_MPI(1+j).resize(taille_buf);
       buffer_ioBI_MPI(1+j).replace(0,taille_buf,buffer_car);
//      buffer_ioBI_MPI(1+j).copy(buffer_car,taille_buf);
      };
   };
  
  // tous les proc lisent le dernier buffer
  {// on initialise tous les offsets au cas où
  
   int ierr = MPI_File_seek(*ent_MPI,offset_maillage[nb_element+1],MPI_SEEK_SET);
   MPI_Offset taille_buf = offset_maillage[nb_element+2] - offset_maillage[nb_element+1];
   char *  buffer_car = new char [taille_buf] ; // def du tableau de travail
   MPI_Status status;
   ierr = MPI_File_read_all(*ent_MPI, buffer_car, taille_buf, MPI_CHAR, &status);
   if (ierr)
     {cout << "\n *** erreur d'acces a MPI_File_read_all: code " << ierr << " , stop Herezh "
           << "\n proc " << proc_en_cours << ", lecture   "
           << "\n Maillage::Lecture_base_info_MPI_IO(..." << endl;
      Sortie(1);
     };
   buffer_ioBI_MPI(2+nb_element).resize(taille_buf);
   buffer_ioBI_MPI(2+nb_element).replace(0,taille_buf,buffer_car);
   //   buffer_ioBI_MPI(2+nb_element).copy(buffer_car,taille_buf);
  }; // fin du deuxième buffer
 
 };

// écriture MPI des infos bufferisées
void Maillage::Ecriture_base_info_MPI_IO(MPI_File * sort_MPI,const int cas)
 {
   int proc_en_cours = ParaGlob::Monde()->rank();
   if (proc_en_cours == 0)
    {//  === écriture dans flot string de la taille des buffers propres
      // ici c'est le premier et le dernier élément des buffers
      // pour avoir une sortie lisible, on crée tout d'abord un buffer string avec les infos
      std::ostringstream buf2(std::ios_base::out);
      buf2 << "\n offset_base_info_MPI_IO \n"; // 27 char
      MPI_Offset taille_offset = offset_maillage.size(); // 3+nb_element
      int nb_element = tab_element.Taille();
      #ifdef MISE_AU_POINT
       if (taille_offset != (nb_element+3))
         {cout << "\n *** sans doute erreur, taille_offset "<<taille_offset
               << " est  different de nb_element+3 ="<<nb_element+3
               << "\n  Maillage::Ecriture_base_info_MPI_IO(..." << endl;
          Sortie(1);
         };
      #endif
      
      for (MPI_Offset i=0;i<taille_offset;i++)
        // on sort donc (3+nb_element)*21 char
        {buf2 << std::right << setw(20) << offset_maillage[i] ;
         buf2 << " ";
        };
       
      // le buffer du stream n'est pas pérenne il faut le récupérer
      string buf_inter = buf2.str(); // on récupère le buffer
      MPI_Offset taille_buf = buf_inter.size(); // doit faire 27+(3+nb_element)*20 char
      #ifdef MISE_AU_POINT
       if (taille_buf != (nb_element+3)*21+27)
         {cout << "\n *** sans doute erreur, taille_buf "<<taille_buf
               << " est  different de (nb_element+3)*21+27 ="<<(nb_element+3)*21+27
               << "\n  Maillage::Ecriture_base_info_MPI_IO(..." << endl;
          Sortie(1);
         };
      #endif
     
      // 1) ==== écriture de la taille de l'ensemble des offsets
      // on encapsule pour ré-utiliser la même trame
      {
        std::ostringstream bufdeb(std::ios_base::out);
        bufdeb << "\n buf0_Maillages "; // 17 char
        bufdeb << std::right << setw(20) << taille_buf; // on justifie à droite et on utilise 20 char
        bufdeb << " "; // 1 char
        string buf_inter = bufdeb.str(); // normalement 38 char
        // sortie sur fichier de la taille de buf2
        MPI_Offset offset = offset_maillage[0]; // récup de l'offset
        int ierr = MPI_File_seek(*sort_MPI, offset, MPI_SEEK_SET); // positionnement
        if (ierr) // traitement erreur éventuelle
            {cout << "\n *** erreur de positionnement MPI_File_seek: code " << ierr << " , stop Herezh "
                  << "\n proc 0, ecriture buf0_Maillages "
                  << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
             Sortie(1);
            };
        MPI_Status status; // pour le retour
        ierr = MPI_File_write(*sort_MPI,buf_inter.c_str(),38,MPI_CHAR,&status);
        if (ierr)
          {cout << "\n *** erreur d'acces a MPI_File_write: code " << ierr << " , stop Herezh "
                << "\n proc 0, ecriture entete buffer "
                << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
           Sortie(1);
          };
      };

      // 2) ==== écriture des offsets c-a-d sortie sur fichier de buf2
      { MPI_Status status; // pour le retour
        int ierr = MPI_File_write(*sort_MPI,buf_inter.c_str(),taille_buf,MPI_CHAR,&status);
        if (ierr)
          {cout << "\n *** erreur d'acces a MPI_File_write: code " << ierr << " , stop Herezh "
                << "\n proc 0, ecriture des offsets "
                << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
           Sortie(1);
          };
      };

      // 3) ==== écriture du premier buffer propre
      { MPI_Status status; // pour le retour
        int ierr = MPI_File_write(*sort_MPI,buffer_ioBI_MPI(1).c_str()
                                     ,buffer_ioBI_MPI(1).size(),MPI_CHAR,&status);
        if (ierr)
            {cout << "\n *** erreur d'acces a MPI_File_write: code " << ierr << " , stop Herezh "
                  << "\n proc 0, ecriture premier buffer propre "
                  << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
             Sortie(1);
            };
      };

      // 4) ==== écriture du dernier buffer propre
      { int nb_element = tab_element.Taille();
        MPI_Offset offset = offset_maillage[nb_element+1]; // récup de l'offset
        int ierr = MPI_File_seek(*sort_MPI, offset, MPI_SEEK_SET); // positionnement
        if (ierr) // traitement erreur éventuelle
            {cout << "\n *** erreur de positionnement MPI_File_seek: code " << ierr << " , stop Herezh "
                  << "\n proc 0, ecriture dernier buffer propre "
                  << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
             Sortie(1);
            };
        MPI_Status status; // pour le retour
        ierr = MPI_File_write(*sort_MPI,buffer_ioBI_MPI(2+nb_element).c_str()
                                     ,buffer_ioBI_MPI(2+nb_element).size(),MPI_CHAR,&status);
        if (ierr)
            {cout << "\n *** erreur d'acces a MPI_File_write: code " << ierr << " , stop Herezh "
                  << "\n proc 0, ecriture dernier buffer propre "
                  << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
             Sortie(1);
            };
      };

    };
    
   // écriture des éléments
   if (proc_en_cours != 0)
    {// pour chaque éléments:
     // 1) on se positionne sur l'offset associé
     // 2) on écrit le buffer
     
     // on récupère la distribution d'éléments concernant le cpu en cours
     const list <int >  list_elem_cpu = ParaGlob::param->const_List_element_CPU_en_cours(idmail);
     // le nombre d'élément spécifiquement pour le CPU
     int nbElement_cpu = list_elem_cpu.size();
     // écriture des éléments
     // on balaie les éléments nécessaires
     list <int >::const_iterator il,ilfin=list_elem_cpu.end();
     int indice_buffer_ioBI_MPI=2;
     for (il = list_elem_cpu.begin();il != ilfin;il++,indice_buffer_ioBI_MPI++)
      {int j = (*il);
       MPI_Offset offset = offset_maillage[j]; // récup de l'offset
       int ierr = MPI_File_seek(*sort_MPI, offset, MPI_SEEK_SET); // positionnement
       if (ierr) // traitement erreur éventuelle
           {cout << "\n *** erreur de positionnement MPI_File_write: code " << ierr << " , stop Herezh "
                 << "\n proc: "<<proc_en_cours
                 << ", pour l'element " << j << " "
                 << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
            Sortie(1);
           };
       MPI_Status status; // pour le retour
       ierr = MPI_File_write(*sort_MPI,buffer_ioBI_MPI(1+j).c_str()
                             ,buffer_ioBI_MPI(1+j).size(),MPI_CHAR,&status);
       if (ierr) // traitement erreur éventuelle
           {cout << "\n *** erreur d'ecriture MPI_File_write: code " << ierr << " , stop Herezh "
                 << "\n proc: "<<proc_en_cours
                 << ", ecriture l'element " << j << " "
                 << "\n Maillage::Ecriture_base_info_MPI_IO(..." << endl;
            Sortie(1);
           };
      };
    };
   
  };
#endif

	    
// ------ informations utiles par exemples pour la visualisation
        // retourne les dimensions minis et maxi suivant les axes du repère
        // absolu du maillage  (en faite le calcul est fondé
        // uniquement sur la position des noeuds du maillage
        // le premier vecteur contient les minimums
        // le deuxième vecteur contient les maximums     
Tableau <Vecteur>  Maillage::Taille_boiteMail()
  { // définition du tableau de retour
    Tableau <Vecteur> tabret(2);
    // cas particulier de maillage vide 
    int nbNoeud = tab_noeud.Taille();
    if (nbNoeud == 0)
      return tabret;
    // sinon le cas normal  
    tabret(1).Change_taille(dimension);
    tabret(2).Change_taille(dimension);
    // on balaie tous les coordonnées des noeuds pour déterminer les tailles
    // maxi et mini 
      // dans une première étape on regarde s'il existe les coordonnées à t=0
      // t et t+dt, ceci à partir du premier noeud qui sert de test
    // on cherche les extrémas  
    for (int i=1; i<=nbNoeud;i++)
      { Coordonnee a0=tab_noeud(i)->Coord0();
        for (int k=1;k<= dimension;k++)
            { if (tabret(1)(k) > a0(k))
                tabret(1)(k) = a0(k);
              if (tabret(2)(k) < a0(k))
                tabret(2)(k) = a0(k);
             }
        // dans le cas de coordonnées à t idem     
        if (tab_noeud(i)->ExisteCoord1())
         {Coordonnee aat=tab_noeud(i)->Coord1();
          for (int k=1;k<= dimension;k++)
            { if (tabret(1)(k) > aat(k))
                tabret(1)(k) = aat(k);
              if (tabret(2)(k) < aat(k))
                tabret(2)(k) = aat(k);
             }
           };  
        // dans le cas de coordonnées à t+dt idem     
        if (tab_noeud(i)->ExisteCoord2())
         {Coordonnee aatdt=tab_noeud(i)->Coord2();
          for (int k=1;k<= dimension;k++)
            { if (tabret(1)(k) > aatdt(k))
                tabret(1)(k) = aatdt(k);
              if (tabret(2)(k) < aatdt(k))
                tabret(2)(k) = aatdt(k);
             }
          };   
       }      
    
    return tabret;
   };
   
//==========================  fonction protegee =============================

// definition des elements frontières mitoyens aux elements de frontiere
// à la fin du programme tous les éléments mitoyens sont stocké dant les éléments front
// la manip est de créer des éléments frontières aux éléments frontières existant
// ensuite deux éléments sont mitoyens s'il ont la même frontière
// à la fin du programme tous les frontières des éléments frontières sont supprimé
void Maillage::MitoyenFront()
{ // le tableau indice_NFr (indice des noeuds frontières) va permettre une recherche plus rapide
  Calcul_indice_NFr();
//  //  on le construit:
//  int tab_noeud_taille= tab_noeud.Taille();
//  Tableau <List_io <Front*> > indice_NFr(tab_noeud_taille);
//  // indice_NFr contiend les front succeptible d'avoir des frontières géométriques communes
//  LaLIST <Front>::iterator iF;
//  LaLIST <Front>::iterator iFfin = listFrontiere.end();
//  for (iF = listFrontiere.begin();iF!=iFfin; iF++)
//    { Front* fro = &(*iF);
//      ElFrontiere * efem1 = fro->Eleme(); // recup de l'element géométrique qui a créé la frontière
//      // récup de son tableau de noeud
//      Tableau<Noeud *>& tabn = efem1->TabNoeud();
//      int tabntaille = tabn.Taille();
//      for (int ij=1;ij<= tabntaille;ij++)
//          // on balaie ses noeuds
//           indice_NFr((tabn(ij)->Num_noeud())).push_back(fro);
//    };
//	 // on supprime les doublons
//	 for (int i=1;i<=tab_noeud_taille;i++)
//    { List_io <Front*>& intertab = indice_NFr(i); // pour allèger l'écriture
//		    intertab.sort(); // on ordonne
//			   intertab.unique(); // on supprime les doublons
//			 };
     
//-- debug
//  cout << "\n maillage " << idmail << "\n";
//  for (int ii=1;ii<= tab_noeud.Taille();ii++) 
//  	{cout << "\n noeud " << ii << "\n";
//  	 list<Front*>::iterator ina,infin;
//     list<Front*>& intertab = indice_NFr(ii); // pour allèger l'écriture
//     infin = intertab.end();
//     for (ina = intertab.begin();ina!=infin;ina++)
//      {Front*  elem2 = (*ina); // recup de l'element
//       elem2->Affiche();
//      };
//  	};  
//  cout << endl;
// // Sortie(1);     
//--fin debug		
     
      
  // on determine les elements front mitoyens a chaque element frontiere, s'ils existent
  LaLIST <Front>::iterator iE,jE,iiE; 
  LaLIST <Front*>  inters; // stockage intermediaire 
  LaLIST <Front>::iterator iEfin = listFrontiere.end();   
  for ( iE = listFrontiere.begin(); iE !=iEfin; iE++)
     // pour chaque element on recherche d'autre element ayant des frontieres communes
     { // création d'élément frontières secondaires des frontières primaires
       Tableau <ElFrontiere*> tabi = (*iE).Eleme()->Frontiere(); // frontieres géométriques de iE
//// --- pour le débug
//cout << "\n on cherche un mitoyen a "; (*iE).Affiche(1);
//{cout << "\n noeuds: ";const Tableau <Noeud *> tabno = (*iE).Eleme()->TabNoeud();
// int nb = tabno.Taille();
// for (int ijk=1;ijk<=nb; ijk++)
//   cout << tabno(ijk)->Num_noeud() << " ";
//}
////-----
       int tabitaille = tabi.Taille();
       for (int i=1;i<= tabitaille;i++)
        { ElFrontiere* elfr = tabi(i);
//// --- pour le débug
//cout << " frontiere : " << i ;
////---
          // si deux éléments frontières sont identiques alors tous leurs noeuds
          // sont identiques. En particulier le premier noeud de *elfr est commum
          // avec tous les éléments succeptibles de contenir un élément frontière
          // identique. On va donc utiliser le vector indice_NFr qui contiend cette liste
          int numnoeud = (elfr->TabNoeud())(1)->Num_noeud();
          list<Front*>::iterator ina,infin;
          list<Front*>& intertab = indice_NFr(numnoeud); // pour allèger l'écriture
          infin = intertab.end();
//// pour le debug
//cout << "\n nb de candidat mitoyen (via indice_NFr) : "<< intertab.size();
////--
          // on balaie les élément succeptibles d'avoir des frontières communes
          for (ina = intertab.begin();ina!=infin;ina++)
           {Front*  elem2 = (*ina); // recup de l'element frontière
//// ---pour le debug
//cout << "\n on test "; elem2->Affiche(1);
//{cout << "\n noeuds: ";const Tableau <Noeud *> tabno = elem2->Eleme()->TabNoeud();
// int nb = tabno.Taille();
// for (int ijk=1;ijk<=nb; ijk++)
//   cout << tabno(ijk)->Num_noeud() << " ";
//}
////--
            // on ne fait la recherche que pour les éléments différent de *iE
            if (*elem2!=*iE)
             {Tableau <ElFrontiere*> tabj = elem2->Eleme()->Frontiere(); // frontieres de ina
              int tabjtaille = tabj.Taille();
              for (int j=1;j<= tabjtaille;j++)
               { // ElFrontiere * tabjjOppose=(tabj(j)->Oppose()); // element transitoire
                 if ((*elfr) == *(tabj(j))) // ||
               //   (*(tabi(i)) == *tabjjOppose) )
                 // iE et ina ont une frontiere commune, sont donc mitoyen
                   { //Front pj = &(*(*ina));
                     inters.push_back(&(*elem2));
//-- debug
//{Tableau <Noeud *>& toto = elfr->TabNoeud(); cout << "\n premiere frontiere NB: "<< i << ":  ";
//for (int ii=1;ii<=toto.Taille();ii++) cout <<toto(ii)->Num_noeud() << " ";}
//{Tableau <Noeud *>& toto = (tabj(j))->TabNoeud(); cout << "\n frontiere mitoyenne NB: "<< j << ":  ";
//for (int ii=1;ii<=toto.Taille();ii++) cout <<toto(ii)->Num_noeud() << " "; }
//cout << "\n ";
//if ((j1==3)&&(j2==6))
// cout << "on y est ";
//--fin debug		
////  pour le débug
//                     cout << "\n on a trouve une frontiere commune ";
//                     elem2->Affiche(1);
//                     cout << " frontiere commune: noeuds: ";
//                     Tableau <Noeud *> tabno = (tabj(j))->TabNoeud();
//                     int nb = tabno.Taille();
//                     for (int ijk=1;ijk<=nb; ijk++)
//                       cout << tabno(ijk)->Num_noeud() << " ";
////  fin pour le débug
                    }
//// pour le debug
//                  else
//                   cout << "\n pas d'égalité ";
////--
              //   delete tabjjOppose; // suppression de l'element  transitoire
               };
             };
           };
        }; 
      // fin de la recherche concernant elfr
	     // on supprime les doublons
		    inters.sort(); // on ordonne
	    	inters.unique(); // on supprime les doublons
      // creation d'un tableau a la place de la liste
      Tableau  <Front*>  tabb((int) inters.size());
      LaLIST <Front*>::iterator ip; int i2;
      LaLIST <Front*>::iterator ipfin=inters.end();
      LaLIST <Front*>::iterator ipdebut=inters.begin();
      for (i2=1,ip = ipdebut;ip != ipfin; ip++,i2++)
       tabb(i2) = &(*(*ip));
      // def des elements mitoyen     
      (*iE).DefMitoyen(tabb);
////  -- débug --- affichage
//cout << "\n au final on a:";
//if (tabb.Taille() > 0)
//  cout << tabb.Taille() <<" frontiere mitoyenne ";
//if (inters.size() == 0)
//  {cout << " nb frontière == 0 ";
//   (*iE).Affiche();
//	cout << endl;
//	};
////  -- fin débug --- affichage
      // on vide la liste
      inters.erase(ipdebut,ipfin);
    };
//  -- débug --- affichage
//  for ( iE = listFrontiere.begin(); iE !=iEfin; iE++)
//      (*iE).Affiche(); 
//  -- fin débug --- affichage
  //effacement de tous les éléments frontières secondaires des éléments frontières
  // primaires
  LaLIST <Front>::iterator iEE; 
  for ( iEE = listFrontiere.begin(); iEE !=iEfin; iEE++)
     (*iEE).Eleme()->EffaceFrontiere();
     
//  -- débug --- affichage
//  for ( iE = listFrontiere.begin(); iE !=iEfin; iE++)
//     { Tableau <Front*>& tabi = (*iE).TabMitoyen(); 
//       int tabitaille = tabi.Taille();
//       for (int i=1;i<= tabitaille;i++)
//        { Front* elfr = tabi(i);
//          cout << "\n"; 
//          elfr->Affiche();
//        }
//     };
////  -- fin débug --- affichage
//     
     
 };      
 
 // dans le cas où les éléments frontières sont des lignes, on les ordonnes 
 // de manière à former une ligne continue
 void Maillage::OrdonancementDesLigne()
  {// on définit une liste intermédiaire
   LaLIST <Front> interlist;
   // on commence par le premier élément de la liste et de proche en proche on 
   // rempli la liste    
  // on passe en revue les éléments frontières
//  LaLIST <Front>::iterator iEE; 
//  for ( iEE = listFrontiere.begin(); iEE !=iEfin; iEE++)
 //    (*iEE).elem->EffaceFrontiere();
   };
	
// definition d'un stockage contenant tous les Front associés à toutes les frontières de tous les éléments
// puis définition des elements mitoyens à ces Front : deux éléments Front sont mitoyens
// s'ils correspondent à des Element différents, et si les frontières associées possèdent les mêmes noeuds 
// toutes ces informations sont stockées dans : mitoyen_de_chaque_element (cf. sa description)
void Maillage::Calcul_tous_les_front_et_leurs_mitoyens()
{   // on crée les éléments frontières dans chaque élément
    int tabelTaille = tab_element.Taille();
    mitoyen_de_chaque_element.Change_taille(tabelTaille); // dimensionnement    
    // on boucle sur les elements 
    for (int i2 = 1; i2 <= tabelTaille; i2++)
      { // création des éléments frontières
		      Element * elem1 = tab_element(i2);
		      elem1->Frontiere(true);
		      // puis on crée tous les éléments Front, qui sont alors stockés dans mitoyen_de_chaque_element(i2)
		      // par contre pour l'instant on n'a pas les mitoyens de calculés
        const Tableau <ElFrontiere*>&  tab1 = elem1->Frontiere(); // et de ses frontières
		      Tableau <Front> & tab_front =  mitoyen_de_chaque_element(i2); // pour simplifier
        int tab1Taille = tab1.Taille();      // nb de frontières
		      tab_front.Change_taille(tab1Taille); // dimensionne mitoyen_de_chaque_element(i2)
		      for (int j=1;j<=tab1Taille;j++)
		        tab_front(j) = Front(*tab1(j),elem1,j);
//cout << "\n les front";
//for (int j=1;j<=tab1Taille;j++)
//		    tab_front(j).Affiche();
		    };

    // on  crée des tableaux permettant d'accélérer l'algorithme final
    // pour chaque noeud on note quel élément contiend ce noeud
    // "indice" contiend les numéros d'élément succeptible d'avoir des frontières communes
	   Calcul_indice();
    // on va  boucler sur les éléments en regardant
    // pour chaque frontière si il y a d'autres frontières mitoyennes  c-a-d si
    // il y a d'autres frontières identiques 
    for (int i1 = 1; i1 <= tabelTaille; i1++)
     {Tableau <Front> & tab_front =  mitoyen_de_chaque_element(i1); // pour simplifier
      int tab1Taille = tab_front.Taille(); // nb de frontières (qui sont déjà stockées)
      for (int j1=1;j1<= tab1Taille;j1++) // on boucle sur les frontière de l'élément principale (nb=i1)
      // on essaie de voir si l'élément j1 est recevable
      {const ElFrontiere * elfr = tab_front(j1).Eleme_const(); // récup de la frontière
       // si deux éléments frontières sont identiques alors tous leurs noeuds
       // sont identiques. En particulier le premier noeud de *elfr est commum
       // avec tous les éléments succeptibles de contenir un élément frontière
       // identique. On va donc utiliser la liste indice qui contiend cette liste
       int numnoeud = (elfr->TabNoeud_const())(1)->Num_noeud();
       list<Element*>::iterator ina,infin;
       list<Element*>& intertab = indice(numnoeud); // pour allèger l'écriture
       infin = intertab.end();
       LaLIST <Front*>  inters; // stockage intermediaire 
       // on balaie les élément succeptibles d'avoir des frontières communes
       for (ina = intertab.begin();ina!=infin;ina++)
        {Element * elem2 = *ina; // recup de l'element
         // on ne fait la recherche que pour les éléments différents de elem1
			      int num_elem2 = elem2->Num_elt(); 
         if (num_elem2 != i1)
           {// récup des éléments front correspondant à elem2 
			         Tableau <Front>& tab_fro = mitoyen_de_chaque_element(num_elem2);
			         int tab_fro_taille = tab_fro.Taille();
				        for (int j2=1;j2<=tab_fro_taille;j2++)
				         { // on compare
				           if ((*tab_fro(j2).Eleme_const()) == (*elfr))
						          {// on récupère le Front de l'élément elem2, pour la frontière j2
						           Front* front_j2 = &tab_fro(j2);
						           inters.push_back(front_j2);
//--debug
//tab_front(j1).Affiche();
//front_j2->Affiche();
//--fin_debug						  
						          };
				         };
           };
		      };
     
	      // on supprime les doublons
		     inters.sort(); // on ordonne
       inters.unique(); // on supprime les doublons
       // creation d'un tableau a la place de la liste
       Tableau  <Front*>  tabb((int) inters.size());
       LaLIST <Front*>::iterator ip; int i2;
       LaLIST <Front*>::iterator ipfin=inters.end();
       LaLIST <Front*>::iterator ipdebut=inters.begin();
       for (i2=1,ip = ipdebut;ip != ipfin; ip++,i2++)
        tabb(i2) = &(*(*ip));
       // def des elements mitoyen, stocké dans mitoyen_de_chaque_element(i1)   
		     tab_front(j1).DefMitoyen(tabb);
     
      }; // fin de la boucle sur les frontières de elem1
     };// fin de la boucle externe des éléments
//--debug
//for (int i=1;i<=mitoyen_de_chaque_element.Taille();i++)
//   {cout <<"\n\n ****  element: "<<i<<" frontiere: ";
//	 Tableau <Front>& tab_f = mitoyen_de_chaque_element(i);
//	 for (int j=1;j<=tab_f.Taille();j++)
//	   tab_f(j).Affiche();
//	}	
//--fin debug	
    // effacement du contenu du tableau indice
    indice.Libere ();
      
};      
	
  
// lectures des infos pour le choix d'un élément
void Maillage::Lecture_info_1element(UtilLecture * entreePrinc,int& num_elt,Enum_geom& id_geom
                         ,Enum_interpol& id_interpol,EnumElemTypeProblem&  id_typeProb
                         ,string& str_precision)
 {  // mise en place des valeurs par défaut
    str_precision = "";
    id_typeProb = MECA_SOLIDE_DEFORMABLE; // type par défaut
    // lecture des champs qui doivent être toujours présents
    *(entreePrinc->entree) >>  num_elt >> id_geom >> id_interpol;
  
    // cas d'info annexe ou du type de problème
    // on regarde  le prochain caractère sans changer le flot
    /// int cr=(entreePrinc->entree)->peek(); ne marche pas !!!
    //--- début du remplacement du peek
    char car = Picococar(*(entreePrinc->entree)); // = flot.peek();
    // on recupère l'entier correspondant au caractère
    int cr = int(car);
    //--- fin du remplacement du peek
    // si c'est un chiffre c'est fini pour le choix de l'élément
    int zero = int('0'); int neuf = int('9');
//    if ((cr >= int('0'))&&(cr <= int('9'))) return;
    if ((cr >= zero)&&(cr <= neuf)) return;
    // maintenant on a deux cas, soit des infos annexes ou soit
    // la définition du type de pb suivi ou non d'infos annexes
    if (cr == int('_'))
       // cas où on a des infos annexes de choix
      { *(entreePrinc->entree) >> str_precision;
        // ensuite il ne doit y avoir que des numéros donc fin
        return;
      } 
    // ou on regarde s'il y a définition du type de problème
    // qui doit commencer par une lettre 
    else if ( ((cr >= int('a'))&&(cr<=int('z'))) ||
              ((cr >= int('A'))&&(cr<=int('Z'))) )
        {  *(entreePrinc->entree) >> id_typeProb; 
           // on regarde s'il y a des infos annexes après le type de problem   
           if (cr == int('_'))
             // cas où on a des infos annexes de choix
             { *(entreePrinc->entree) >> str_precision;
               // ensuite il ne doit y avoir que des numéros donc fin
               return;
              } 
        };
    // sinon c'est le cas qui ne doit pas arriver mais pour éviter des warnings
    return;  
  };             
               
// affectation d'un noeud au maillage c-a-d au tableau de pointeur de noeud, 
// a condition que la place ne soit pas déjà occupée sinon on change le numéro
// de noeud et on augmente le tableau 
void Maillage::Affectation_noeud(Noeud& noeud)      
  {	int nbn = noeud.Num_noeud();
    if (tab_noeud(nbn) == NULL)
      {tab_noeud(nbn)=&noeud;}
    else
      // on augmente la place
      {int tail_tab_noeud = tab_noeud.Taille()+1;
       tab_noeud.Change_taille(tail_tab_noeud);
       noeud.Change_num_noeud(tail_tab_noeud);
       tab_noeud(tail_tab_noeud)=&noeud;
       if (ParaGlob::NiveauImpression() > 0)
          {cout << "\n warning : le numero initial du noeud " << nbn << " est remplace par "
           		<< " le numero d'ordre attribue automatiquement par herezh " << tail_tab_noeud
           		<< "\n seul ce dernier sera utilise par la suite ! " << endl;
           if (ParaGlob::NiveauImpression() > 5)
             cout << "\n  Maillage::Affectation_noeud (Noeud& noeud) " << endl;		
          };
      };
  };
		
// affectation d'un element au maillage c-a-d au tableau de pointeur d'element, 
// a condition que la place ne soit pas déjà occupée sinon on change le numéro
// de l'élément et on augmente le tableau 
void Maillage::Affectation_element(Element& element)   
  { int nbe = element.Num_elt();
    if (tab_element(nbe) == NULL)
      {tab_element(nbe)=&element;}
    else
      // on augmente la place
      {int tail_tab_element = tab_element.Taille()+1;
       tab_element.Change_taille(tail_tab_element);
       element.Change_num_elt(tail_tab_element);
       tab_element(tail_tab_element)=&element;
       if (ParaGlob::NiveauImpression() > 0)
          {cout << "\n warning : le numero initial de l'element " << nbe << " est remplace par "
           		<< " le numero d'ordre attribue automatiquement par herezh " << tail_tab_element
           		<< "\n seul ce dernier sera utilise par la suite ! " << endl;
           if (ParaGlob::NiveauImpression() > 5)
             cout << "\n  Maillage::Affectation_element (Element& element) " << endl;		
          };
      };
    // on met à jour éventuellement les types de problèmes gérés
    EnumElemTypeProblem enu = element.Id_TypeProblem();
    if (!types_de_problemes.Contient(enu))
     {int tail = types_de_problemes.Taille();
      types_de_problemes.Change_taille(tail+1);
      types_de_problemes(tail+1) = enu;
      ddl_representatifs_des_physiques.Change_taille(tail+1);
      switch (enu)
          {case MECA_SOLIDE_DEFORMABLE :
            ddl_representatifs_des_physiques(tail+1)=X1;break;
           case THERMIQUE :
            ddl_representatifs_des_physiques(tail+1)=TEMP;break;
           default :
            cout << "\n***Erreur : pour l'instant le type de probleme: "<<NomElemTypeProblem(enu)
               << "n'est pas pris en compte !\n";
            cout << "\n Maillage::Affectation_element(... \n";
            Sortie(1);
          };

     };
//   
//   
//   
//    if (find(types_de_problemes.begin(),types_de_problemes.end(),enu) == types_de_problemes.end())
//       {
//         types_de_problemes.push_back(enu);
//         types_de_problemes.sort(); types_de_problemes.unique();
//         switch (enu)
//          {case MECA_SOLIDE_DEFORMABLE :
//            ddl_representatifs_des_physiques.push_back(X1);break;
//           case THERMIQUE :
//            ddl_representatifs_des_physiques.push_back(TEMP);break;
//           default :
//            cout << "\n***Erreur : pour l'instant le type de probleme: "<<NomElemTypeProblem(enu)
//               << "n'est pas pris en compte !\n";
//            cout << "\n Maillage::Affectation_element(... \n";
//            Sortie(1);
//          };
//       };
  };

// Modifie le nombre de noeuds du maillage (N.B.: Fait appel
// a la methode Change_taille de la classe Tableau<Noeud>)
// les éléments supplémentaires ont un pointeur mis à Null
void Maillage::Change_nb_noeud (int nouveau_nb)    
{ int vieille_taille = tab_noeud.Taille();	
  tab_noeud.Change_taille(nouveau_nb);	
  for (int i=vieille_taille+1;i<=nouveau_nb;i++)
   tab_noeud(i)=NULL;
};
		
// Modifie le nombre d'elements du maillage (N.B.: Fait appel
// a la methode Change_taille de la classe Tableau<Element>)
// les éléments supplémentaires ont un pointeur mis à Null
void Maillage::Change_nb_element (int nouveau_nb)   
{ int vieille_taille = tab_element.Taille();	
  tab_element.Change_taille(nouveau_nb);	
  for (int i=vieille_taille+1;i<=nouveau_nb;i++)
   tab_element(i)=NULL;
};
              
               
               
                                      
  
  
  
 


