// 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"
//#ifndef SYSTEM_MAC_OS_X_unix
//   #include "Frontier.h"
//#endif
#include "ConstMath.h"
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "Util.h"
#include "MvtSolide.h"
#include "Basiques.h"
#include "TriaSfe1.h"
#include "TriaSfe1_cm5pti.h"
#include "TriaSfe2.h"
#include "TriaSfe3.h"
#include "TriaSfe3_cm3pti.h"
#include "TriaSfe3_cm4pti.h"
#include "TriaSfe3_cm5pti.h"
#include "TriaSfe3_cm6pti.h"
#include "TriaSfe3_cm7pti.h"
#include "TriaSfe3_cm12pti.h"
#include "TriaSfe3_cm13pti.h"
#include "TriaSfe3_3D.h"
#include "TriaSfe3C.h"
#include "TriaQSfe1.h"
#include "TriaQSfe3.h"

#include <limits>

//------------------- on s'occupe de 3 classes de travail ----------------------------------
bool Maillage::NBelemEtFace::operator < (const Maillage::NBelemEtFace& c) const
{if (nbElem < c.nbElem) {return true;}
 else if (nbElem > c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbFace < c.nbFace);};
};
bool Maillage::NBelemEtFace::operator > (const Maillage::NBelemEtFace& c) const
{if (nbElem > c.nbElem) {return true;}
 else if (nbElem < c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbFace > c.nbFace);};
};
bool Maillage::NBelemEtArete::operator < (const Maillage::NBelemEtArete& c) const
{if (nbElem < c.nbElem) {return true;}
 else if (nbElem > c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbArete < c.nbArete);};
};
bool Maillage::NBelemEtArete::operator > (const Maillage::NBelemEtArete& c) const
{if (nbElem > c.nbElem) {return true;}
 else if (nbElem < c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbArete > c.nbArete);};
};

bool Maillage::NBelemEtptInteg::operator < (const Maillage::NBelemEtptInteg& c) const
{if (nbElem < c.nbElem) {return true;}
 else if (nbElem > c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbPtInteg < c.nbPtInteg);};
};
bool Maillage::NBelemEtptInteg::operator > (const Maillage::NBelemEtptInteg& c) const
{if (nbElem > c.nbElem) {return true;}
 else if (nbElem < c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { return (nbPtInteg > c.nbPtInteg);};
};


bool Maillage::NBelemFAEtptInteg::operator < (const Maillage::NBelemFAEtptInteg& c) const
{if (nbElem < c.nbElem) {return true;}
 else if (nbElem > c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  { if (nbFA < c.nbFA ) {return true;}
    else if (nbFA > c.nbFA ) {return false;}
    else // cas où il ne reste que le pti
     {return (nbPtInteg < c.nbPtInteg);};
  };
};
bool Maillage::NBelemFAEtptInteg::operator > (const Maillage::NBelemFAEtptInteg& c) const
{if (nbElem > c.nbElem) {return true;}
 else if (nbElem < c.nbElem) {return false;}
 else // ici cas ou nbElem == c.nbElem
  {if (nbFA > c.nbFA) {return true;}
   else if (nbFA < c.nbFA) {return false;}
   else // cas où il ne reste que le pti
    { return (nbPtInteg > c.nbPtInteg);};
  };
};


//----------------------- fin des classes de travail ------------------------------------------

// modification de l'orientation d'éléments
void Maillage::Modif_orientation_element(int cas_orientation,LesReferences* lesRef)
 {  
  switch (cas_orientation)
   {case -1: case 1: 
 	// =-1: on sort une information s'il y a un pb d'orientation, mais on ne fait rien
 	// =1: on modifie automatiquement l'orientation des éléments lorsque le jacobien
 	//     est purement négatif
     { // on va boucler sur les éléments
        int nbelem = tab_element.Taille();
        for (int ie=1;ie<=nbelem;ie++) 
          tab_element(ie)->Modif_orient_elem(cas_orientation);
        break;	
     }
    case 2: // cas d'une orientation semi-automatique des faces d'un maillage de coques ou de membranes
     {cout << "\n processing of the mesh : " << nomDuMaillage << " nB= " << idmail;
      cout << "\n this re-orientation of elements can be applied only for shell and membrane elements"
           << " the other elements are ignored. " ;
      // initialisation des différents tableaux utilisés par Orientation_elements_mitoyens_recursif
      Init_Orientation_elements_mitoyens_recursif();
      // on commence par faire l'acquisition d'un élément particulier dont la direction servira de référence
	     bool fin_boucle_infinie = false;
      bool calcul_frontiere = false; // pour le calcul une fois des frontières
	     int num_elem=0; // init du numéro de l'élément
	     bool fr = ParaGlob::Francais(); // pour simplifier
	     while (!fin_boucle_infinie)
       {num_elem=0; // re-init du numéro de l'élément, dans le cas où on bouclerait
        bool inverse = false;  // init de l'indicateur permettant de savoir si l'on souhaite essayer 
                             // d'inverser le premier élément, donc tous les éléments de la nouvelle ref
        if (fr)
         {cout << "\n --- choix d'un element dont l'orientation servira de reference ------- ";
          cout << "\n le reperage  peut se faire de differentes manieres :" 
               << "\n par un  numero d'element dans le maillage                                -> (choix : 1)"
               << "\n (rep -1 si l'on veut tenter une orientation inverse pour les elements)                        "
               << "\n par des coordonnees d'un point (meme approximatives),               "
               << "\n l'element choisit sera celui le plus proche	de ce point                  -> (choix : 2)"
               << "\n (rep -2 si l'on veut tenter une orientation inverse pour les elements)                        "
               << "\n  fin                                                                     -> (choix : f ou 0)";
         }
        else
         {cout << "\n --- choise of a reference element for the orientation ------- ";
          cout << "\n could be done by  :" 
               << "\n the number of the element in the mesh                                  -> (choice : 1)"
               << "\n (choice -1 if an inverse orientation is tried for the elements)                      "
               << "\n the coordinates of a point (even approximately)   "
               << "\n the choice will be the nearest element                                 -> (choice : 2)"
               << "\n (choice -2 if an inverse orientation is tried for the elements)                      "
               << "\n  end                                                                   -> (choice : f or 0)";
         };
        string rep="";
        if (fr)
         {cout << "\n reponse ? ";}else {cout << "\n answer ? ";};
        rep= lect_return_defaut(false,"f");
        bool a_traiter=false; // pour gérer l'action d'orienter ou non
        if ((rep == "1") || (rep == "-1"))
         {if (rep =="-1") inverse = true; // on enregistre le souhait d'une orientation inverse
          if (fr) { cout << "\n numero de l'element ? "; }
          else    { cout << "\n number of the element ? ";};
		        rep=lect_chaine(); num_elem = ChangeEntier(rep); 
         } 
        else if ((rep == "2") || (rep =="-2"))
         {int dim = ParaGlob::Dimension();
          if (rep =="-2") inverse = true; // on enregistre le souhait d'une orientation inverse
          Coordonnee xi(dim);
          if (fr) {cout << "\n coordonnee ("<<dim<<" nombre(s)) ? ";}
			       else    {cout << "\n coordinate  ("<<dim<<" scalar(s)) ? ";};
          for(int j=1;j<=dim;j++) cin >> xi(j);
          std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          if (fr) {cout << "\n les coordonnees sont a:  t = 0 ou t ou tdt (repondre 0 ou t ou tdt) ? ";}
			       else    {cout << "\n the coordinates are at :  t = 0 or t or tdt (answer 0 or t or tdt) ? ";}
          rep = lect_chaine();
          bool rep_exploitable = true; Enum_dure enu_temps;
          if (rep == "0")
             enu_temps = TEMPS_0;
          else if (rep == "t")   
             enu_temps = TEMPS_t;
          else if (rep == "tdt") 
             enu_temps = TEMPS_tdt;
          else
            { if (fr) {cout << "\n erreur de syntaxe, on attendait: 0, t ou tdt ";}
				          else {cout << "\n error, the input must be : 0, t or tdt ";}
              rep_exploitable = false;
            };
          if (rep_exploitable)    
            {const Element * elem_ret = Centre_de_Gravite_Element_le_plus_proche(enu_temps,xi);
             if (elem_ret == NULL) // cas où l'on ne trouve pas d'élément
              { if (fr) {cout << "\n pas d'element trouve , pour le temps " 
										                    << rep << "  recommencez ! ";}
					           else    {cout << "\n no element founded,  for the time   " 
										                    << rep << "  do it again ! ";};
                        }
                else  
                 { if (fr) {cout << "\n le numero de l'element contenant le point: "<< elem_ret->Num_elt_const();}
                   else  {cout << "\n the number of the element that contains the point:   "<< elem_ret->Num_elt_const();};
                   num_elem = elem_ret->Num_elt_const();
                 };
            };
         }
        else if ((Minuscules(rep) == "fin") || (Minuscules(rep) == "f") || (Minuscules(rep) == "0"))
         {fin_boucle_infinie = true; a_traiter=false;}
        else
         {if (fr) {cout << "\n choix non valide, recommencez !";}
          else    {cout << "\n the choice is not valide, starts again ! ";};
         };	
		
        // on vérifie que l'élément est correcte
        if (!fin_boucle_infinie) // on ne vérifie pas si c'est la fin demandée
         {if ((num_elem < 1) || (num_elem > tab_element.Taille()))
		        {if (fr) {cout << "\n choix non valide, le numero "<<num_elem<<" est en dehors de "; 
		                   cout << "l'intervalle des elements enregistres ["<<1<<":"<<tab_element.Taille()<<"]"; }
           else { cout << "\n the choice is not valide, the number  "<<num_elem<<" is out of the range of recorded elements "; 
		 		              cout << "["<<1<<":"<<tab_element.Taille()<<"]"; };
                 }
           else if (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) != SURFACE)
		            { if (fr) {cout << "\n choix non valide, l'element "<<num_elem<<" n'est pas un element de surface !!  "; 
		                       cout << " c'est un element : "<< Type_geom_generique(tab_element(num_elem)->Id_geometrie()); }
                else { cout << "\n the choice is not valide, the element "<<num_elem<<" is a surface element "; 
		 		                  cout << " it is an element: "<< Type_geom_generique(tab_element(num_elem)->Id_geometrie()); };
              }
           else if (TestEnum_geom_axisymetrique(tab_element(num_elem)->Id_geometrie()))
              { if (fr) {cout << "\n choix non valide, l'element "<<num_elem<<" est un element axisymetrique !!  ";}
		              else { cout << "\n the choice is not valide, the element "<<num_elem<<" is an axisymetric element "; };
		            }
           else // sinon c'est ok
		            { a_traiter=true;};
          
           // maintenant on va traiter éventuellement
           if (a_traiter)
           {double angle_maxi=0; // angle maxi entre deux éléments, au-dessus duquel, on ne traite pas
            if (fr)
			          {cout << "\n angle maxi (en degre) au dessus duquel on considerera "
			                << "\n qu'il n'y a plus de continuite : "; 
			          }
		          else
			          {cout << "\n angle maximun (in degree) up this angle, up this value,  "
			                << "\n the conitnuity is not taking into account : "; 
			          };
            angle_maxi=lect_double();
            cout << "\n angle= " << angle_maxi ;
            // transformation en radian
            angle_maxi *= ConstMath::Pi/180.;
            cout << " ("<<angle_maxi <<" rd) "; 
            // on s'occupe du nom des ref
            string nom_ref="_"; // nom par défaut
            string reponse = "n";
            if (fr)
              { cout << "\n gene auto du nom des ref (par defaut rep \"o\" ) ou def d'un nom particulier  (rep \"n\") ";}
            else 
              { cout << "\n automatic name for the ref (default rep\"o\" ) or def of a specific name (rep \"n\") ";};
            reponse = lect_return_defaut(false,"o");
            if (reponse == "n")
             {if (fr) {cout << "\n nom de la ref  ? ";}
              else    {cout << "\n name of the reference ? ";};
              nom_ref= lect_chaine();
              if (fr) {cout << "\n nom lu " << nom_ref<<endl;}
              else    {cout << "\n reading name " << nom_ref<<endl;};
              fin_boucle_infinie = false; // pour être sûr de refaire une passe
             };

            // --- on appelle les programmes ad hoc
            // - on définie tous les Front des éléments, et leurs Front mitoyens
            if (!calcul_frontiere)
              {Calcul_tous_les_front_et_leurs_mitoyens();
               calcul_frontiere = true;
               };
            // - premier passage avec le numéro choisit et éventuellement un nom donné
            bool recursif = false;
            list <int> nums_non_oriente = Orientation_elements_mitoyens_recursif(recursif,nom_ref,num_elem,*lesRef
                                                                                 ,angle_maxi,inverse);
            // dans le cas où la liste de retour n'est pas vide cela signifie qu'il y a des groupes d'éléments mitoyens qui n'ont pas
            // la même orientation, on demande si l'on veut les orienter
            if (nums_non_oriente.size() != 0)
             { if (fr) {cout << "\n des groupes d'elements mitoyens ont ete detectes comme ayant des orientations differentes "
                             << " voulez-vous les orienter (arbitrairement) par groupes mitoyens "
                             << " avec des noms de ref genere automatiquement ? (rep o ou n ) ";}
               else    {cout << "\n we have found set of elements, that have common boundaries, but have no similar orientation,"
                             << " do you want to change these orientation (arbirary) for each set "
                             << " with automatic generation of ref name ? (answer y or n )";};
               string answer="";answer=lect_o_n(false);
               if ((fr && (Minuscules(answer) == "o")) || (!fr && (Minuscules(answer) == "y")))
                 { nom_ref="_";bool recursif = true;
                   while (nums_non_oriente.size())
                     { nums_non_oriente = Orientation_elements_mitoyens_recursif
                                             (recursif,nom_ref,*(nums_non_oriente.begin()),*lesRef,angle_maxi,inverse);}
                   fin_boucle_infinie = true; 
                 };
             };
          };
        }; // fin du cas où on n'a pas demandé de finir la boucle infinie

       }; // -- fin de la boucle infinie sur le choix noeud/élément ou arrêt
				 		
		    break;
		   }														      
    case 3: // cas d'une orientation en fonction d'un rayon
     {cout << "\n processing of the mesh : " << nomDuMaillage << " nB= " << idmail;
      cout << "\n this re-orientation of elements can be applied only for shell and membrane elements"
           << " the other elements are ignored. " ;
      // def des tableaux de travail initialisés à rien par défaut
      int dim_espace(ParaGlob::Dimension());
      if (dim_espace != 3) // pour l'instant ne fonctionne qu'en dimension 3
        { cout << "\n erreur *** pour l'instant, cette fonction d'orientation ne fonctionne qu'en dimension 3 "
               << endl;
          Sortie(2);
          return; // normalement ne sert à rien
        };
      Tableau <bool>  indic_G(3,false);
      Coordonnee3  A;
      Tableau <bool> item_renseigne(3,false); // utilisé pour savoir si tous les items ont été renseignés
      string zone_a_traiter("_");
      bool inverse=false;
      // on définit les paramètres de l'orientation: on va utiliser un menu
      string rep("_");bool traitement_pas_pret = true;
      while (traitement_pas_pret)
       { while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
          {
           try
            { 
             cout
                << "\n (0 ou f)  (fin normal avant traitement)   "
                << "\n (1)  definition du point de reference     "
                << "\n (2)  inversion eventuelle de sens "
                << "\n (3)  definition de la zone a traiter "
                << "\n (4)  arret du processus (sans traitement)  "
                << "\n (5)  affichage de la liste des ref existantes (pour info) "
                << "\n (6)  affichage min max sur x y z pour info "
                << "\n  ";
             rep = lect_return_defaut(false,"f");
             // sortie directe si tout est ok, sinon
             if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))
              {if (item_renseigne(1)  && item_renseigne(3))
                  break; // ok on peut s'arrêter
               else { cout << "\n la mise en donnee n'est pas complete ! "<<endl;
                      if (!item_renseigne(1)) cout << " vous devez renseigner le (1) "<<endl;
                      if (!item_renseigne(3)) cout << " vous devez renseigner le (3) "<<endl;
                    };
               rep = "_"; // on réinitialise pour éviter de sortir de la boucle
              }
             else
              {
               int num = ChangeEntier(rep);
               bool choix_valide=false;
               if ((num >= 0)&&(num<7))
                    { choix_valide=true; }
               else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
                           << "\n redonnez une bonne valeur"
                           << "\n ou taper f ou 0 pour arreter le programme et valider les choix ";
                      choix_valide=false;
                    }
               switch (num)
                { case 0:  // sortie
                    { break;} // normalement cela a déjà été filtré avant
                  case 1:  // définition du point de référence
                    { cout << "\n\n definition du point de reference \n";
                      { string nom;
                        cout << "\n coord x du point ou XG pour utiliser le x du G de la facette ? ";
                        nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
                        if (nom == "XG") {indic_G(1)=true;A(1)=0.;}
                        else { indic_G(1)=false;A(1)=ChangeReel(nom);};
                      }
                      { string nom;
                        cout << "\n coord y du point ou YG pour utiliser le y du G de la facette ? ";
                        nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
                        if (nom == "YG") {indic_G(2)=true;A(2)=0.;}
                        else { indic_G(2)=false;A(2)=ChangeReel(nom);};
                      }
                      { string nom;
                        cout << "\n coord z du point ou ZG pour utiliser le z du G de la facette ? ";
                        nom= lect_chaine();cout << " valeur lue "<< nom<<endl;
                        if (nom == "ZG") {indic_G(3)=true;A(3)=0.;}
                        else { indic_G(3)=false;A(3)=ChangeReel(nom);};
                      }
                      item_renseigne(1)=true; // on valide l'item
                      break;
                    }
                  case 2:  // inversion de sens
                    { cout << "\n inversion eventuelle du sens rep o ou n ";
                      string nom;
                      nom= lect_chaine();cout << " valeur lue "<< nom<<endl; nom = Minuscules(nom);
                      if (nom == "o" ) inverse = true;
                      else if (nom == "n") inverse = false;
                      // sinon on laise en l'état
                      item_renseigne(2)=true; // on valide l'item
                      break;
                    }
                  case 3:  // definition de la zone a traiter
                    { cout << "\n definition de la zone a traiter \n";
                      cout << "\n donner la reference des elements a traiter ? ";
                      string nom;
                      nom= lect_chaine(); cout << " valeur lue "<< nom<<endl;
                      // on regarde si la référence existe
                      if (!lesRef->Existe(nom,idmail))
                        {cout << "\n *** cette reference n'existe pas !! "<<endl;
                         item_renseigne(3)=false;
                        }
                      else {zone_a_traiter=nom; item_renseigne(3)=true;};
                      break;
                    }
                  case 4:  // arret du processus sans traitement
                    { cout << "\n fin du processus, pas de traitement de re-orientation !! ";
                      return;
                      break;
                    }
                  case 5:  // affichage de la liste des ref existantes
                    { cout << "\n affichage de la liste de nom des ref existantes \n";
                      lesRef->Affiche(1);
                      break;
                    }
                  case 6:  // affichage min max x y z pour info
                    { cout << "\n affichage min max x y z pour info \n";
                      // on récupère la boite d'encombrement
                      Tableau <Vecteur> tab_vec = Taille_boiteMail();
                      cout << "\n min_x= "<<tab_vec(1)(1) << " max_x= "<< tab_vec(2)(1);
                      cout << "\n min_y= "<<tab_vec(1)(2) << " max_y= "<< tab_vec(2)(2);
                      cout << "\n min_z= "<<tab_vec(1)(3) << " max_z= "<< tab_vec(2)(3);
                      break;
                    }
                  default:
                    cout << "\n mauvais choix !! recommencez ! ";
                };
              };
            }    
           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"<<endl;
            };
          }; //-- fin du while
       
         // on regarde si tous les items ont été renseigné
         if (item_renseigne(1)  && item_renseigne(3))
              {traitement_pas_pret = false;rep = "";}
         else {traitement_pas_pret = true;rep = "";};
       };
      // arrivée ici on dispose de toutes les données ad hoc
      // appel de la routine
      Orientation_via_rayon(indic_G,A,zone_a_traiter,*lesRef,inverse);
		    break;
     }
 	  default:
 	    cout << "\n error: case of an orientation not envisaged : cas_orientation= " << cas_orientation 
 	         << "\n Maillage::Modif_orientation_element(... ";
 	    Sortie(1);     	
 	};
		
 };

// Lecture et Collapse des éléments superposés, c-a-d identiques, dans le cas où il en existe
void Maillage::LectureEtCollapse_element_superpose(UtilLecture * entreePrinc,LesReferences* lesRef)
 { if (strstr(entreePrinc->tablcar,"fusion_elements_superposes_")!=NULL) 
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse elements which are "
																	 << " superposed "<< endl ;   
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de collapse
        Collapse_element_superpose(lesRef);
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse elements which are "
																	 << " superposed "<< endl ;   
      };
 };

// Collapse des éléments supperposés, c-a-d identiques, dans le cas où il en existe
void Maillage::Collapse_element_superpose(LesReferences* lesRef)
{  // création pour chaque noeud de la liste des éléments qui contiennent le noeud
   Calcul_indice();
   // on crée un tableau d'indicateur des éléments à supprimer
   int nbelem = tab_element.Taille();
   Tableau <int> elem_supprime(nbelem,0);
   // on balaie les éléments, et pour chaque élément, on recherche les éléments supperposés éventuels
   for (int ine = 1;ine <= nbelem;ine++)
    // on ne continue que si c'est un élément qui n'a pas déjà été marqué " à supprimé "
    if (elem_supprime(ine) == 0)
     {Element * elem = tab_element(ine);
      // on récupère uniquement le premier noeud
      Noeud * noe = tab_element(ine)->Tab_noeud()(1);
      // indice(i) contient la liste des éléments qui contiennent le noeud i
      List_io < Element*> & li_elem = indice(noe->Num_noeud()); // pour simplifier
      List_io < Element*>::iterator il,ilfin = li_elem.end();
      for (il=li_elem.begin();il != ilfin;il++)
       // on intervient que si le numéro de l'élément est supérieur à celui de l'élément de base
       // et que ce n'est pas un élément déjà marqué à supprimé
       if (((*il)->Num_elt() > ine )&&(elem_supprime((*il)->Num_elt()) == 0))
         // on test si les deux éléments ont la même signature, même géométrie et appartiennent au même maillage
         if (elem->Meme_signature_et_geometrie(*(*il))) // si égalité, on indique que l'élément il est à supprimer,
           elem_supprime((*il)->Num_elt())=ine;         // et on sauvegarde l'élément de substitution
     };

   // on sauvegarde les anciens numéros de noeuds, servira pour contruire nv_num
   // normalement c'est directement iN mais on ne sait jamais
   Tableau <int> ancien_num_ele(nbelem);
   for (int ie=1;ie<=nbelem;ie++)
     ancien_num_ele(ie) = tab_element(ie)->Num_elt();
   // -- maintenant on va vraiment supprimer les éléments en double et mettre à jour les références
   // 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
   // 2- on supprime les éléments qui ne servent plus
   int nb_elem_restant = nbelem; // init du nombre d'élément restant après fusion
   Tableau <bool> non_referencer(nbelem,false); // un tableau intermédiaire qui servira pour les ref
   for (int ine=1;ine<=nbelem;ine++)
     {if (elem_supprime(ine)) // s'il est différent de 0, on doit supprimer
       { int num_nelem = elem_supprime(ine);
         delete tab_element(ine); // on supprime l'élément
  // -- debug
  // cout << "\n Maillage::Collapse_element_superpose debug !! à remettre en service la ligne précédente "<<endl;
  // -- fin debug
         tab_element(ine)=NULL; // on indique qu'il n'y a plus d'élément
 
//         non_referencer(ine)=true; // servira pour les ref
// *** modif 15 avril 2016: comme il s'agit d'éléments supperposés, cela veut dire qu'il reste un élément de substitution
// qui lui est valide donc on met false, ce qui veut dire que l'on ne veut pas supprimer l'élément dans la ref
// car sinon la ref devient différente et incomplète
         non_referencer(ine)=false; // servira pour les ref

         nb_elem_restant--; // on diminue le nombre d'éléments restants
         if (ParaGlob::NiveauImpression() > 2)
               cout << "\n collapse element " << ine << " --> " << num_nelem ;
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_element(ine-1); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_element(ine+1); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
// Sortie(1);
// 
//};
////--fin debug
       };
     };
  
   // maintenant on refait un nouveau tableau d'éléments avec les éléments inutiles supprimés
   Tableau <Element* > tab_final(nb_elem_restant);
   int nbelem_restant=0; // le nombre d'éléments restant
   cout << "\n ";
   for (int ijn = 1; ijn <= nbelem; ijn++)
    { if(tab_element(ijn)!=NULL)
       {nbelem_restant++;
        tab_final(nbelem_restant) = tab_element(ijn);
       };
    };
   // // on redimentionne le tableau final (ses premiers restent !!)
   // tab_final.Change_taille(nbn_restant);
   if (ParaGlob::NiveauImpression() >= 0)
        cout << "\n collapse of " << (nbelem-nbelem_restant) <<" element(s) "  << endl;
   // on met à jour les références
   lesRef->SupprimeReference("E_tout",idmail); // on supprime la référence E_tout
   Tableau <int> nv_num(nbelem,0); // nouveau num/ au ancien
   for (int ia=1;ia <= nbelem_restant; ia++)
        nv_num(tab_final(ia)->Num_elt()) = ia;


 
   // *** modif 15 avril 2016: il faut tous les numéros de remplacement et pas seulement ceux
   // qui restent car  dans la mise à jour on commence par changer les numéros et "ensuite"
   // on supprime les doublons --> donc on complète
   // nv_num(num_ancien) = le nouveau numéro d'élément donc celui qui est en coincidence et qui reste
   // a_fusionner(ancien_num_ele(ia)) -> le nouveau numéro dans l'ancien tableau
   // qui aura comme nouveau numéro:nv_num(a_fusionner(ancien_num_ele(ia)))
   for (int ia=1;ia <= nbelem; ia++)
      if (nv_num(ia) == 0) // cela veut dire que c'est un numéro qui disparait
         nv_num(ia) = nv_num(elem_supprime(ancien_num_ele(ia)));

  // -- debug
  // cout << "\n Maillage::Collapse_element_superpose debug  "<<endl;
  //lesRef->Affiche(); cout << endl;
  // -- fin debug
   lesRef->Mise_a_jour_ref_element(nv_num,idmail,non_referencer);
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_final(152); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_final(153); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
// 
//};
//--fin debug
   // on enregistre le nouveau tableau d'éléments
   tab_element = tab_final;
   // on met à jour les numéros d'éléments
   for (int ia=1;ia <= nbelem_restant; ia++)
        tab_element(ia)->Change_num_elt(ia);
   // on recrée la référence E_tout
   string Etout("E_tout");
   { // on construit le tableau des numéros de noeuds
     Tableau <int> tabE(nbelem_restant); for (int i=1;i<=nbelem_restant;i++) tabE(i)=i;
     ReferenceNE*  rtout = new ReferenceNE(tabE,idmail,2,Etout);// construction de la référence
     lesRef->Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
    };
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// Element * elem1 = tab_element(152); // recup de l'element
// cout << " element " << elem1->Num_elt() << " ";
// elem1->Affiche();
//// Element * elem2 = tab_element(ine); // recup de l'element
//// cout << " element " << elem2->Num_elt() << " ";
//// elem2->Affiche();
// Element * elem3 = tab_element(153); // recup de l'element
// cout << " element " << elem3->Num_elt() << " ";
// elem3->Affiche();
// cout << "\n"<<endl ;
//};
////--fin debug
////-- debug
//{cout << "\n debug ** Maillage::Collapse_element_superpose() ";
// int tail=tab_element.Taille();
// cout << "\n NBE= " << tail  ;
// for (int ina = 1;ina <= tail;ina++)
//  {Element * elem2 = tab_element(ina); // recup de l'element
//	  cout << " element " << elem2->Num_elt() << " ";
//   elem2->Affiche();
//	 };
// cout << "\n"<<endl ;
// Sortie(1);
//};
//////--fin debug
 
   
};

// Lecture et collapse de noeuds très proche: appartenant à des éléments différents
void Maillage::LectureEtCollapse_noeuds_proches(UtilLecture * entreePrinc, LesReferences* lesRef)
 { if (strstr(entreePrinc->tablcar,"fusion_noeuds_proches_")!=NULL) 
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse nodes which are "
																	 << " nearly at the same position "<< endl ;
        // on lit la distance mini
        double rayon = 0;string nom;
        *(entreePrinc->entree) >> nom >> rayon;
        if (nom != "fusion_noeuds_proches_")
         { cout << "\n error : we expected the keyword: fusion_noeuds_proches_ but we read \""<<nom<<"\" ";
           if (ParaGlob::NiveauImpression() >= 6)
             cout << "\n Maillage::LectureEtCollapse_noeuds_proches(...";
           Sortie(1);
         };
        if (ParaGlob::NiveauImpression() >= 5)
          cout << "\n minimum distance = " << rayon;
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de collapse
        Collapse_noeuds_proches(rayon,lesRef);
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse nodes which are "
																	 << " nearly at the same position "<< endl ;   
      };
 };

// collapse de noeuds très proche: appartenant à des éléments différents
// rayon : donne la distance maxi entre les noeuds qui doivent être collapsé
void Maillage::Collapse_noeuds_proches(double rayon ,LesReferences* lesRef)
{// au niveau de l'algo on va commencer par faire un classement des noeuds pour accélérer les recherches futures
 // pour cela on découpe le volume de travail en boites contenant un petit nombre de noeuds
 // et on s'aide de grandeurs de référence
 int NBN = tab_noeud.Taille();
 int dim = ParaGlob::Dimension();
 if (ParaGlob::NiveauImpression() >= 0)
   cout << "\n " << NBN << " node(s) " << tab_element.Taille() << " element(s) "  ;
 
 // racine3NBN donne une idée du nombre de noeuds dans chaque direction de la dimension
 int racine3NBN = (int) (exp(1./dim * log(NBN) )); // floor: extraction de la partie entière
 // on veut environ 3*3*3=27 noeuds par boites en 3D par exemple
 // en fait les tests on montré que c'était mieux d'avoir plus de boite, donc on ne divise pas par 3
 int nb_decoupe = racine3NBN ; // 3;// on pourrait donc avoir nb_decoupe**dim cubes
   // mais il faut également que la taille du cube de base soit plus grande que le rayon
 // maintenant on détermine les dimensions max et min qui contiennent tous les noeuds
 Tableau <Vecteur>  ta_d =  Taille_boiteMail();
 Tableau <int> nbboite(dim); int nb_totale=1;
 // on va calculer les paramètres de stockage et de calculs
 Coordonnee pas_en_espace(dim); // les pas d'espace dans les différentes directions
 for (int i=1;i<=dim;i++)
    {double distance = ta_d(2)(i)-ta_d(1)(i);
     // en générale le rayon est très petit, donc on va considérer des arêtes de boites > 5 * rayons
     int nb_mini = (int)(distance / (rayon*5.));
     // si nb_mini est négatif cela veut dire que l'on a dépasser la précision et que
     // le nombre est trop grand on le met également à 1
    
     if ((nb_mini == 0)
         || (nb_mini < 0)
        )
         nb_mini=1; // au minimum on doit avoir 1
     nbboite(i) = MiN(nb_mini,nb_decoupe); // on stocke le nombre de boite dans la direction i
     pas_en_espace(i) = distance / nbboite(i) + ConstMath::petit; // on stocke le pas d'espace dans la direction i
     // on a ajouté un chouil pour être sur que le point le plus grand soit calculé dans les boites existantes
     nb_totale *= nbboite(i); // on stocke le nombre maxi de boite
    };
 if (ParaGlob::NiveauImpression() >= 5)
        {cout <<"\n nbboite(i)= ";for (int i=1;i<=dim;i++) cout << nbboite(i);
         cout <<endl;}
 // on définit des boites = listes de noeuds, qui vont nous permettre ensuite de trier rapidemment
 // tout d'abord chaque noeud est associé à une boite = un élément de tab_Boite
 Tableau <list <int> > tab_Boite(nb_totale); // dimensionnement des listes de noeuds principale
 // pour chaque noeud de la liste , il faudra considérer tous les noeuds des boites qui l'entourent
 // on comparera ce noeud avec ceux des 3 ou 9 ou 27 boites (suivant la dimension) qui entourent la boite du noeud
 // étant donné que la taille de la boite est au moins plus grande que le rayon de recherche, normalement c'est ok
 Tableau <list <int> > tab_BS(NBN); // les listes des numéros de boites qui seront associées à la recherche
 // défini le décalage que l'on doit avoir pour le calcul des indices
 Coordonnee M_ref(dim);
 switch (dim)
    {case 3: M_ref(3) = ta_d(1)(3);
     case 2: M_ref(2) = ta_d(1)(2);
     case 1: M_ref(1) = ta_d(1)(1);
    };
  
 // maintenant on va remplir les boites = listes de noeuds
 for (int iN=1;iN<=NBN;iN++)
  { Noeud& no = *(tab_noeud(iN)); // pour simplifier
    const Coordonnee& M0 =no.Coord0();
    int indica=0; // indice de la boite
    // soit i j k les indices suivants x y et z, et N1 N2 N3 les maxis de stockage suivants x y z
    // le noeud est stocké dans (k-1)*N1*N2 + (j-1)*N1 + i
    // - calcul de l'indice de stockage
    int nb1,nb2,nb3; // les indices suivant x y z
    switch (dim)
     {case 3:
        {nb3= ((int) ((M0(3)-M_ref(3))/pas_en_espace(3))); // le numéro -1, suivant 3
         indica += nb3 * nbboite(3) * nbboite(2);
        }
      case 2:
        {nb2= ((int) ((M0(2)-M_ref(2))/pas_en_espace(2))); // le numéro -1, suivant 2
         indica += nb2 * nbboite(2);
        }
      case 1:
        {nb1= ((int) ((M0(1)-M_ref(1))/pas_en_espace(1))); // le numéro -1, suivant 1
         indica += nb1 + 1 ;
        }
     };
//debug
//    if ((nb1 > nbboite(1)) || (nb2 > nbboite(2)) || (nb3 > nbboite(3)))
//      cout << "\n nb1= "<<nb1 <<" nb2= "<<nb2 <<" nb3= "<<nb3 << endl;
//fin debug
    // stockage du noeud dans la bonne boite
    tab_Boite(indica).push_back(no.Num_noeud());
    // def des boites qui seront associées à la recherche
    list <int>& li_BS = tab_BS(no.Num_noeud()); // pour simplifier
    li_BS.push_back(indica); // la boite centrale
//if (indica > nb_totale)
//  cout <<"\n indica="<<indica << endl;
    switch (dim)
      {case 3:
          {// d'abord les 8 boites du centre en plus du centre centre centre déjà entrée
           int nb3_12 = nb3 * nbboite(3) * nbboite(2);
           if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
//   cout <<"\n nb3_12+ nb2 * nbboite(2)+nb1+2="<<nb3_12+ nb2 * nbboite(2)+nb1+2<< endl;
           };
              if(nb1 > 0)         {li_BS.push_back(nb3_12+ nb2 * nbboite(2)+nb1);
//if (nb3_12+ nb2 * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_12+ nb2 * nbboite(2)+nb1="<<nb3_12+ nb2 * nbboite(2)+nb1<< endl;
              };
           if(nb2+1 < nbboite(2))
           {li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_12+(nb2+1) * nbboite(2)+nb1+1<< endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_12+(nb2+1) * nbboite(2)+nb1+2<< endl;
               };
               if(nb1 > 0)         {li_BS.push_back(nb3_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_12+(nb2+1) * nbboite(2)+nb1="<<nb3_12+(nb2+1) * nbboite(2)+nb1<< endl;
               };
              };
           if(nb2 > 0)
              {li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_12+(nb2-1) * nbboite(2)+nb1+1<< endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_12+(nb2-1) * nbboite(2)+nb1+2<< endl;
                  };
                  if(nb1 > 0)         {li_BS.push_back(nb3_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_12+(nb2-1) * nbboite(2)+nb1="<<nb3_12+(nb2-1) * nbboite(2)+nb1<< endl;
                  };
              };
           // les 9 au dessus dans la direction z
           if(nb3+1 < nbboite(3))
             {int nb3_p1_12=(nb3+1) * nbboite(3) * nbboite(2);
              li_BS.push_back(nb3_p1_12+nb2 * nbboite(2)+nb1+1);
//if (nb3_p1_12+nb2 * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_p1_12+nb2 * nbboite(2)+nb1+1="<<nb3_p1_12+nb2 * nbboite(2)+nb1+1
//         <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
              if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_p1_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_p1_12+ nb2 * nbboite(2)+nb1+2="<<nb3_p1_12+ nb2 * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                 };
              if(nb1 > 0)         {li_BS.push_back(nb3_p1_12+ nb2 * nbboite(2)+nb1);
//if (nb3_p1_12+ nb2 * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_p1_12+ nb2 * nbboite(2)+nb1="<<nb3_p1_12+ nb2 * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                 };
              if(nb2+1 < nbboite(2))
              {li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1+1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
              if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                  };
              if(nb1 > 0)         {li_BS.push_back(nb3_p1_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_p1_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2+1) * nbboite(2)+nb1="<<nb3_p1_12+(nb2+1) * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                  };
              };
              if(nb2 > 0)
              {li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1+1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                  };
               if(nb1 > 0)         {li_BS.push_back(nb3_p1_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_p1_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_p1_12+(nb2-1) * nbboite(2)+nb1="<<nb3_p1_12+(nb2-1) * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
                  };
              };
             };
              
              
           // les 9 au dessus dans la direction z
           if(nb3 > 0)
              {int nb3_m1_12=(nb3-1) * nbboite(3) * nbboite(2);
               li_BS.push_back(nb3_m1_12+nb2 * nbboite(2)+nb1+1);
//if (nb3_m1_12+nb2 * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_m1_12+nb2 * nbboite(2)+nb1+1="<<nb3_m1_12+nb2 * nbboite(2)+nb1+1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+ nb2 * nbboite(2)+nb1+2);
//if (nb3_m1_12+ nb2 * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_m1_12+ nb2 * nbboite(2)+nb1+2="<<nb3_m1_12+ nb2 * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               if(nb1 > 0)         {li_BS.push_back(nb3_m1_12+ nb2 * nbboite(2)+nb1);
//if (nb3_m1_12+ nb2 * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_m1_12+ nb2 * nbboite(2)+nb1="<<nb3_m1_12+ nb2 * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               if(nb2+1 < nbboite(2))
               {li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1+1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               if(nb1 > 0)         {li_BS.push_back(nb3_m1_12+(nb2+1) * nbboite(2)+nb1);
//if (nb3_m1_12+(nb2+1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2+1) * nbboite(2)+nb1="<<nb3_m1_12+(nb2+1) * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               };
               if(nb2 > 0)
               {li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1+1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               if(nb1+1 < nbboite(1)){li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1+2
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               if(nb1 > 0)         {li_BS.push_back(nb3_m1_12+(nb2-1) * nbboite(2)+nb1);
//if (nb3_m1_12+(nb2-1) * nbboite(2)+nb1 > nb_totale)
//    cout <<"\n nb3_m1_12+(nb2-1) * nbboite(2)+nb1="<<nb3_m1_12+(nb2-1) * nbboite(2)+nb1
//    <<" nb3="<<nb3<<" nb2="<<nb2<<" nb1="<<nb1 << endl;
               };
               };
              };
           break;
          }
          case 2: // cas 2D, on a 9 boites à considérer, sauf si l'on est dans les extrèmes
          {if(nb1+1 < nbboite(1)){li_BS.push_back((nb2) * nbboite(2)+nb1+2);};
           if(nb1 > 0)         {li_BS.push_back((nb2) * nbboite(2)+nb1);};
           if(nb2+1 < nbboite(2))
            {li_BS.push_back((nb2+1) * nbboite(2)+nb1+1);
             if(nb1+1 < nbboite(1)){li_BS.push_back((nb2+1) * nbboite(2)+nb1+2);};
             if(nb1 > 0)         {li_BS.push_back((nb2+1) * nbboite(2)+nb1);};
            };
           if(nb2 > 0)
            {li_BS.push_back((nb2-1) * nbboite(2)+nb1+1);
             if(nb1+1 < nbboite(1)){li_BS.push_back((nb2-1) * nbboite(2)+nb1+2);};
             if(nb1 > 0)         {li_BS.push_back((nb2-1) * nbboite(2)+nb1);};
            };
           break; 
          }
          case 1: // cas 1D, on a 3 boites à considérer, sauf si l'on est dans les extrèmes
          {if(nb1+1 < nbboite(1)) {li_BS.push_back(indica+1);};
           if(nb1 > 0) {li_BS.push_back(indica-1);};
          }
          break;
      };
    
  };
  
 // on effectue maintenant la fusion des noeuds en s'aidant des boites pour diminuer la recherche
 Tableau <int> a_fusionner(NBN,0); // tableau d'indicateurs de noeuds a fusionner
 for (int ib = 1; ib<=nb_totale;ib++)
  {// on parcours les boites: ib: le numéro de la boite courante
   list <int>::iterator il,ilfin=tab_Boite(ib).end();
   for (il=tab_Boite(ib).begin();il != ilfin; il++)
    {// on parcours tous les noeuds le la boite: (*il) est le numéro du noeud courant
     // on ne continue que si le noeud n'a pas été déclaré fusionable par ailleurs
     if (!a_fusionner(*il))
      {list <int>::iterator im,imfin=tab_BS((*il)).end(); // tab_BS = une liste de numéro de boite
       for (im = tab_BS((*il)).begin();im != imfin; im++) // *im c'est un numéro de boite     
        {
         if ((*im)>nb_totale) cout << " *il="<<(*il)<<" *im="<<(*im)<<endl;//" tab_BS.size()="<<tab_BS(*il).size();
         list <int>::iterator ip,ipfin=tab_Boite(*im).end(); // *ip sera un numéro de noeud
         for (ip = tab_Boite(*im).begin();ip != ipfin; ip++)
         // on parcours tous les noeuds à considérer
         if ((!(a_fusionner(*ip)))&&((*il)!=(*ip))) // on examine que si le noeud ne sera fusionné
          if ((tab_noeud(*il)->Coord0()-tab_noeud(*ip)->Coord0()).Norme() < rayon)
            { a_fusionner(*ip)=*il;  // on enregistre
              if (ParaGlob::NiveauImpression()>3)
                 cout << "\n detail du processus de collapse de noeud proche Maillage::Collapse_noeuds_proches( "
                      << "\n  rayon= " << rayon << " noe_afusionner ip: " << (*ip)
                      << " noeud identique il: " << *il
                      << "\n coor ip: " << tab_noeud(*ip)->Coord0()
                      << "\n coor il: " << tab_noeud(*il)->Coord0() << endl;
            };
        };
      };
    };
  };
  
 // création pour chaque noeud de la liste des éléments qui contiennent le noeud
 Calcul_indice();
 // on passe en revue les noeuds et on regarde si la fusion est possible
 // elle est impossible si deux noeuds a fusionner appartiennent à un même élément
 // dans ce cas on désactive l'indicateur de fusion
 for (int ine=1;ine<=NBN;ine++)
  {if (a_fusionner(ine)) // s'il est différent de 0, indique que ine peut-être fusionné
    {// on regarde si les deux noeuds : ine et a_fusionner(ine) n'appartiennent pas à un même élément
     List_io < Element*>& indic = indice(ine); // pour simplifier
     List_io < Element*>::iterator ie,iefin=indic.end();
     bool fusion_non_possible = false; // init par défaut
     int num_maitre = a_fusionner(ine);
     for (ie=indic.begin();ie!=iefin;ie++)
       { Element& ele = *(*ie); // récup d'un élément qui contient a priori le numéro ine
         Tableau<Noeud *>& tn = ele.Tab_noeud(); // récup des noeuds de l'élément
         // maintenant on regarde si l'élément contient également le a_fusionner(ine)
         int taille_tn=tn.Taille();
         for (int j=1;j<=taille_tn;j++)
           if (tn(j)->Num_noeud() == num_maitre)
             {fusion_non_possible=true;
              break;// on sort de la première boucle sur les noeuds de l'élément
             };
         if (fusion_non_possible)
           break; // on sort de la seconde boucle sur les éléments contenant le noeud
        };
      //
      if (fusion_non_possible) // cas où la fusion n'est pas possible
       {a_fusionner(ine)=0;};
    };
  };
 // on sauvegarde les anciens numéros de noeuds, servira pour contruire nv_num
 // normalement c'est directement iN mais on ne sait jamais
 Tableau <int> ancien_num_Noe(NBN);
 for (int iN=1;iN<=NBN;iN++)
   ancien_num_Noe(iN) = tab_noeud(iN)->Num_noeud();

 // -- maintenant on va vraiment fusionner et mettre à jour les références
 // 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
 // 2- on supprime les noeuds qui ne servent plus
 
 
 int nb_noeud_restant = NBN; // init du nombre de noeud restant après fusion
 Tableau <bool> non_referencer(NBN,false); // un tableau intermédiaire qui servira pour les ref
 for (int ine=1;ine<=NBN;ine++)
   {if (a_fusionner(ine)) // s'il est différent de 0, on doit fusionner
     { int num_ne = a_fusionner(ine);
//cout << "\n ine= "<<ine<<" num_ne="<<num_ne<<endl;
       // on va balayer uniquement les éléments qui contiennent le noeud a fusionner
       List_io < Element*>& indic = indice(ine); // pour simplifier
       List_io < Element*>::iterator ie,iefin=indic.end();
       for (ie=indic.begin();ie!=iefin;ie++)
         { Element& ele = *(*ie); // récup de l'élément qui contient ine
           Tableau<Noeud *>& tn = ele.Tab_noeud(); // récup des noeuds de l'élément
           int taille_tn=tn.Taille();
           for (int j=1;j<=taille_tn;j++)
            if (tn(j)->Num_noeud() == ine)
              {ele.Change_noeud(j,tab_noeud(num_ne)); // on change la connexion
               if (tab_noeud(num_ne) == NULL)
                cout << "\n*** le noeud num_ne=" <<num_ne << " est nulle !" << endl;
               };
         };
       // on reporte le tableau de ddl de l'élément à supprimer sur celui qui reste
       tab_noeud(num_ne)->PlusTabDdl(*tab_noeud(ine));
       // maintenant il n'y a plus d'élément qui utilise le noeud ine donc on le supprime
       delete tab_noeud(ine); // on supprime le noeud
       tab_noeud(ine)=NULL; // on indique qu'il n'y a plus de noeud

//       non_referencer(ine)=true; // servira pour les ref
// *** modif 15 avril 2016: comme il s'agit de noeuds supperposés, cela veut dire qu'il reste un noeud de substitution
// qui lui est valide donc on met false, ce qui veut dire que l'on ne veut pas supprimer le noeud dans la ref
// car sinon la ref devient différente et incomplète
       non_referencer(ine)=false; // servira pour les ref

       nb_noeud_restant--; // on diminue le nombre de noeuds restants
       if (ParaGlob::NiveauImpression() > 2)
             cout << "\n collapse node " << ine << " --> "<<num_ne ;
     };
   };
  
 // maintenant on refait un nouveau tableau de noeud avec les noeuds inutiles supprimés
 Tableau <Noeud* > tab_final(nb_noeud_restant);
 int nbn_restant=0; // le nombre de noeud restant
 cout << "\n ";
 for (int ijn = 1; ijn <= NBN; ijn++)
  { if(tab_noeud(ijn)!=NULL)
     {nbn_restant++;
      tab_final(nbn_restant) = tab_noeud(ijn);
     };
  };
// // on redimentionne le tableau final (ses premiers restent !!)
// tab_final.Change_taille(nbn_restant);
 if (ParaGlob::NiveauImpression() >= 0)
        cout << "\n collapse of " << (NBN-nbn_restant) <<" node(s) "  << endl;
 // on met à jour les références
 lesRef->SupprimeReference("N_tout",idmail); // on supprime la référence N_tout
 Tableau <int> nv_num(NBN,0); // nouveau num/ au ancien, initialisé à 0
 for (int ia=1;ia <= nbn_restant; ia++)
      nv_num(tab_final(ia)->Num_noeud()) = ia;
 
// *** modif 15 avril 2016: il faut tous les numéros de remplacement et pas seulement ceux
// qui restent car  dans la mise à jour on commence par changer les numéros et "ensuite"
// on supprime les doublons --> donc on complète
// nv_num(num_ancien) = le nouveau numéro de noeud donc celui qui est en coincidence et qui reste
// a_fusionner(ancien_num_Noe(ia)) -> le nouveau numéro dans l'ancien tableau
// qui aura comme nouveau numéro:nv_num(a_fusionner(ancien_num_Noe(ia)))
 for (int ia=1;ia <= NBN; ia++)
   if (nv_num(ia) == 0) // cela veut dire que c'est un numéro qui disparait
      nv_num(ia) = nv_num(a_fusionner(ancien_num_Noe(ia)));
 
 
 lesRef->Mise_a_jour_ref_noeud(nv_num,idmail,non_referencer);
 // on enregistre le nouveau tableau de noeuds
 tab_noeud = tab_final;
 // on met à jour les numéros de noeuds
 for (int ia=1;ia <= nbn_restant; ia++)
      tab_noeud(ia)->Change_num_noeud(ia);
 // on recrée la référence N_tout
 string ntout("N_tout");
 { // on construit le tableau des numéros de noeuds
   Tableau <int> tabN(nbn_restant); for (int i=1;i<=nbn_restant;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
  };

};

// Lecture et suppression  d'elements à 2 noeuds, de distances très proches
void Maillage::LectureEtSup_Elem_noeudsConfondu(UtilLecture * entreePrinc, LesReferences* lesRef)
 { if (strstr(entreePrinc->tablcar,"suppression_elements_2noeuds_tres_proches_")!=NULL)
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to collapse element with two nodes which are "
																	 << " nearly at the same position "<< endl ;
        // on lit la distance mini
        double rayon = 0;string nom;
        *(entreePrinc->entree) >> nom >> rayon;
        if (nom != "suppression_elements_2noeuds_tres_proches_")
         { cout << "\n error : we expected the keyword: suppression_elements_2noeuds_tres_proches_ but we read \""<<nom<<"\" ";
           if (ParaGlob::NiveauImpression() >= 6)
             cout << "\n Maillage::LectureEtSup_Elem_noeudsConfondu(...";
           Sortie(1);
         };
        if (ParaGlob::NiveauImpression() >= 5)
          cout << "\n minimum distance = " << rayon;
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de suppression
        Sup_Elem_noeudsConfondu(rayon,lesRef);
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to collapse element with two nodes which are "
																	 << " nearly at the same position "<< endl ;   
      };
 };
// suppression  d'elements à 2 noeuds, de distances très proches
// rayon : donne la distance maxi entre les noeuds
void Maillage::Sup_Elem_noeudsConfondu(double rayon, LesReferences* lesRef)
{  // on crée un tableau d'indicateur des éléments à supprimer
   int nbelem = tab_element.Taille();
   Tableau <int> elem_supprime(nbelem,0);
   // on calcul les frontières et les mitoyens de tous les éléments
   Calcul_tous_les_front_et_leurs_mitoyens();
   // on balaie les éléments
   for (int ine = 1;ine <= nbelem;ine++)
    // on ne continue que si c'est un élément qui n'a pas déjà été marqué " à supprimé "
    if (elem_supprime(ine) == 0)
    {Element * elem = tab_element(ine);
     // on ne continue que si c'est un éléments à 2 noeuds
     if (elem->Nombre_noeud() == 2)
      { // on récupère les deux noeuds
        Noeud * noe1 = tab_element(ine)->Tab_noeud()(1);
        Noeud * noe2 = tab_element(ine)->Tab_noeud()(2);
        // on calcule la distance entre les deux noeuds
        if ((noe1->Coord0()-noe2->Coord0()).Norme() < rayon)
           elem_supprime(ine)=1;  // on enregistre la suppression
      }
     else if (elem->Nombre_noeud() == 3)
      { // un élément à 3 noeuds peut également être supprimable, mais
        // pour l'instant il faut qu'il ne soit relié qu'à des éléments également à 3 ou 2 noeuds
        //  .. on itère sur les cotés tout d'abord pour s'assurer que les mitoyens ont au plus 3 ou 2
        // noeuds: car si on a un mitoyen à 4 noeuds par exemple, il faut le convertir en
        // un élément à 3 noeud, c'est possible mais pas directement dans la version actuelle
        bool continou = true; // init
        // pour chaque élément "i" , mitoyen_de_chaque_element(i)(j) contient l'élément Front
        // qui décrit la frontière "j" de l'élément et dedans, les éléments mitoyens de cette frontière
        // appartenant à d'autres éléments
        for (int i=0;i<3;i++)
         {Front& fron = mitoyen_de_chaque_element(ine)(i+1);
          const Tableau <Front*>* t_mitoy = fron.TabMitoyen();
          if (t_mitoy != NULL)
           {int taille = t_mitoy->Taille();
            for (int j=1;j<= taille; j++)
             { if( (*t_mitoy)(j)->PtEI()->Nombre_noeud()>3)
                  {continou = false; break;}; // pas bon on arrête
             };
           }
          if (!continou) break; // arrêt car mitoyen avec plus de 3 noeuds
         };
        // Maintenant on regarde la distance entre les noeuds de chaque frontière
        // pour l'instant ne fonctionne que pour des frontières à 2 noeuds
        if (continou)
         for (int i=0;i<3;i++)
          { Front& fron = mitoyen_de_chaque_element(ine)(i+1);
            // on ne continue que s'il s'agit d'un élément frontière à 2 noeuds
            const Tableau <Noeud *>& tlocNoe = fron.Eleme()->TabNoeud();
            if (tlocNoe.Taille() == 2)
              { // on récupère les deux noeuds de l'arête
                Noeud * noe1 = tlocNoe(1);
                Noeud * noe2 = tlocNoe(2);
                // on calcule la distance entre les deux noeuds
                if ((noe1->Coord0()-noe2->Coord0()).Norme() < rayon)
                   {elem_supprime(ine)=1;  // on enregistre la suppression
                    // on doit également suppimer les éléments mitoyens
                    const Tableau <Front*>* t_mitoy = fron.TabMitoyen();
                    if (t_mitoy != NULL)
                     { int tail = t_mitoy->Taille();
                       for (int a=1;a<=tail;a++)
                         {Front* fr = (*t_mitoy)(a);
                          elem_supprime(fr->PtEI()->Num_elt())=1;
                         };
                     };
                   };
              };
          };
      };
    };

   // -- maintenant on va vraiment supprimer les éléments et mettre à jour les références
   // 1- tout d'abord on s'intéresse aux éléments, dont on va mettre à jour les références
   // 2- on supprime les éléments qui ne servent plus
   int nb_elem_restant = nbelem; // init du nombre d'élément restant après suppression
   Tableau <bool> non_referencer(nbelem,false); // un tableau intermédiaire qui servira pour les ref
   for (int ine=1;ine<=nbelem;ine++)
     {if (elem_supprime(ine)) // s'il est différent de 0, on doit supprimer
       { //int num_nelem = elem_supprime(ine); // ne sert à rien ici, j'ai repris l'algo Collapse_noeuds_proches
         delete tab_element(ine); // on supprime l'élément
         tab_element(ine)=NULL; // on indique qu'il n'y a plus d'élément
         non_referencer(ine)=true; // servira pour les ref
         nb_elem_restant--; // on diminue le nombre d'éléments restants
         if (ParaGlob::NiveauImpression() > 2)
               cout << "\n delete element " << ine << " <-- " ;
       };
     };
  
   // maintenant on refait un nouveau tableau d'éléments avec les éléments inutiles supprimés
   Tableau <Element* > tab_final(nb_elem_restant);
   int nbelem_restant=0; // le nombre d'éléments restant
   cout << "\n ";
   for (int ijn = 1; ijn <= nbelem; ijn++)
    { if(tab_element(ijn)!=NULL)
       {nbelem_restant++;
        tab_final(nbelem_restant) = tab_element(ijn);
       };
    };
   // // on redimentionne le tableau final (ses premières entitées restent !!)
   // tab_final.Change_taille(nbn_restant);
   if (ParaGlob::NiveauImpression() >= 0)
        cout << "\n delete of " << (nbelem-nbelem_restant) <<" element(s) "  << endl;
   // on met à jour les références
   lesRef->SupprimeReference("E_tout",idmail); // on supprime la référence E_tout
   Tableau <int> nv_num(nbelem,0); // nouveau num/ au ancien
   for (int ia=1;ia <= nbelem_restant; ia++)
        nv_num(tab_final(ia)->Num_elt()) = ia;
   lesRef->Mise_a_jour_ref_element(nv_num,idmail,non_referencer);
   // on enregistre le nouveau tableau d'éléments
   tab_element = tab_final;
   // on met à jour les numéros d'éléments
   for (int ia=1;ia <= nbelem_restant; ia++)
        tab_element(ia)->Change_num_elt(ia);
   // on recrée la référence E_tout
   string Etout("E_tout");
   { // on construit le tableau des numéros de noeuds
     Tableau <int> tabE(nbelem_restant); for (int i=1;i<=nbelem_restant;i++) tabE(i)=i;
     ReferenceNE*  rtout = new ReferenceNE(tabE,idmail,2,Etout);// construction de la référence
     lesRef->Ajout_reference(rtout); // ajout de la ref, qui est maintenant géré par lesRef
    };
   
};

// création d'éléments SFE en fonction d'éléments classiques
void Maillage::CreationMaillageSFE()
{  // une première étape est de vérifier que tous les éléments sont des triangles, sinon
   // arrêt et message d'incompétance
   if (!OKPourTransSfe())
   	{ cout << "\n error*** the mesh " << idmail << " ( " << nomDuMaillage << " ) "
   	       << " does not contain only triangular elements, currently  "
   	       << " the continuation of the processing is not possible ! -->  stop ";
   	  return;     
   	};
   	
   // sinon c'est ok, on n'a que des éléments triangulaires
   // -- on demande le choix d'éléments
   bool bonne_lecture=false;Enum_interpol enuSfe=SFE1;
   while (!bonne_lecture)
     { cout << "\n give the type of SFE element you want: "
            << "\n   SFE1   (resp 1)   SFE1_3D    (resp 11) "
            << "\n   SFE2   (resp 2)   SFE2_3D    (resp 12) "
            << "\n   SFE3   (resp 3)   SFE3_3D    (resp 13) "
            << "\n   SFE3C  (resp 4)   SFE3C_3D   (resp 14) "
            << "\n   QSFE1  (resp 5)   QSFE3      (resp 6)   ";
       string rep; rep = lect_chaine();
       if (rep == "1") {enuSfe = SFE1; bonne_lecture=true;}
       else if (rep == "2") {enuSfe = SFE2; bonne_lecture=true;}
       else if (rep == "3") {enuSfe = SFE3; bonne_lecture=true;}
       else if (rep == "4") {enuSfe = SFE3C; bonne_lecture=true;}
       else if (rep == "5") {enuSfe = QSFE1; bonne_lecture=true;}
       else if (rep == "6") {enuSfe = QSFE3; bonne_lecture=true;}

       else if (rep == "11") {enuSfe = SFE1_3D; bonne_lecture=true;}
       else if (rep == "12") {enuSfe = SFE2_3D; bonne_lecture=true;}
       else if (rep == "13") {enuSfe = SFE3_3D; bonne_lecture=true;}
       else if (rep == "14") {enuSfe = SFE3C_3D; bonne_lecture=true;}
       
       
       else  { cout << "\n bad answer, we have read : " << rep << "! try again ";};
     };
   cout << "\n choice read  : " << Nom_interpol(enuSfe);
   
   // On va créer des éléments en plus que ceux qui existent déjà, puis on supprimera ceux qui 
   // existent, et on les remplacera par ceux que l'on vient de créer
   int tabelTaille = tab_element.Taille();
   Tableau< Tableau <Noeud *> > t_noe_ele(tabelTaille); // les noeuds des SFE
   // on commence par remplir t_noe_ele en considérant qu'il n'y a pas de mitoyen
   int nbe_C = 3; // init: nb de noeud centraux
   if ((enuSfe == QSFE3) || (enuSfe == QSFE1))
       nbe_C = 6; // interpolation quadratique au centre
   for (int i4 = 1; i4 <= tabelTaille; i4++) 
     { Tableau <Noeud *>& t_noe = t_noe_ele(i4); // pour simplifier
       Element * elem = tab_element(i4); // recup de l'element
       t_noe.Change_taille(nbe_C+3); // nbe_C+3 noeuds pour les sfe triangles
       // les noeuds du centre
       for (int i=1;i<= nbe_C;i++)
         t_noe(i) = &(elem->Noeud_elt(i));
       // les noeuds externes initialisés aux noeuds centraux des sommets
       t_noe(nbe_C+1) = &(elem->Noeud_elt(1));
       t_noe(nbe_C+2) = &(elem->Noeud_elt(2));
       t_noe(nbe_C+3) = &(elem->Noeud_elt(3));
         
//       t_noe(1) = t_noe(4) = &(elem->Noeud_elt(1));
//       t_noe(2) = t_noe(5) = &(elem->Noeud_elt(2));
//       t_noe(3) = t_noe(6) = &(elem->Noeud_elt(3));
     };
   
   // I-- on définit les noeuds externe de chaque triangles
   // I.1- on crée des tableaux permettant d'accélérer l'algorithme final
   //      pour chaque noeud on regarde quel élément contiend ce noeud
   int tab_noeud_taille= tab_noeud.Taille();
   Tableau <List_io <Element*> > indice(tab_noeud_taille);
   // indice contiend les éléments succeptibles d'avoir des arrêtes communes
   // on en profite également pour calculer les normales à chaque élément
   Tableau <Coordonnee > tab_Nor(tabelTaille);
   for (int i22 = 1; i22 <= tabelTaille; i22++)
       { Element * elem1 = tab_element(i22); // recup de l'element
         Tableau<Noeud *>& tabn = elem1->Tab_noeud(); // récup de son tableau de noeud
//         int tabntaille = tabn.Taille();
         int tabntaille = 3; // on n'utilise que les noeuds sommets !! : 1 mars 2021
         for (int ij=1;ij<= tabntaille;ij++)
            indice((tabn(ij)->Num_noeud())).push_back(elem1); // on balaie ses noeuds
         // calcul de la normale
         Coordonnee A=tabn(1)->Coord0();Coordonnee B=tabn(2)->Coord0();
         Coordonnee C=tabn(3)->Coord0();
         Coordonnee AB(B-A); Coordonnee AC(C-A);
         tab_Nor(i22)=Util::ProdVec_coor(AB,AC);tab_Nor(i22).Normer();
       };
   // I.2 - un tableau intermédiaire t_i(i) , d'indiçage local
   //       l'indice i = le numéro du premier noeud de l'arrête, et t_i(i) = le num du noeud externe
   Tableau <int > t_i(3);
   t_i(1)=6; t_i(2)=4;  t_i(3)=5; // init éléments SFE lineaires
   if ((enuSfe == QSFE3) || (enuSfe == QSFE1))
       {t_i(1)=9; t_i(2)=7;  t_i(3)=8; }// interpolation quadratique au centre

   // également un tableau pour noter les éléments dont la courbure est supérieure à un maxi
   // c'est à dire qui ont deux facettes avec un produit scalaire des normales suffisamment grand
   // on choisit arbitrairement 30° c-a-d cos(pi/6) = 0.86603
   Tableau <int> elem_courb(tabelTaille,0); // par défaut tous sont ok
   double limit_inf_prod_scal = 0.86603; // la limite inf -> servira pour les SFE3
   // qui sera mesuré par
   // I.3- maintenant on va de nouveau boucler sur les éléments en regardant
   // pour chaque arrêtes si elle est effectivement commune
   for (int i1 = 1; i1 <= tabelTaille; ++i1)
     {Element * elem1 = tab_element(i1); // recup de l'element
//      Tableau<Noeud *>& tabn = elem1->Tab_noeud(); // récup de son tableau de noeuds
      //int nb_noe_elem1 = tabn.Taille();
      // on boucle sur les 3 arrêtes
      // normalement les 3 premiers noeuds sont les sommets du triangle
      for (int ina=1;ina<=3;ina++) 
       { int noe1 = elem1->Noeud_elt(ina).Num_noeud();// num du premier noeud de l'arrête
         int noe2 = 0; // init pour le second noeud
         if (ina == 3) { noe2 = elem1->Noeud_elt(1).Num_noeud();}
         else          { noe2 = elem1->Noeud_elt(ina+1).Num_noeud();}
         List_io <Element*>& indic1 = indice(noe1); // les éléments à considérer pour noe1
         List_io <Element*>& indic2 = indice(noe2); // les éléments à considérer pour noe2
         // on cherche un élément de l'intersection de indic1 et indic2
         // qui doit également être différent de l'élément central
         List_io <Element*>::iterator il1,ilfin1=indic1.end();
         List_io <Element*>::iterator il2,ilfin2=indic2.end();
         list <Element *> candidats; // une liste de travail
         for (il1=indic1.begin();il1 != ilfin1;il1++)
           for (il2=indic2.begin();il2 != ilfin2;il2++)
              if (((*il1) == (*il2)) && ((*il1) != elem1 )) 
                { //ele = (*il1); break;
                  candidats.push_back((*il1));
                };
         // maintenant parmi tous les candidats on va choisir celui qui conduit à l'élément le plus plat
         // NB: on considère que les éléments sont correctement orientés dans le même sens
         Element* ele = NULL; // init a priori
         if (candidats.size() != 0)
          { list <Element *>::iterator ilfin=candidats.end();
            list <Element *>::iterator il=candidats.begin();
            ele = (*il); il++; // on stocke a priori le premier élément
            double prodscal = tab_Nor(ele->Num_elt()) * tab_Nor(elem1->Num_elt());
            // puis on parcours les éléments suivants et on garde celui dont le prodscal est le + grand
            for (;il != ilfin;il++)
             { double prod = tab_Nor((*il)->Num_elt()) * tab_Nor(elem1->Num_elt());
               if (prod > prodscal)
                 {prodscal = prod; ele = (*il);};
             };
            // si le produit scalaire est inférieur à limit_inf_prod_scal, on enregistre
            if (prodscal < limit_inf_prod_scal)
              elem_courb(elem1->Num_elt()) = 1;
           
          };
         // si on a trouvé un candidat
         if (ele != NULL)
           {// on recherche le noeud qui n'est pas commun avec l'arrête
            for (int j=1;j<=3;j++) // on boucle sur les 3 noeuds sommets de l'élément
             {int num = ele->Noeud_elt(j).Num_noeud();
              if ((num != noe1) && (num != noe2))
               { // on met à jour le tableau des noeuds externes
                 t_noe_ele(i1)(t_i(ina)) = &(ele->Noeud_elt(j));
                 break;
               };
             };
           };
         // si aucun candidat n'est trouvé, t_noe_ele reste tel_quel
       };
     };
   // II-- on crée les éléments SFE
//   bool bonne_lecture=false;Enum_interpol enuSfe=SFE1;
//   while (!bonne_lecture)
//     { cout << "\n give the type of SFE element you want: "
//            << "\n   SFE1   (resp 1)   SFE1_3D    (resp 11) "
//            << "\n   SFE2   (resp 2)   SFE2_3D    (resp 12) "
//            << "\n   SFE3   (resp 3)   SFE3_3D    (resp 13) "
//            << "\n   SFE3C  (resp 4)   SFE3C_3D   (resp 14) ";
//       string rep; rep = lect_chaine();
//       if (rep == "1") {enuSfe = SFE1; bonne_lecture=true;}
//       else if (rep == "2") {enuSfe = SFE2; bonne_lecture=true;}
//       else if (rep == "3") {enuSfe = SFE3; bonne_lecture=true;}
//       else if (rep == "4") {enuSfe = SFE3C; bonne_lecture=true;}
//
//       else if (rep == "11") {enuSfe = SFE1_3D; bonne_lecture=true;}
//       else if (rep == "12") {enuSfe = SFE2_3D; bonne_lecture=true;}
//       else if (rep == "13") {enuSfe = SFE3_3D; bonne_lecture=true;}
//       else if (rep == "14") {enuSfe = SFE3C_3D; bonne_lecture=true;}
//
//
//       else  { cout << "\n bad answer, we have read : " << rep << "! try again ";};
//     };
//   cout << "\n choice read  : " << Nom_interpol(enuSfe);
   Element * toto = NULL;
   Tableau<Element *> tab_SFE(tabelTaille,toto); // création de pointeurs nuls
   // cas d'info annexe
   string str_precision(""); // stockage info annexe de choix, initié à rien par défaut
   bonne_lecture=false; int num_pti=0; // init
   if (enuSfe == SFE3 ) // on a des nombres de pti variables que pour les SFE3
    while (!bonne_lecture)
     { cout << "\n give eventually le number of integration point : "
            << "\n   2, 3, 4, 5, 6, 7, 12, 13 : ";
       string rep; rep = lect_chaine();
       if (rep == "2") {str_precision="";bonne_lecture=true;num_pti=2;}
       else if (rep == "3") {str_precision="_cm3pti";bonne_lecture=true;num_pti=3;}
       else if (rep == "4") {str_precision="_cm4pti";bonne_lecture=true;num_pti=4;}
       else if (rep == "5") {str_precision="_cm5pti";bonne_lecture=true;num_pti=5;}
       else if (rep == "6") {str_precision="_cm6pti";bonne_lecture=true;num_pti=6;}
       else if (rep == "7") {str_precision="_cm7pti";bonne_lecture=true;num_pti=7;}
       else if (rep == "12") {str_precision="_cm12pti";bonne_lecture=true;num_pti=12;}
       else if (rep == "13") {str_precision="_cm13pti";bonne_lecture=true;num_pti=13;}
       else  { cout << "\n bad answer, we have read : " << rep << "! try again ";};
     };
   if (enuSfe == SFE1 ) // idem pour les SFE1
    while (!bonne_lecture)
     { cout << "\n give eventually le number of integration point : "
            << "\n   2, 5 : ";
       string rep; rep = lect_chaine();
       if (rep == "2") {str_precision="";bonne_lecture=true;num_pti=2;}
       else if (rep == "5") {str_precision="_cm5pti";bonne_lecture=true;num_pti=5;}
       else  { cout << "\n bad answer, we have read : " << rep << "! try again ";};
     };
 
   for (int i5 = 1; i5 <= tabelTaille; ++i5)
     {ElemMeca * el = ((ElemMeca *) tab_element(i5)); // recup de l'element
      Tableau <Noeud *>& t_noe = t_noe_ele(i5); // pour simplifier
      Tableau<Noeud *>& tabn = el->Tab_noeud(); // récup de son tableau de noeuds
      // coordonnées du centre de gravité
      Coordonnee G = (tabn(1)->Coord0()+tabn(2)->Coord0()+tabn(3)->Coord0())/3.;
      double epaisseur =  el->Epaisseurs(TEMPS_0,G); // épaisseur à G
      switch (enuSfe)
        { case SFE1:  switch (num_pti)
             { case 2: tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
               case 5: tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
               default:
                 cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                      << " avec " << num_pti << " pti "
                      << " n'est pas possible pour l'instant " << endl;
             };
            break;
          case SFE2:  tab_SFE(i5) = new TriaSfe2(epaisseur,idmail,el->Num_elt(),t_noe); break;
          case SFE3:
            // si la courbure de l'élément est trop grande on bascule vers un SFE1
            if (elem_courb(i5))
             { if (ParaGlob::NiveauImpression() > 0)
                 cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
                      << "  est remplace par un SFE1 car la courbure est sup a 30° "<< endl;
               switch (num_pti)
               { case 2: tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
                 case 5: tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 default:
                  if (ParaGlob::NiveauImpression() > 2)
                    cout << " attention le cas "<<Nom_interpol(enuSfe)
                         << " avec " << num_pti << " pti "
                         << " sera remplace par un SFE1 avec seulement 5 pti " << endl;
                  tab_SFE(i5) = new TriaSfe1_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
               };
             }
            else // cas normal
             {switch (num_pti)
               { case 2: tab_SFE(i5) = new TriaSfe3(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 3: tab_SFE(i5) = new TriaSfe3_cm3pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 4: tab_SFE(i5) = new TriaSfe3_cm4pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 5: tab_SFE(i5) = new TriaSfe3_cm5pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 6: tab_SFE(i5) = new TriaSfe3_cm6pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 7: tab_SFE(i5) = new TriaSfe3_cm7pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 12: tab_SFE(i5) = new TriaSfe3_cm12pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 case 13: tab_SFE(i5) = new TriaSfe3_cm13pti(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 default:
                   cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                        << " avec " << num_pti << " pti "
                        << " n'est pas possible pour l'instant " << endl;
               };
             }
          break;
          case QSFE1:
            { num_pti = 2; // pour l'instant seul le cas avec 2 pti dans l'épaisseur
              // existe, on laisse le choix suivant pour mémoire mais il faudra ensuite
              // modifier pour demander le nb de pti en surface et en hauteur ...
              switch (num_pti)
                { case 2: tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe);
                          break;
                  default:
                    cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                         << " avec " << num_pti << " pti "
                         << " n'est pas possible pour l'instant " << endl;
                };
               break;
            }
          case QSFE3:
            // si la courbure de l'élément est trop grande on bascule vers un SFE1
            if (elem_courb(i5))
             { if (ParaGlob::NiveauImpression() > 0)
                 cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
                      << "  est remplace par un QSFE1 car la courbure est sup a 30° "<< endl;
               switch (num_pti)
               { case 2: tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
                 default:
                  if (ParaGlob::NiveauImpression() > 2)
                    cout << " attention le cas "<<Nom_interpol(enuSfe)
                         << " avec " << num_pti << " pti "
                         << " sera remplace par un SFE1 avec seulement Sxh = 3x2 pti " << endl;
                  tab_SFE(i5) = new TriaQSfe1(epaisseur,idmail,el->Num_elt(),t_noe);break;
               };
             }
            else // cas normal
             {switch (num_pti)
               { case 2: tab_SFE(i5) = new TriaQSfe3(epaisseur,idmail,el->Num_elt(),t_noe);break;
                 default:
                   cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                        << " avec " << num_pti << " pti "
                        << " n'est pas possible pour l'instant " << endl;
               };
             }
          break;
          case SFE3C:  tab_SFE(i5) = new TriaSfe3C(epaisseur,idmail,el->Num_elt(),t_noe); break;

  //        case SFE1_3D:  tab_SFE(i5) = new TriaSfe1(epaisseur,idmail,el->Num_elt(),t_noe); break;
  //        case SFE2_3D:  tab_SFE(i5) = new TriaSfe2(epaisseur,idmail,el->Num_elt(),t_noe); break;
          case SFE3_3D:  tab_SFE(i5) = new TriaSfe3_3D(idmail,el->Num_elt(),t_noe); break;
  //        case SFE3C_3D:  tab_SFE(i5) = new TriaSfe3C(epaisseur,idmail,el->Num_elt(),t_noe); break;
          default:
            cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                 << " avec " << num_pti << " pti "
                 << " n'est pas possible pour l'instant " << endl;
        };
	    };
 
   // II_bis-- maintenant que les SFE sont fabriqué, on fait un dernier passage pour voir si à l'origine
   // il n'y a pas un pb de calcul de courbure
   double inf_normale=0.01;
   switch (enuSfe)
        { case SFE3: case SFE3C: case SFE3_3D: // cas particulier des sfe3
          case QSFE3 :
             {cout << "\nAssocie au choix SFE3, il y a une verification"
                   << " avant le calcul de la distorsion du maillage"
                   << " celle-ci est controlee par le calcul de la courbure"
                   << " initiale via le determinant de la matrice des composantes de courbure"
                   << " si le determinant est trop petit (inf a une limite) on bascule"
                   << " automatiquement vers des elements sfe1"
                   << "\n valeur de la limite inf ? (rep par defaut "<<inf_normale
                   <<" retour chariot ou f) "<<endl;
              string rep = "_";
              rep = lect_return_defaut(true,"f");
              // si la taille de rep == 0 cela veut dire que c'est un retour chariot
              if ((rep.size()==0)||(Minuscules(rep) == "f"))
                {cout << "--> valeur par defaut : " << inf_normale << endl;}
              else
                {inf_normale = ChangeReel(rep);
                 cout << "--> valeur lue "<< inf_normale << endl;
                };
              break;
             }
          default:  break;
        };
 
   
   // pour l'instant on se fixe une limite inf mais ensuite il faudra demander à l'utilisateur
   for (int i5 = 1; i5 <= tabelTaille; ++i5)
     { SfeMembT& el = *((SfeMembT*) tab_SFE(i5)); // pour simplifier
       Tableau <Noeud *>& t_noe = t_noe_ele(i5); // pour simplifier
       Tableau<Noeud *>& tabn = el.Tab_noeud(); // récup de son tableau de noeuds
       // coordonnées du centre de gravité
       Coordonnee G = (tabn(1)->Coord0()+tabn(2)->Coord0()+tabn(3)->Coord0())/3.;
       double epaisseur =  el.Epaisseurs(TEMPS_0,G); // épaisseur à G
       int verif_courb = el.Test_courbure_anormale3(TEMPS_0,inf_normale);
       // si pb inconnue
       if (verif_courb == -1)
        { cout << "\n *** pb verification de l'element  "<<Nom_interpol(enuSfe)<< " "<<i5
               << "\n *** on laisse tel quel mais il y a un pb !! **** "
               << "\n info sur l'element: \n ";
          if (ParaGlob::NiveauImpression() > 1)
            el.Affiche(2);
        }
       else // sinon cas normal de vérif avec remplacement éventuel
        {// si pb on modifie éventuellement les éléments, a minima on signale
         if (!verif_courb)
          {// on crée un nouvel element intermédiaire
           Element * eleinter;
           switch (enuSfe)
             { case SFE1: case SFE2: case QSFE1:
                  cout << "*** pb, la verification de l'element  "<<Nom_interpol(enuSfe)<< " "<<i5
                       << " montre que le calcul de la courbure initiale est de mauvaise qualite "
                       << " il faut s'attendre a des pb dans la simulation du comportement  " << endl;
                  break;
               case SFE3: case SFE3C: case SFE3_3D:
                // on va remplacer l'élément par un SFE1 qui a priori de pose pas de pb
                if (ParaGlob::NiveauImpression() > 0)
                     cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
                          << " est remplace par un SFE1 (calcul de la courbure"
                          << " initiale de mauvaise qualite)  " << endl;
                switch (num_pti)
                 { case 2: eleinter = new TriaSfe1(epaisseur,idmail,el.Num_elt(),t_noe); break;
                   case 5: eleinter = new TriaSfe1_cm5pti(epaisseur,idmail,el.Num_elt(),t_noe);break;
                     default:
                      if (ParaGlob::NiveauImpression() > 2)
                        cout << " attention le cas "<<Nom_interpol(enuSfe)
                             << " avec " << num_pti << " pti "
                             << " sera remplace par un SFE1 avec seulement 5 pti " << endl;
                      eleinter = new TriaSfe1_cm5pti(epaisseur,idmail,el.Num_elt(),t_noe);break;
                 };
                break;
                case QSFE3:
                 // on va remplacer l'élément par un QSFE1 qui a priori de pose pas de pb
                 if (ParaGlob::NiveauImpression() > 0)
                      cout << " attention l'element " << Nom_interpol(enuSfe)<< " "<<i5
                           << " est remplace par un QSFE1 (calcul de la courbure"
                           << " initiale de mauvaise qualite)  " << endl;
                 switch (num_pti)
                  { case 2: eleinter = new TriaQSfe1(epaisseur,idmail,el.Num_elt(),t_noe); break;
                    default:
                       if (ParaGlob::NiveauImpression() > 2)
                         cout << " attention le cas "<<Nom_interpol(enuSfe)
                              << " avec " << num_pti << " pti "
                              << " sera remplace par un SFE1 avec seulement Sxh 3x2 pti " << endl;
                       eleinter = new TriaQSfe1(epaisseur,idmail,el.Num_elt(),t_noe);break;
                  };
                 break;
                default:
                  cout << "*** pb, le cas "<<Nom_interpol(enuSfe)
                       << " avec " << num_pti << " pti "
                       << " n'est pas possible pour l'instant " << endl;
             };
           // on remplace de sfe
           delete tab_SFE(i5);
           tab_SFE(i5)=eleinter;
           // on revérifie que le nouvel élément est correct
           if (!(((SfeMembT*) tab_SFE(i5))->Test_courbure_anormale3(TEMPS_0,inf_normale)))
              cout << "*** pb, la verification de l'element  "<<Nom_interpol(enuSfe)<< " "<<i5
                   << " montre que la courbure initiale calculee est tres grande "
                   << " il faut s'attendre a des pb dans la simulation du comportement  " << endl;
          };
        }
     };
 
   // III-- on efface les éléments triangulaires et on les remplaces par les SFE
   for (int i6 = 1; i6 <= tabelTaille; ++i6)
     { delete tab_element(i6);
       tab_element(i6) = tab_SFE(i6);
     };
 
};
 
// test pour savoir si le maillage est ok pour être transformée en sfe
bool Maillage::OKPourTransSfe()
{  // on vérifie que tous les éléments sont des triangles, sinon
   // message d'incompétance
   int tabelTaille = tab_element.Taille();
   bool on_continue=true; // bon par défaut
   // on boucle sur les elements 
   for (int i2 = 1; i2 <= tabelTaille; i2++)
//   	 if ((tab_element(i2)->Id_geometrie() != TRIANGLE)
//   	     || (tab_element(i2)->Id_interpolation() != LINEAIRE))
// 1 mars 2021 ==> maintenant on peut avoir des triangles internes quadratique
     if (tab_element(i2)->Id_geometrie() != TRIANGLE)
   	        {on_continue = false;break;};
   if (!on_continue)
   	{ cout << "\n Warning *** the mesh " << idmail << " ( " << nomDuMaillage << " ) "
   	       << " does not contain only linear triangular element, currently  "
   	       << " the continuation of the processing is not possible ! -->  stop ";
    };
   // retour
   return on_continue;
};

//  lecture et suppression éventuelle des noeuds, non référencés par les éléments et les références 
void Maillage::LectureEtSuppressionNoeudNonReferencer(UtilLecture * entreePrinc,LesReferences& lesRef)
 { if (strstr(entreePrinc->tablcar,"suppression_noeud_non_references_")!=NULL) // cas d'une demande de suppression
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process to delete nodes which are "
																	 << " not connected with an element "<< endl ;   
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de suppression
        SuppressionNoeudNonReferencer(lesRef);
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process to delete nodes which are "
																	 << " not connected with an element "<< endl ;   
      };
 };

// uniquement suppression éventuelle des noeuds, non référencés par les éléments et les références
void Maillage::SuppressionNoeudNonReferencer(LesReferences& lesRef)
 {  if (ParaGlob::NiveauImpression() > 2)
       cout << "\n delete of nodes which are not referred in the mesh "
            << nomDuMaillage << endl;
    // on commence par chercher les noeuds non référencés
    int taille_tabnoeud=tab_noeud.Taille();
    Tableau <bool> non_referencer(taille_tabnoeud,true);
    // on passe en revue tous les éléments, pour marquer les noeuds référencés
    int nbelem = tab_element.Taille();
    for (int ie = 1; ie <= nbelem ; ie++)
   	  { Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
   	    int dim_tnel = tnel.Taille();
   	    for (int ib = 1; ib <= dim_tnel; ib++)
   	      non_referencer(tnel(ib)->Num_noeud())=false;
   	  };
   	// idem les références
// le cas des références fonctionnent, mais en fait, ce n'est pas 
// une bonne idée de garder les noeuds référencés dans les références seulement
// a priori, il vaut mieux ne garder que les noeuds référencés par les éléments
// et supprimer tous les autres, d'où la mise en commentaires du cas des références   	 
   	/* 
	const Reference* refe = lesRef.Init_et_Premiere();
	while (refe != NULL)
	 { if (refe->Indic() == 1)
	 	{ // cas d'une référence de noeud
	 	  ReferenceNE* refeN = ((ReferenceNE*) refe); // on récupère la référence
	 	  if (refeN->Nom() != "N_tout")
      	   {int nb_el = refeN->Taille();
      	    for (int i=1; i<= nb_el; i++)
      	      { int num_noeud = refeN->Numero(i);
      	        if ((num_noeud > taille_tabnoeud ) || (num_noeud < 1))
      	        	{ cout << "\n erreur: pendant la suppression des noeuds non references, "
      	        	       << " le numero " << num_noeud << " de la reference " << refeN->Nom() 
      	        	       << " n'est pas correcte, peut-etre que le noeud n'existe pas ? "
      	        	       << " on arrete la procedure ";
      	        	  return;     
      	        	}
      	        else 	
      	            { non_referencer(num_noeud)=false;};
      	      };
      	   };
	 	};
	   // on passe à la référence suivante
	   refe = lesRef.Reference_suivante();	
	 }; */
    // maintenant on refait un nouveau tableau de noeud avec les noeuds inutiles supprimés
    Tableau <Noeud* > tab_final(taille_tabnoeud);
    int nbn_restant=0; // le nombre de noeud restant
    cout << "\n ";
    for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
     {if (non_referencer(ijn) == false)
       {nbn_restant++;
        tab_final(nbn_restant) = tab_noeud(ijn);
       }
		    else
       { if (ParaGlob::NiveauImpression() > 2)
             cout << "\n delete of the node " << ijn ; //<< endl;
         delete tab_noeud(ijn); // suppression du noeud
       };
		   };
    if (ParaGlob::NiveauImpression() > 2)
        cout << " \n " << (taille_tabnoeud-nbn_restant)
             << " nodes have been deleted  "  << endl;
    // on redimentionne le tableau final (les premiers restent !!)
    tab_final.Change_taille(nbn_restant);
    // on met à jour les références
    lesRef.SupprimeReference("N_tout",idmail); // on supprime la référence N_tout
    Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
    for (int ia=1;ia <= nbn_restant; ia++)
        nv_num(tab_final(ia)->Num_noeud()) = ia;
    lesRef.Mise_a_jour_ref_noeud(nv_num,idmail,non_referencer);
    // on enregistre le nouveau tableau de noeud
    tab_noeud = tab_final;
    // on met à jour les numéros de noeuds
    for (int ia=1;ia <= nbn_restant; ia++)
       tab_noeud(ia)->Change_num_noeud(ia);
	   string ntout("N_tout");
    // on recrée la référence N_tout
    { // on construit le tableau des numéros de noeuds
      Tableau <int> tabN(nbn_restant); for (int i=1;i<=nbn_restant;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
    };
 };
//  Affichage des noeuds, non référencés par les éléments
void Maillage::AffichageNoeudNonReferencer()
 {  //if (ParaGlob::NiveauImpression() > 2)
//       cout << "\n print nodes which are not referred in the mesh "
//            << nomDuMaillage << endl;
 #ifdef UTILISATION_MPI
   // cas d'un  calcul //, seul le CPU 0 affiche
   if (ParaGlob::Monde()->rank() != 0)
      return ;
 #endif
    // on commence par chercher les noeuds non référencés
    int taille_tabnoeud=tab_noeud.Taille();
    Tableau <bool> non_referencer(taille_tabnoeud,true);
    // on passe en revue tous les éléments, pour marquer les noeuds référencés
    int nbelem = tab_element.Taille();
    for (int ie = 1; ie <= nbelem ; ie++)
   	  { Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
   	    int dim_tnel = tnel.Taille();
   	    for (int ib = 1; ib <= dim_tnel; ib++)
   	      non_referencer(tnel(ib)->Num_noeud())=false;
   	  };
    bool existe_non_reference = false; // init par défaut
    // on regarde s'il faut afficher un warning
    for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
     {if (non_referencer(ijn))
       {existe_non_reference=true;break;};
		   };
    if (existe_non_reference)
     {for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
       {if (non_referencer(ijn))
         { cout << "\n --- print nodes which are not referred in the mesh --- "
                << nomDuMaillage ;
           cout << "\n ** warning: the node " << tab_noeud(ijn)->Num_noeud()
                << " is not link with an element ! ";
         }
       };
     };
  
 };

//  lecture et création éventuelle d'une ref sur les noeuds, non référencés par les éléments
void Maillage::LectureEtCreationRefNoeudNonReferencer(UtilLecture * entreePrinc,LesReferences& lesRef)
 { if (strstr(entreePrinc->tablcar,"creation_ref_noeud_non_references_")!=NULL) // cas d'une demande de création
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n beginning of the process of building a new reference on nodes which are "
																	 << "\n not connected with an element "<< endl ;
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de suppression
        CreationRefNoeudNonReferencer(lesRef);
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the process of building a new reference on nodes which are "
																	 << "\n not connected with an element "<< endl ;   
      };
 };

// création éventuelle d'une référence sur les noeuds, non référencés par les éléments
void Maillage::CreationRefNoeudNonReferencer(LesReferences& lesRef)
 {  if (ParaGlob::NiveauImpression() > 2)
       cout << "\n new ref of nodes which are not referred by an element "
            << nomDuMaillage << endl;
    // on commence par chercher les noeuds non référencés
    int taille_tabnoeud=tab_noeud.Taille();
    Tableau <bool> non_referencer(taille_tabnoeud,true);
    // on passe en revue tous les éléments, pour marquer les noeuds référencés
    int nbelem = tab_element.Taille();
    for (int ie = 1; ie <= nbelem ; ie++)
   	  { Tableau<Noeud *>& tnel = tab_element(ie)->Tab_noeud();
   	    int dim_tnel = tnel.Taille();
   	    for (int ib = 1; ib <= dim_tnel; ib++)
   	      non_referencer(tnel(ib)->Num_noeud())=false;
   	  };
    // maintenant on refait une nouvel liste de noeud avec les noeuds non référencés
    list <Noeud* > list_final;
    cout << "\n ";
    for (int ijn = 1; ijn <= taille_tabnoeud; ijn++)
     {if (non_referencer(ijn) == true)
       {list_final.push_back(tab_noeud(ijn));};
		   };
    int taille = list_final.size();
    if ((ParaGlob::NiveauImpression() > 2) && (taille != 0))
        cout << " \n " << taille
             << " nodes are not referred by an element  "
             << " new ref = N_noeud_libre "<< endl;
	   string nlibre("N_noeud_libre");
    // on recrée la référence N_noeud_libre
    { // on construit le tableau des numéros de noeuds
      list <Noeud* >::iterator il,ilfin=list_final.end();
      Tableau <int> tabN(taille);
      int i=1; // init
      for (il = list_final.begin(); il != ilfin;il++,i++)
        {tabN(i)= (*il)->Num_noeud();}
      ReferenceNE*  rlibre = new ReferenceNE(tabN,idmail,1,nlibre);// construction de la référence
      lesRef.Ajout_reference(rlibre); // ajout de la ref, qui est maintenant géré par lesRef
    };
 };
// ------------------------------ partie relative à la renumérotation --------------

// lecture et renumérotation éventuelle des noeuds
// ici la renumérotation permet d'optimiser la largeur de bande relative au maillage uniquement
// par exemple on ne tiens pas compte de relations linéaires éventuelles entre des noeuds
void Maillage::LectureEtRenumerotation(UtilLecture * entreePrinc,LesReferences& lesRef)
 { if (strstr(entreePrinc->tablcar,"renumerotation_des_noeuds_")!=NULL) // cas d'une demande de renumérotation
      { if (ParaGlob::NiveauImpression() > 2) cout << "\n  beginning of the new numbering of nodes " << endl ;
        entreePrinc->NouvelleDonnee(); // on passe le mot clé
        // appel de l'algo de renumérotation
        Tableau <Tableau <Condilineaire> > condCLL; // un tableau par défaut 
        bool calcul_ok = Renumerotation(lesRef,condCLL);
        if (!calcul_ok) // si retour false, pas de renumerotation effectué
         { cout << "\n ** warning: no new numbering of nodes !! ";};
        if (ParaGlob::NiveauImpression() > 2) cout << "\n end of the new numbering of nodes \n" << endl ;
      };
 };

// renumérotation des noeuds du maillage, en fonction  de conditions linéaires éventuelles
// ramène false si rien n'a changé (à cause d'un pb ou parce que la renumérotation n'est pas meilleure), vrai sinon
// nv_tab est tel que : nv_tab(i) est le nouveau numéro qui avait auparavant le numéro "i"
bool  Maillage::Renumerotation(LesReferences& lesRef
                              ,const Tableau <Tableau <Condilineaire> >& condCLL)
{  bool retour = false; // par défaut pour le retour
   int taille_tabnoeud=tab_noeud.Taille();
   // on calcul le point de départ
   Tableau < LaLIST_io <Noeud* > > t_voisin; // def du tableau des voisins
   list < list < Noeud_degre  > >  lis_descent; // stockage des descendants
// --- suppression de la création d'éléments frontières,
// c'est fait avant, dans l'algo appelant, car certaine fois on ne veut pas que cela change
//   CreeElemFront(); // on crée tous les éléments frontières
   if (listFrontiere.size()==0)
      CreeElemFront(); // on essaie en conditionnel
   // on crée un tableau intermédiaire pour appeler les routines suivantes qui sont static
   Tableau <Tableau <Noeud*> *> tt_noeud_front(1);
   tt_noeud_front(1) = &tab_noeud_front;
   bool calcul_ok = true; // init par défaut
   Noeud* noe_dep = Point_de_depart(tab_element,tab_noeud,tt_noeud_front,t_voisin,lis_descent,condCLL,calcul_ok);
   if (!calcul_ok) // il y a un pb, on sort en le signalant
    { retour = false;}
   else // sinon on continue
    {// on appelle l'algorithme de Cuthill Mac Kee
     Tableau <Noeud* > tab_N_final =  Cuthill_Mac_Kee(taille_tabnoeud,noe_dep,t_voisin,lis_descent);
     // --- maintenant on regarde l'évolution de la largeur de bande en noeud
     // tout d'abord la largeur initiale
     int largeur_initiale	 = LargeurBandeEnNoeuds(tab_element);
     // on change la numérotation
     for (int ia=1;ia <= taille_tabnoeud; ia++)
        tab_N_final(ia)->Change_num_noeud(ia);
     // nouvelle largeur de bande
     int largeur_Cuthill = LargeurBandeEnNoeuds(tab_element);
     // on change en numérotation inverse : Cuthill Mac Kee inverse
     Tableau <Noeud* > tab_N_inverse(tab_N_final);
     for (int ia=1;ia <= taille_tabnoeud; ia++)
        {tab_N_final(ia)->Change_num_noeud(1+taille_tabnoeud-ia);
         tab_N_inverse(1+taille_tabnoeud-ia) = tab_N_final(ia);
        };
     int largeur_Cuthill_inverse = LargeurBandeEnNoeuds(tab_element);
     if (ParaGlob::NiveauImpression() > 2)
      { cout << "\n 1/2 largeur de bande en noeud, initiale " << largeur_initiale
             << " apres l'algo de Cuthill Mac Kee " << largeur_Cuthill
             << " idem en inverse " << largeur_Cuthill_inverse  ;
      };

     // normalement le dernier est le meilleur, en tout cas il est meilleur que le cas 2
     if (   (largeur_initiale <= largeur_Cuthill_inverse)
         && (largeur_initiale <= largeur_Cuthill )
        )
         // bizarre, cela veut dire qu'il faut revenir à la forme initiale
         { for (int ia=1;ia <= taille_tabnoeud; ia++)
             tab_noeud(ia)->Change_num_noeud(ia);
           if (ParaGlob::NiveauImpression() > 2)
             cout << "\n pas d'amelioration, on garde la numerotation initiale "<<  endl ;
           retour = false; // pour signaler que rien n'a changé
         }
     else if (largeur_Cuthill < largeur_Cuthill_inverse)
         // bizarre, cela veut dire qu'il faut revenir à la forme de Cuthill directe
         { for (int ia=1;ia <= taille_tabnoeud; ia++)
              tab_N_final(ia)->Change_num_noeud(ia);
           Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
           for (int ia=1;ia <= taille_tabnoeud; ia++)
                nv_num(ia) = tab_noeud(ia)->Num_noeud();
           lesRef.Mise_a_jour_ref_noeud(nv_num,idmail);
           tab_noeud = tab_N_final;
           if (ParaGlob::NiveauImpression() > 2)
             cout << "\n on utilise la numerotation obtenue avec l'algo Cuthill direct "<<  endl ;
           retour = true; // pour signaler qu'il y a eu un changement
         }
     else
         // c'est le cas normale
         { Tableau <int> nv_num(taille_tabnoeud); // nouveau num/ au ancien
           for (int ia=1;ia <= taille_tabnoeud; ia++)
                nv_num(ia) = tab_noeud(ia)->Num_noeud();
           lesRef.Mise_a_jour_ref_noeud(nv_num,idmail);
           tab_noeud = tab_N_inverse;
           if (ParaGlob::NiveauImpression() > 2)
             cout << "\n on utilise la numerotation obtenue avec l'algo Cuthill inverse "<<  endl ;
           retour = true; // pour signaler qu'il y a eu un changement
         };
   };
  // retour
  return retour;
 };
 
// méthode static: c-a-d  indépendante des données du maillage (elle est générale)
// calcul du point de départ, en fonction  de conditions linéaires éventuelles 
// il y a également calcul des voisins et de la descendance du noeud de retour
// s'il y a un pb, calcul_ok en retour est false
Noeud*  Maillage::Point_de_depart(const Tableau<Element *>& tab_elem
                                  ,const Tableau<Noeud  *>& tab_noe
                                  ,const Tableau <Tableau <Noeud*> *> tt_noeud_front
                                  ,Tableau < LaLIST_io <Noeud* > >& t_voisin
                                  , list < list < Noeud_degre  > > & lis_descent
                                  ,const Tableau <Tableau <Condilineaire> >& condCLL,bool& calcul_ok)
 { // début de l'algorithme de gibbs, suivant la description faite par Pironneau
   // cf. Pironneau_coursWebFR.pdf page 81
   
   // • x,y,... sont les noeuds de la triangulation Th, 
   // • y est voisin de x s'il existe un élément T de Th tel que x et y en soient des noeuds, 
   // • le degré d'un noeud x est le nombre de ses voisins, il est noté d(x), 
   // • les voisins de x constituent N1(x) le niveau 1 de sa descendance, 
   // • les voisins des noeuds de N1(x) non encore répertoriés forment N2(x), 
   //   le niveau 2 de la descendance de x (un noeud apparaît au plus une fois 
   //   dans Nk(x) et par suite nt peut être dans les autres niveaux), 
   // • l'ensemble des niveaux Nk(x) constitue la descendance, notée D(x) du noeud x, 
   // • la profondeur p de la descendance est le nombre de niveaux de celle-ci, 
   
   // --- on recherche un bon point de départ
   // " Parmi les noeuds du contour du domaine, on sélectionne le noeud x " 
   // " tel que d(x) soit minimal: d(x) "
   calcul_ok=false; // init par défaut
   Noeud* noe_dep=NULL; // par défaut
   Maillage::Voisins(tab_elem,tab_noe,t_voisin,condCLL,calcul_ok); // on crée les voisins
   if (calcul_ok) // on ne continue que si Voisins s'est bien passé
    {// on définit le degré de chaque noeuds
     int taille_tabnoeud=tab_noe.Taille();
     Tableau <int> dx(taille_tabnoeud,1000000); // un tableau de dx initialisé à très grand
     for (int idx = 1; idx <= taille_tabnoeud; idx++)
      { dx(idx) = t_voisin(idx).size(); };

     // maintenant on cherche le plus petit dx des noeuds frontière
     int nb_front = tt_noeud_front.Taille();
     int numnoeuddep = 1;
     int dx_mini=dx((*(tt_noeud_front(1)))(1)->Num_noeud());
     for (int ifron = 1; ifron <= nb_front; ifron++)
      { Tableau <Noeud *> & tab_noeud_front = *(tt_noeud_front(ifron)); // pour simplifier
        int taille_noe_front = tab_noeud_front.Taille();
        for (int io =1; io <= taille_noe_front; io++)
           {int num_noe=tab_noeud_front(io)->Num_noeud();
            if (dx(num_noe) < dx_mini)
              { numnoeuddep = num_noe; dx_mini = dx(num_noe);};
           };
      };
     
     // Soient D(x) sa descendance et Np(x) son dernier niveau; on réalise alors l'algorithme suivant:
     // • Début
     // • Pour tous les noeuds y de Np(x), dans l'ordre croissant de leur degré d(y),
     //   on calcule D(y) et sa profondeur p(y),
     // • Si p(y) est supérieur à p(x) alors y est sélectionné, on fait x=y et on va à Début,
     //   Sinon on teste un nouvel y.
     
     int compt=1; // un compteur pour éviter une boucle infinie
     noe_dep = tab_noe(numnoeuddep);
     Descendance (taille_tabnoeud,noe_dep,t_voisin,lis_descent,calcul_ok);
     if (calcul_ok) // on ne continue que si Voisins s'est bien passé
      {int profondeur = lis_descent.size();
       bool premier_elem_ok = true;
       do
        { premier_elem_ok = true; // init dans le cas d'une nouvelle boucle
          // on calcul la descendance  du noeud
          // récup de son Np(x)
          list < Noeud_degre  >& lis_Npx = *(lis_descent.begin());
          lis_Npx.sort(); // classement
          list < Noeud_degre  >::iterator ic,icfin=lis_Npx.end();
          for (ic=lis_Npx.begin();ic != icfin; ic++)
           { list < list < Noeud_degre  > >  lis_des_inter;
             Noeud * noei = (*ic).noe; // pour simplifier
             Descendance (taille_tabnoeud,noei,t_voisin,lis_des_inter,calcul_ok);
             if (!calcul_ok)
               break; // si pb dans le calcul de la Descendance on sort de la boucle
             if (lis_des_inter.size() > profondeur)
              { // cas où on a trouvé une p(y) plus grand que p(x)
                profondeur = lis_des_inter.size();
                 noe_dep = noei;
                 lis_descent = lis_des_inter;
                 premier_elem_ok = false; // pour que l'on refasse une boucle dans le do
                 break;
              };
           };
          if (!calcul_ok)
             break; // si pb dans le calcul de la Descendance on sort de la boucle
          compt++; // pour éviter une boucle infinie
        }
       while ((compt < 1000) && (!premier_elem_ok));
       if (calcul_ok) // on ne continue que si Voisins s'est bien passé
        {
         // normalement ici soit on a fait 1000 passages et ça n'a pas marché, ou soit c'est ok
         if (compt == 1000)
          { cout << "\n Maillage::Renumerotation: on a fait 1000 passage on retiens le premier !! ";
            // on repasse en revue uniquement la liste des noeuds de lis_Npx pour le premier noeud
            noe_dep = tab_noe(numnoeuddep);
            Descendance (taille_tabnoeud,noe_dep,t_voisin,lis_descent,calcul_ok);
            if (calcul_ok) // on ne continue que si Voisins s'est bien passé
              {profondeur = lis_descent.size();
               bool cestLePoint_deDepart = true;
               // récup de son Np(x)
               list < Noeud_degre  >& lis_Npx = *(lis_descent.begin());
               lis_Npx.sort(); // classement
               list < Noeud_degre  >::iterator ic,icfin=lis_Npx.end();
               list < list < Noeud_degre  > >  lis_des_inter;
               for (ic=lis_Npx.begin();ic != icfin; ic++)
                { Noeud * noei = (*ic).noe; // pour simplifier
                  Descendance (taille_tabnoeud,noei,t_voisin,lis_des_inter,calcul_ok);
                  if (!calcul_ok)
                     break; // si pb dans le calcul de la Descendance on sort de la boucle
                  if (lis_des_inter.size() > profondeur)
                   { // cas où on a trouvé une p(y) plus grande que p(x)
                     profondeur = lis_des_inter.size();
                      noe_dep = noei;
                      cestLePoint_deDepart=false;
                   };
                };
               if (calcul_ok)
                {// si la descendance n'est pas sauvegardée
                 if (!cestLePoint_deDepart)
                   lis_descent = lis_des_inter;
                 // ici on est sur de sortir avec le plus petit p(x)
                };
   	          };
          };
        };
      };
    };      
  // retour
  return noe_dep; 	
		
};

// calcul des voisins de tous les  noeuds du maillage en fonction des éléments et de conditions
// linéaires éventuelles, 
// la méthode est en static, c-a-d qu'elle est indépendante des données du maillage (elle est générale)
// en entrée/sortie t_voisin
// restriction: il faut que tab_noe contienne tous les noeuds référencés dans tab_elem et tt_t_condCLL
// s'il y a un pb, calcul_ok en retour est false
Tableau < LaLIST_io <Noeud* > >& Maillage::Voisins(const Tableau<Element *>& tab_elem
                     ,const Tableau<Noeud  *>& tab_noe
                     ,Tableau < LaLIST_io <Noeud* > >& t_voisin
                     ,const Tableau <Tableau <Condilineaire> >& t_t_condCLL,bool& calcul_ok)
 { // on efface les voisins existants
   int taille_tabnoeud=tab_noe.Taille();
   t_voisin.Change_taille(taille_tabnoeud);
   for (int it = 1; it <= taille_tabnoeud; it++) 
      t_voisin(it).erase(t_voisin(it).begin(),t_voisin(it).end());
   // on passe en revue tous les éléments
   int nbelem = tab_elem.Taille();
   for (int ie = 1; ie <= nbelem ; ie++)
   	{ Tableau<Noeud *>& tnel = tab_elem(ie)->Tab_noeud();
   	  int dimtab = tnel.Taille();
   	  LaLIST_io <Noeud* > listlocal;
   	  for (int ine = 1; ine <= dimtab; ine++)  // création d'une liste locale de tous les 
   	  	{ listlocal.push_front(tnel(ine)); };  // noeud de l'élément
   	  listlocal.sort(); // on trie la liste locale 	
   	  // on remplit la liste globale 	
   	  for (int ine = 1; ine <= dimtab; ine++)
   	  	{ int ne = tnel(ine)->Num_noeud(); // le numéro du noeud
   	  	  LaLIST_io <Noeud* > list_inter = listlocal; // recopie, list_inter est donc également ordonnée
   	  	  t_voisin(ne).merge(list_inter); // on ajoute  en gardant l'ordre dans la liste résultante
   	  	};
   	};
   // on fait de même avec toutes les conditions linéaires
   int nb_gr_CLL = t_t_condCLL.Taille();
   for (int ig=1;ig<=nb_gr_CLL; ig++)
   	{Tableau <Condilineaire>& t_condCLL = t_t_condCLL(ig); // pour simplifier
   	 int taille_t_condCLL = t_condCLL.Taille();
   	 for (int ic = 1; ic<= taille_t_condCLL; ic++)
   	 	{const Tableau<Noeud *>& tnel = t_condCLL(ic).TabNoeud();	
   	     int dimtab = tnel.Taille();
      	 LaLIST_io <Noeud* > listlocal;
      	 for (int ine = 1; ine <= dimtab; ine++)  // création d'une liste locale de tous les 
      	 	{ listlocal.push_front(tnel(ine)); };  // noeud de l'élément 
      	 listlocal.sort(); // on trie la liste locale 	
      	 // on remplit la liste globale 	
      	 for (int ine = 1; ine <= dimtab; ine++)
      	 	{ int ne = tnel(ine)->Num_noeud(); // le numéro du noeud
      	 	  LaLIST_io <Noeud* > list_inter = listlocal; // recopie, list_inter est donc également ordonnée
      	 	  t_voisin(ne).merge(list_inter); // on ajoute  en gardant l'ordre dans la liste résultante
      	 	};
   	 	};
   	};

   // on supprime maintenant tous les doublons dans les listes des voisins
   // sachant que t_voisin(i) est déjà ordonné, because on a utilisé merge()
   for (int inn = 1; inn <= taille_tabnoeud; inn++)
   	  t_voisin(inn).unique(); // on supprime les doublons
//on vérifie que tous les noeuds ont un voisin
   calcul_ok = true; // init par défaut
   if (ParaGlob::NiveauImpression() > 3)
    {for (int i=1;i<=taille_tabnoeud;i++)
      if (t_voisin(i).size() == 0)
        {cout << "\n erreur dans Voisins(.., le noeud " << i << " n'a pas de voisins ! " << endl;
         calcul_ok = false; // là pb, on signale qu'il y a un pb
        };
    };
   // retour
   return t_voisin;		
 };

// méthode static: c-a-d  indépendante des données du maillage (elle est générale)
// calcul de la descendance d'un noeud noeu,
// on considère que les voisins sont dèjà correctement définis
// en entrée la liste qui est modifiée en interne et retournée en sortie
// le premier élément de la liste c'est la dernière descendance
// s'il y a un pb, calcul_ok en retour est false
list < list < Maillage::Noeud_degre  > > & Maillage::Descendance(const int& taille_tabnoeud
                              ,Noeud * noeu, Tableau < LaLIST_io <Noeud* > >& t_voisin
                              ,list < list < Maillage::Noeud_degre  > > & lient,bool& calcul_ok)
	{     //int taille_tabnoeud=tab_noeud.Taille();
	      int nb_noeud_restant = taille_tabnoeud; // le nombre de noeud a considérer
       Tableau <bool> utiliser(taille_tabnoeud); // un tableau indiquant si le noeud est utilisé ou pas
       // init du  niveau 0 avec le noeud
       utiliser(noeu->Num_noeud())=true;
       nb_noeud_restant--; 
       // on vide la liste d'entrée
       lient.erase(lient.begin(),lient.end());
       int dxxy = t_voisin(noeu->Num_noeud()).size(); // le degre du noeud
       list <Maillage::Noeud_degre > list_pere; list_pere.push_back(Maillage::Noeud_degre(noeu,dxxy));
       // pour le noeud, on rempli le premier niveau
       LaLIST_io <Noeud* >::iterator kl,klfin;
       list <Maillage::Noeud_degre >::iterator jl,jlfin;
       
       // on boucle
       while ((nb_noeud_restant > 0) && (list_pere.size() != 0))
       	{ list <Noeud_degre > liste_enfant; // l'étage courant
          jlfin=list_pere.end(); // init
          // on balaie la liste  des peres
       	  for (jl=list_pere.begin();jl != jlfin; jl++)
       	  	{ Noeud & noe = *((*jl).noe); // pour simplifier
       	  	  LaLIST_io <Noeud* >& lesvoisins = t_voisin(noe.Num_noeud());
       	  	  klfin=lesvoisins.end();
       	  	  for (kl=lesvoisins.begin();kl != klfin; kl++)
       	  	  	{ Noeud * novoi = (*kl); // pour simplifier
       	  	  	  int num_novoi = novoi->Num_noeud(); // le numéro de novoi
       	  	  	  if (! (utiliser(num_novoi))) // si le noeud n'a pas déjà été utilisé
       	  	  	     { int dxx = t_voisin(num_novoi).size(); // le degre du noeud
       	  	  	       liste_enfant.push_back(Maillage::Noeud_degre(novoi,dxx)); 
       	  	  	       utiliser(num_novoi)=true;nb_noeud_restant--;
       	  	  	     };
       	  	  	};
       	  	};
       	  // on enregistre les enfants
       	  lient.push_front(liste_enfant);
       	  // on init la liste des peres pour la boucle suivante
       	  list_pere = liste_enfant;	
       	};
       // vérification
       calcul_ok = true; // init par défaut
       if (nb_noeud_restant != 0)
       	{ if (ParaGlob::NiveauImpression()>3)
            {cout << "\n problem dans le calcul de la descendance (algorithme de gibbs) !!! il y a "
                  << nb_noeud_restant << " noeuds, qui ne sont pas "
       	          << " references par les elements, l'algorithme de renumeration ne fonctionne pas "
       	          << " dans ce cas !! ";
       	     for (int i=1;i<=taille_tabnoeud;i++)
       	        if (!utiliser(i)) cout << "\n c'est le numero : " << i << endl;
            };
       	  calcul_ok = false; // là pb, on signale
       	};
       // retour
       return lient; 
	};
	
// méthode static: c-a-d  indépendante des données du maillage (elle est générale)
// algorithme de Cuthill Mac Kee directe
// noeu : le noeud de départ
// lis_descent : les descendants de noeud, qui va être modifié dans le processus
// ramène une nouvelle numérotation (mais les numéros internes des noeuds ne sont pas changé
Tableau <Noeud* >  Maillage::Cuthill_Mac_Kee(const int& taille_tabnoeud,Noeud * noeu
                                        ,Tableau < LaLIST_io <Noeud* > >& t_voisin
                                        , list < list < Noeud_degre  > >&  lis_descent)
	{ // un tableau intermédiaire qui permet de savoir si un noeud a déjà été numéroté ou pas
	  Tableau <bool > numeroter(taille_tabnoeud,false);
	  // le tableau de retour
	  Tableau <Noeud* > tab_N_final(taille_tabnoeud);  
	  tab_N_final(1)=noeu; // le premier noeud
	  numeroter(noeu->Num_noeud())=true;
	  int numero_courant=2; // le numéro courant de prochain noeud à numéroter
	  
	  // la boucle
	  // on parcourt la liste des descendants
	  list < list < Noeud_degre  > >::reverse_iterator il,ilfin = lis_descent.rend();
	  list <Maillage::Noeud_degre >::iterator it,itfin;
   LaLIST_io <Noeud* >::iterator kl,klfin;
   int nb_couche = 1;
	  for (il=lis_descent.rbegin(); il != ilfin; il++,nb_couche++)
	  	{ list <Maillage::Noeud_degre >& list_pere = (*il);
	  	  //cout << "\n couche nb " << nb_couche << endl;
	  	  // on passe en revue les noeuds des peres et on recalcule le degré en tenant compte
	  	  // des noeuds déjà numérotés, qui ne doivent pas être pris en compte
	  	  itfin = list_pere.end();
	  	  for (it= list_pere.begin();it != itfin; it++)
	  	  	{ Noeud* no = (*it).noe; // pour simplifier
       	 LaLIST_io <Noeud* >& lesvoisins = t_voisin(no->Num_noeud());
       	 klfin=lesvoisins.end();
       	 int& degre = (*it).degre; // pour simplifier
       	 degre = 0;
       	 for (kl=lesvoisins.begin();kl != klfin; kl++)
       	 	{ Noeud * novoi = (*kl); // pour simplifier
       	 	  int num_novoi = novoi->Num_noeud(); // le numéro de novoi
       	 	  if (! (numeroter(num_novoi))) // si le noeud n'a pas déjà été numéroté
       	 	     { degre++; }; // on incrémente le degré
       	 	};
	  	  	};
	  	  // maintenant on ordonne la list_pere en fonction des degrés
	  	  list_pere.sort();	

	  	  // et on numérote à partir ce ceux qui ont le plus haut degré, c'est-à-dire le plus
	  	  // de voisin non encore numéroté
	     list <Maillage::Noeud_degre >::reverse_iterator rit,ritfin=list_pere.rend();
	     //int deb_num = numero_courant; // numéro le plus bas de la couche
	     //cout << "\n ";
	  	  for (rit= list_pere.rbegin();rit != ritfin; rit++)
	  	  	{ //cout << (*rit).degre << " ";
	  	  	  tab_N_final(numero_courant)=(*rit).noe;
	  	  	  numero_courant++;
	  	  	};
	  	  //int fin_num = numero_courant; // numéro le plus haut de la couche
	  	  // la largeur de bande finale est fonction du  maxi de (fin_num - deb_num) 
	  	  //cout << "\n largeur en noeud de la couche = " << fin_num - deb_num << endl;	
	  	};
	  // retour
	  return tab_N_final;	
	};                                         

// méthode static: c-a-d  indépendante des données du maillage (elle est générale)
// calcul de la largeur de bande en noeuds 
int Maillage::LargeurBandeEnNoeuds(const Tableau<Element *>& tab_elem)
 { // def du retour
   int largeur = 0; 
   // on passe en revue tous les éléments
   int nbelem = tab_elem.Taille();
   for (int ie = 1; ie <= nbelem ; ie++)
   	{ Tableau<Noeud *>& tnel = tab_elem(ie)->Tab_noeud();
   	  int dim_tnel = tnel.Taille();
   	  for (int ix = 1; ix <= dim_tnel; ix++)
   	    for (int iy = ix+1; iy <= dim_tnel; iy++)
   	      largeur = MaX(largeur, Abs(tnel(ix)->Num_noeud() - tnel(iy)->Num_noeud()) );
   	};
   	// retour
   	return largeur;
 };                            
 
// création automatique des références globales de frontière si demandé  dans le .info
void Maillage::CreationRefFrontiere(UtilLecture * entreePrinc,LesReferences& lesRef)
{  if (strstr(entreePrinc->tablcar,"def_auto_ref_frontiere_")!=NULL) 
	{  entreePrinc->NouvelleDonnee(); // on passe le mot clé
	   // on demande de créer les références
      CreationRefFrontiere(lesRef);	  		  
	 };
};

// demande de création automatique des références globales de frontière 
void Maillage::CreationRefFrontiere(LesReferences& lesRef)
{  if (ParaGlob::NiveauImpression() > 2) cout << " automatic definition of frontier references " << endl ;
   bool creationEffective=false; // pour savoir s'il y a une création effective
   // on regarde si les frontières existent, si oui on ne fait rien sinon on les crées
		
////---- debug
//      {  cout << "\n listFrontiere taille: " << listFrontiere.size() ;
//         LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
//			// on balaie les éléments frontière, et on récupère les éléments associé
//			for (ili=listFrontiere.begin();ili!=ilifin;ili++)
//			   (*(ili)).Affiche();
//			cout << endl;	
//		 };
////---- fin debug
		
   if (listFrontiere.size()==0) CreeElemFront();
////---- debug
//      {  cout << "\n listFrontiere taille: " << listFrontiere.size() ;
//         LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
//			// on balaie les éléments frontière, et on récupère les éléments associé
//			for (ili=listFrontiere.begin();ili!=ilifin;ili++)
//			   (*(ili)).Affiche();
//			cout << endl;	
//		 };
////---- fin debug
   // --- maintenant on commence par définir la référence des noeuds frontières
		 // c-a-d de tous les noeuds contenues dans les éléments frontières
   string ntoutfront("N_tout_front");
   if (!lesRef.Existe(ntoutfront,idmail))
     { // on construit le tableau des numéros de noeuds
		        int nbNf = tab_noeud_front.Taille();		  
          Tableau <int> tabN(nbNf); for (int i=1;i<=nbNf;i++) tabN(i)=tab_noeud_front(i)->Num_noeud();          
          ReferenceNE*  rtoutfront = new ReferenceNE(tabN,idmail,1,ntoutfront);// construction de la référence
          lesRef.Ajout_reference(rtoutfront); // ajout de la ref, qui est maintenant géré par lesRef
          if (ParaGlob::NiveauImpression() >= 8) rtoutfront->Affiche();
          if (ParaGlob::NiveauImpression() >= 4) cout << " N_tout_front ";
          creationEffective = true;
        };
		 // --- on continue par une référence sur les éléments de la frontière
		 string etoutfront("E_front");
   if (!lesRef.Existe(etoutfront,idmail))
    { // on définit une liste de stockage transitoire, because plusieurs éléments frontières
		    // peuvent se rattacher à un même élément fini
		    list <int> listE; 
		    LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
		    // on balaie les éléments frontière, et on récupère les éléments associé
		    for (ili=listFrontiere.begin();ili!=ilifin;ili++)
         listE.push_back((*ili).PtEI()->Num_elt());
		    listE.sort();// on ordonne la listE
      listE.unique();// on supprime les doublons
      // on crée un tableau correspondant à la liste
      // on construit le tableau des numéros des éléments
      int nbEfront = listE.size();
      Tableau <int> tabE(nbEfront); 
      list <int>::iterator ibi, ibifin = listE.end();
		    int i=1;
		    for (ibi=listE.begin();ibi!=ibifin;ibi++,i++)
			       tabE(i)=(*ibi);
      ReferenceNE*  retoutfront = new ReferenceNE(tabE,idmail,2,etoutfront);// construction de la référence
      lesRef.Ajout_reference(retoutfront); // ajout de la ref, qui est maintenant géré par lesRef
		    if (ParaGlob::NiveauImpression() >= 8) retoutfront->Affiche();
         if (ParaGlob::NiveauImpression() >= 4) cout << " ref E_front ";
         creationEffective = true;
    };
   // ---- puis  une référence sur les faces des éléments de la frontière 
   string ftoutfront("F_front");
   if (!lesRef.Existe(ftoutfront,idmail))
    { // on construit le tableau des numéros d'éléments + numéros de face
      //int nbEfront = listFrontiere.size();
		 // on définit une liste de stockage transitoire, because on ne connait pas a priori
		 // le nombre de face frontière
      list <NBelemEtFace> listEface; 
      LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
      // on balaie les éléments fronitère
      NBelemEtFace nu; // une grandeur de travail
      for (ili=listFrontiere.begin();ili!=ilifin;ili++)
			    { Enum_type_geom type_front = (*ili).Eleme()->Type_geom_front(); // le type de frontière
			    // on récupère le numéro de la face (éventuellement 0)
         nu.nbFace = (*ili).Num_frontiere();
			      // on n'intervient que si la frontière est une face
			      if (type_front == SURFACE)
				      { nu.nbElem = (*ili).PtEI()->Num_elt(); // le numéro de l'élément
				        // on considère que la face existe
				        listEface.push_back(nu);
				      };
       };
		    listEface.sort();// on ordonne la listE
		    listEface.unique();// on supprime les doublons
		    // maintenant on va s'occuper de créer la référence
		    int numElFace	= listEface.size();
		    if (numElFace != 0)
			     { // création des tableaux de numéros d'éléments et faces
	  	    	 Tableau<int> tabelem(numElFace); // éléments
	  	    	 Tableau<int> tabface(numElFace); // idem pour les face
	  	    	 list <NBelemEtFace >::iterator itn,itnfin=listEface.end();
	  	    	 int i=1;
	  	    	 for (itn=listEface.begin();itn!=itnfin;itn++,i++)
	  	    	   {tabelem(i)=(*itn).nbElem;tabface(i) = (*itn).nbFace;};
	  	    	 ReferenceAF* refAF = new ReferenceAF(tabelem,tabface,idmail,3,ftoutfront);// création de la référence
	  	    	 lesRef.Ajout_reference( refAF);
			       if (ParaGlob::NiveauImpression() >= 8) refAF->Affiche();
                 if (ParaGlob::NiveauImpression() >= 4) cout << " F_front ";
                 creationEffective = true;
        };
    };
   // ---- et enfin une référence sur les lignes des éléments
   //      ainsi qu'une référence des seules noeuds des lignes frontières
   string atoutfront("A_front");string nAreteFront("N_A_front");
   //bool n_a_front_existe = lesRef.Existe(nAreteFront,idmail);
   if (!lesRef.Existe(atoutfront,idmail))
     { // on construit le tableau des numéros d'éléments + numéros des arrêtes
       //int nbEfront = listFrontiere.size();
       // on définit une liste de stockage transitoire, because on ne connait pas a priori
       // le nombre de face frontière
       list <NBelemEtArete> listEArrete; 
       list <int> listN_Arrete; // idem pour les noeuds
       LaLIST <Front>::iterator ili, ilifin = listFrontiere.end();
       // on balaie les éléments frontières
       NBelemEtArete nu; // une grandeur de travail
       for (ili=listFrontiere.begin();ili!=ilifin;ili++)
			     { Enum_type_geom type_front = (*ili).Eleme()->Type_geom_front(); // le type de frontière
			       // on récupère le numéro de l'arête (éventuellement 0)
          nu.nbArete = (*ili).Num_frontiere();
			       // on n'intervient que si la frontière est une arête
			       if (type_front == LIGNE)
				        { nu.nbElem = (*ili).PtEI()->Num_elt(); // le numéro de l'élément
				          // on considère que l'arête existe
				          listEArrete.push_back(nu);
					         // idem pour les noeuds
					         const Tableau <Noeud *> ttn = (*ili).Eleme()->TabNoeud_const();
					         int taillettn = ttn.Taille();
					         for (int k=1;k<=taillettn;k++)
					           listN_Arrete.push_back(ttn(k)->Num_noeud());
            };
        };
       // maintenant on va s'occuper de créer la référence d'arêtes
		     int numElArrete	= listEArrete.size();
       if (numElArrete != 0)
		      { // création des tableaux de numéros d'éléments et d'arêtes
	  	 	    Tableau<int> tabelem(numElArrete); // éléments
          Tableau<int> tabArrete(numElArrete); // idem pour les arêtes
	  	 	    list <NBelemEtArete >::iterator itn,itnfin=listEArrete.end();
	  	 	    int i=1;
	  	 	    for (itn=listEArrete.begin();itn!=itnfin;itn++,i++)
	  	 	      {tabelem(i)=(*itn).nbElem;tabArrete(i) = (*itn).nbArete;};
          ReferenceAF* refAF = new ReferenceAF(tabelem,tabArrete,idmail,4,atoutfront);// création de la référence
	  	 	    lesRef.Ajout_reference( refAF);
		        if (ParaGlob::NiveauImpression() >= 8) refAF->Affiche();
          if (ParaGlob::NiveauImpression() >= 4) cout << " A_front ";
          creationEffective = true;
        };
		     // même chose pour la référence de noeuds
		     listN_Arrete.sort();// on ordonne la listE
		     listN_Arrete.unique();// on supprime les doublons
		     int numNArrete	= listN_Arrete.size();
		     if (numNArrete != 0)
		      { // création des tableaux de numéros de noeuds
	  	      Tableau<int> tabNArete(numNArrete); 
	  	      list <int >::iterator itn,itnfin=listN_Arrete.end();
	  	      int i=1;
	  	      for (itn=listN_Arrete.begin();itn!=itnfin;itn++,i++)
	  	           tabNArete(i)=(*itn);
	  	      ReferenceNE* refNE = new ReferenceNE(tabNArete,idmail,1,nAreteFront);// création de la référence
	  	      lesRef.Ajout_reference( refNE);
			       if (ParaGlob::NiveauImpression() >= 4) refNE->Affiche();
          if (ParaGlob::NiveauImpression() >= 4) cout << " N_A_front ";
          creationEffective = true;
        };
     };
	  if (creationEffective) cout << endl;
	  
   if (ParaGlob::NiveauImpression() >= 4) cout << " end of automatic definition of frontier references " << endl ;

};
 
// 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
void Maillage::VerifReference(LesReferences& lesRef)
{ // on va balayer toutes les références
  const Reference* refi = lesRef.Init_et_Premiere();  // init du balyage
  while (refi != NULL) 
	{ // on prend en compte que si c'est le bon maillage
	  if (refi->Nbmaille() == idmail)
	   { // choix en fonction du type de référence
		  switch (refi->Indic()) 
		   {case 1: // cas de noeuds
				{const ReferenceNE & refN  = *((ReferenceNE *) refi);
              int reftaille = refN.Taille();
				  int nbN = tab_noeud.Taille();
				  for (int nn =1; nn<= reftaille;nn++)  
				    if ((refN.Numero(nn) < 0) || (refN.Numero(nn) > nbN))
					   {cout << "\n **** error, the node number " << refN.Numero(nn) << " don't belong to the range of nodes of the mesh " 
						      << nomDuMaillage << " [1,"<< nbN << "] "
								<< "\n error of definition of the reference of nodes : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						 }
				}
				  break;
		    case 2: // cas d'éléments
				{const ReferenceNE & refE   = *((ReferenceNE *) refi);
              int reftaille = refE.Taille();
				  int nbE = tab_element.Taille();
				  for (int nn =1; nn<= reftaille;nn++)  
				    if ((refE.Numero(nn) < 0) || (refE.Numero(nn) > nbE))
					   {cout << "\n **** error, the element number  " << refE.Numero(nn) << " don't belong to the range of element of the mesh " 
						      << nomDuMaillage << " [1,"<< nbE << "] "
								<< "\n error of definition of the reference of elements : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						 }
				}
				  break;
		    case 3: // cas de surfaces d'éléments
				{const ReferenceAF & refF   = *((ReferenceAF *) refi);
              int reftaille = refF.Taille();
				  int nbE = tab_element.Taille();
				  for (int nn =1; nn<= reftaille;nn++)
					{ // récupération du numéro de face et élément
					  const int numE = refF.NumeroElem(nn); const int numF = refF.NumeroFA(nn);
				     if ((numE < 0) || (numE > nbE))
					   {cout << "\n **** error, the element number " << numE << " don't belong to the range of element of the mesh " 
						      << nomDuMaillage << " [1,"<< nbE << "] "
								<< "\n error of definition of the reference of elements surfaces : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						 };
					  // arrivé ici, cela signifie que l'élément existe, maintenant on regarde si la face peut exister
					  int nbface = tab_element(numE)->ElementGeometrique().NbFe(); 
				     if ((numF < 0) || (numF > nbface))
					   {cout << "\n **** error, the surface number " << numF << " of the element " << numE 
						      << " don't belong to the range of possible surfaces numbers of the element  [1,"<< nbface << "] "
								<< "\n error of definition of the reference of elements surfaces : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						};
					};
				}
				  break;
		    case 4: // cas d'arêtes d'éléments
				{const ReferenceAF & refA    = *((ReferenceAF *) refi);
              int reftaille = refA.Taille();
				  int nbE = tab_element.Taille();
				  for (int nn =1; nn<= reftaille;nn++)
					{ // récupération du numéro d'arête et élément
					  const int numE = refA.NumeroElem(nn); const int numA = refA.NumeroFA(nn);
				     if ((numE < 0) || (numE > nbE))
					   {cout << "\n **** error, the element number " << numE << " don't belong to the range of element of the mesh " 
						      << nomDuMaillage << " [1,"<< nbE << "] "
								<< "\n error of definition of the reference of elements edge : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						 };
					  // arrivé ici, cela signifie que l'élément existe, maintenant on regarde si l'arête peut exister
					  int nbArete = tab_element(numE)->ElementGeometrique().NbSe(); 
				     if ((numA < 0) || (numA > nbArete))
					   {cout << "\n **** error, the edge number " << numA << " of the element " << numE 
						      << " don't belong to the range of possible edges numbers of the element  [1,"<< nbArete << "] "
								<< "\n error of definition of the reference of elements edges : " << refi->Nom() << endl;
						 if (ParaGlob::NiveauImpression() >= 6) 
						   cout << "\n Maillage::VerifReference(LesReferences& lesRef) ";
					    Sortie(1);
						};
					};
				}
				  break;
			  default:
			    if (ParaGlob::NiveauImpression() >= 6) 
				   cout << " \n indication  ! no verification for reference on element node and on gauss point ";
				  break;
		  }		
		}
	  refi = lesRef.Reference_suivante();
    }
};

// méthode pour initialiser les différents tableaux utilisés par Orientation_elements_mitoyens_recursif
void Maillage::Init_Orientation_elements_mitoyens_recursif()
{  // - on initialise le tableau d'indicateur, permettant de savoir si un élément a été traité ou pas
   int nb_elem = tab_element.Taille();
   ind_elem.Change_taille(nb_elem,false); // def et init à 0, c-à-d non traité
   // --- à chaque fois que l'on va inverser le sens d'un élément, le sens de ses frontières normalement devrait également changer
   //     mais comme on ne les recalcule pas, on utilise un tableau pour s'en rappeler et s'en servir, au début = 1 pour tous les éléments
   tab_sens_element.Change_taille(nb_elem,1.);  // ensuite quand le sens change, la valeur passe à -1
};


// ** pour l'instant ne fonctionne que pour les éléments surfaces
// orientation automatique des éléments mitoyens, à l'élément num_elem, et ensuite
// récursivement à tous les éléments mitoyens des mitoyens jusqu'à ce que la chaine s'arrête
// L'ensemble des éléments est alors groupé dans une référence qui est construit
//   . soit à partir du numéro num_elem
//   . soit à partir d'un nom passé en paramètre (cf. nom_ref, ci dessous)
// et qui est ajouté aux refs déjà existantes
// ensuite, le programme passe en revue les éléments restants, et regarde s'ils font parti
// d'un ensemble homogène orienté, si non, ramène la liste des éléments hors ensemble orienté
// *** ne concerne que les éléments surfaces, les autres sont ignorés
// ind_elem(i) : (tableau interne) indique si l'élément i a été traité (=true) ou non (=false)
// ind_elem: est pris en compte puis mis à jour par le programme, c-a-d que les nouveaux éléments orienté
//           passe de false à true, par contre tous les éléments déjà à true, ne sont pas pris en compte dans le traitement
// angle_maxi : angle maximum entre deux éléments, au dessus duquel on considère qu'il y a une rupture de la mitoyenneté
// nom_ref : s'il est différent de "_", donne le nom de base voulu à la série de référence qui va être construite
// inverse : indique si l'on souhaite partir d'une orientation inverse de celle existante avant application de l'algo
//           ceci pour l'élément de départ: au premier appel, l'opération est toujours possible, ensuite cela dépend
//           si l'élément trouvé a déjà été traité ou pas
// recursiv : indique si l'on se situe dans une suite récursive d'appel de la méthode
//            si oui, seule les éléments non déjà pris en compte dans les appels précédents, sont examiné
//            c'est ind_elem qui permet de s'en assurer
//            si non: cas par exemple d'un angle_maxi qui change, on réexamine tous les éléments, cependant
//            la ré_orientation éventuelle n'est faite qu'une seule fois (toujours via ind_elem)
list <int>  Maillage::Orientation_elements_mitoyens_recursif(bool recursif,string& nom_base_ref,int num_elem
                                                             ,LesReferences& lesRef,double& angle_maxi,bool inverse)
{ double cos_angle_maxi = cos(angle_maxi); // pour simplifier
  // --- à chaque fois que l'on va inverser le sens d'un élément, le sens de ses frontières normalement devrait également changer
  //     mais comme on ne les recalcule pas, on utilise le tableau tab_sens_element (tableau interne)
  //     pour s'en rappeler et s'en servir, au début = 1 pour tous les éléments
  //     ensuite quand le sens change, la valeur passe à -1
  int nb_elem = tab_element.Taille();
  int compteur_elem_inverse=0; // pour compter le nombre d'éléments inversés
  // --- def de la liste des éléments qui ont été traité
  list <int> ele_oriente; // la liste des éléments qui ont été orienté, donc qui ont la même orientation
								  // servira à la fin pour créer les références
  // --- définition et initialisation de la liste d'éléments qu'il faut traiter
  list <int> ele_a_traiter; // la liste des éléments qu'il faut traiter
  ele_a_traiter.push_back(num_elem); // on initialise la liste à l'aide du numéro du premier élément à traiter
  // si c'est possible on change l'orientation de l'élément si c'est demandé
  if (inverse && (ind_elem(num_elem)==false))
   { tab_element(num_elem)->Modif_orient_elem(0);
     tab_sens_element(num_elem)=-1.;
   };
  #ifdef MISE_AU_POINT
  if (ParaGlob::NiveauImpression() > 4)
   { cout << "\n racine element nb: "<<num_elem<<" sens:"<<tab_sens_element(num_elem)<<endl;
   };
  #endif
  ind_elem(num_elem)=true; // on signale (dans tous les cas) que l'élément a été traité
  // c'est forcément une surface, car l'algo n'est appelé que dans ce cas
 
  ele_oriente.push_back(num_elem); // init avec le premier élément
  // -- def du tableau des Front qui ont été traité: elle permet d'éviter qu'une frontière (qui est dupliqué selon
  //    le nombre d'éléments qui la partage) soit traité plusieurs fois dans les boucles de recherches
  // t_front_deja_traite(i)(j) : indique si la frontière j de l'élément i, est traité ou non
  Tableau < Tableau <bool> >  t_front_deja_traite(nb_elem);
  for (int i=1;i<=nb_elem;i++)
    t_front_deja_traite(i).Change_taille(mitoyen_de_chaque_element(i).Taille(),false);
  
  // --- on va passer en revue tous les éléments de manière récursive, ceci à partir du premier élément: num_elem
  // on n'intervient que pour les éléments surfaces en 3D et ligne en 2D
 
  int dim = ParaGlob::Dimension(); // la dimension de l'espace de travail
  Coordonnee A,B,C,AB,AC,N; // des variables de travail
  Coordonnee Ap,Bp,Dp,ApBp,ApDp,N_mitoy; //    """
  while (ele_a_traiter.size() != 0) 
  { list <int>::iterator iter_elem_a_traiter = ele_a_traiter.begin(); // récup du premier élément
    int num_elem_a_traiter = (*iter_elem_a_traiter); // récup du numéro de l'élément
	   ele_a_traiter.erase(iter_elem_a_traiter); // on supprime l'élément de la liste à traiter

	   // récup des Front de l'élément
    Tableau <Front>& mtce = mitoyen_de_chaque_element(num_elem_a_traiter);

    // et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
    // ou une ligne en 2D
    if (   (Type_geom_generique(tab_element(num_elem_a_traiter)->Id_geometrie()) == SURFACE)
        || ((dim == 2)&& (Type_geom_generique(tab_element(num_elem_a_traiter)->Id_geometrie()) == LIGNE))
       )
      {int dim_mtce = mtce.Taille();
       // on passe en revue tous les Front
       for (int i=1;i<= dim_mtce;i++)
        { // on ne va s'intéresser qu'aux frontières lignes, qui sont celles qui joignent les éléments de surface
          // + aux cas où il existe des éléments mitoyens + au cas où le Front n'a pas été traité
          Front& fro = mtce(i); // pour simplifier
          const Tableau <Front*>* tabmitoy = fro.TabMitoyen();
          if ((fro.Eleme()->Type_geom_front() == LIGNE) && (tabmitoy != NULL)
             && (!t_front_deja_traite(num_elem_a_traiter)(fro.Num_frontiere())) )
           { int tail_tabmitoy = tabmitoy->Taille();
             // --- on calcul une normale à l'élément à l'aide des extrémités de la frontière ligne et d'un autre point
             //     ou d'un déterminant, dans le cas 2D
             Tableau <Noeud *>& tab_N_fro = fro.Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
             int tail_N_fro=tab_N_fro.Taille(); // récup de la taille
             A=tab_N_fro(1)->Coord0(); B= tab_N_fro(tail_N_fro)->Coord0(); // def des extrémités
             // on récupère les numéros de A et B
             int num_A=tab_N_fro(1)->Num_noeud();int num_B=tab_N_fro(tail_N_fro)->Num_noeud(); 
             // on cherche un troisième noeud de l'élément, différent
             Tableau<Noeud *>& tab_N_elem = tab_element(num_elem_a_traiter)->Tab_noeud();
             int NBN=tab_N_elem.Taille();
             bool trouve_C=false;
             for (int j=1;j<=NBN;j++)
              { Noeud * pt_noeud=tab_N_elem(j);
                if ((pt_noeud->Num_noeud() != num_A) && (pt_noeud->Num_noeud() != num_B))
                  { C=pt_noeud->Coord0(); trouve_C=true;break;};
              };
             if (!trouve_C)
              { cout << "\n *** erreur dans l'algo Orientation_elements_mitoyens_recursif, on n'a pas"
                     << " trouve de point C ?? l'orientation automatique risque d'etre erronee " << endl;
              };
             // calcul des vecteurs intermédiaire
             AB=B-A;AC=C-A;
             double deter_centrale = 0.; // util pour le cas 2D
             if (dim == 3) // dans le cas 3D on utilise la normal
                { N=Util::ProdVec_coor(AB,AC); N.Normer();} // calcul de la normale, normée 
             else { deter_centrale = Util::Determinant(AB,AC);}; // cas 2D: on utilise le déterminant pour déterminer le sens  
             Front* fro_retenu=NULL; // init du Front que l'on retiendra au final
             bool mitoyen_meme_sens = true;  // par défaut on initialise l'élément mitoyen comme étant de même sens			
             // dans le cas où on a plusieurs éléments Front mitoyen, et que l'on est en dimension 3, on choisit un seul, 
             // celui qui correspond à un Element qui est le plus dans le prolongement de l'élément num_elem_a_traiter
             // en dimension 2, il n'y a pas de choix possible, on prend le premier élément 
             if ((tail_tabmitoy > 1) && (dim == 3))
              { // --- on passe en revue tous les mitoyens et on retiend celui donc la normale est le plus // avec celle de l'élément
                //     donc dont le produit scalaire avec la normale, est le plus important
                double projection = 0.; int num_front_mitoy = 0;
                for (int j=1;j<=tail_tabmitoy;j++)
                 { Front& fri = *(*tabmitoy)(j); // pour simplifier
                   // si on est récursif, on ne continue que si l'élément associé n'a pas été traité
                   int num_e = fri.PtEI()->Num_elt(); // récup du numéro de l'élément
                   // et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
                   if (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == SURFACE)
                    {if (!ind_elem(num_e) || !recursif )
                      { Tableau <Noeud *>& tab_N_fri = fri.Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
                        int tail_N_fri=tab_N_fri.Taille(); // récup de la taille
                        Ap=tab_N_fri(1)->Coord0(); Bp= tab_N_fri(tail_N_fro)->Coord0(); // def des extrémités
                        // on récupère les numéros de Ap et Bp
                        int num_Ap=tab_N_fri(1)->Num_noeud();int num_Bp=tab_N_fri(tail_N_fri)->Num_noeud(); 

                        // on cherche un troisième noeud de l'élément, différent des deux noeuds centraux
                        Tableau <Noeud *>& tab_N_elem_mitoy = fri.PtEI()->Tab_noeud(); // récup des noeuds de l'élément mitoyen
                        int NBN_mitoyen=tab_N_elem_mitoy.Taille();
                        bool trouve_Dp = false;
                        for (int k=1;k<=NBN_mitoyen;k++)
                         { Noeud * pt_n=tab_N_elem_mitoy(k);
                           if ((pt_n->Num_noeud() != num_Ap) && (pt_n->Num_noeud() != num_Bp))
                             { Dp=pt_n->Coord0(); trouve_Dp = true; break;};
                         };					  
                        if (!trouve_Dp)
                          { cout << "\n *** erreur dans l'algo Orientation_elements_mitoyens_recursif, on n'a pas"
                                 << " trouve de point Dp ?? l'orientation automatique risque d'etre erronee " << endl;
                          };
                        // calcul de la nouvelle normale, normée ici pour que ça soit indépendant de la surface de ABD
                        // (on utilise que la normale, car ici on doit être en 3D vue le test en début de block)
                        ApBp=Bp-Ap; ApDp=Dp-Ap; N_mitoy=Util::ProdVec_coor(ApBp,ApDp);N_mitoy.Normer();
                        // si l'élément de référence (num_elem_a_traiter) a eu un sens modifié, on en tient compte à l'aide de tab_sens_element
                        double essai_projection = tab_sens_element(num_elem_a_traiter) * N  * tab_sens_element(num_e) * N_mitoy;
     //	fro.Affiche(); fri.Affiche();			 
     //	cout << "\n tab_sens_element(num_elem_a_traiter) " << tab_sens_element(num_elem_a_traiter) << " essai_projection "<< essai_projection;			 
     //	cout << "\n ele= "<< fro.PtEI()->Num_elt() << " elem_mitoy= " << fri.PtEI()->Num_elt()
     //	     << "\n A:" << A << " B: " << B << " C: " << C << " N: " << N 
     //	     << "\n Ap: "<<Ap<< " Bp: " << Bp << " Dp: " << Dp << " N_mitoy: " << N_mitoy << endl;
                        if (Abs(essai_projection) > Abs(projection))
                          {projection = essai_projection; num_front_mitoy = j;}; 
            
     //	cout << "\n ** num_front_mitoy= " << num_front_mitoy << " projection= " << projection << endl;				  
            
                      };
                    };
                 };
                // arrivée ici on a la projection de l'élément associé, dans le cas où l'on a trouvé un élément non déjà traité
                if((num_front_mitoy != 0) && (Abs(projection) > Abs(cos_angle_maxi)))
                 { fro_retenu = (*tabmitoy)(num_front_mitoy); // on enregiste le front de l'élément mitoyen
                   if (projection < 0) {mitoyen_meme_sens = false;} // on regarde le sens
                   else					           {mitoyen_meme_sens = true;};
                 };
              }
             else if (tail_tabmitoy != 0)
              { // si on est récursif, on ne continue que si l'élément associé n'a pas été traité 
                int num_e = (*tabmitoy)(1)->PtEI()->Num_elt(); // récup du numéro de l'élément

                // et on ne contine que s'il s'agit d'un élément surface (ajout 15 avril 2016) en 3D
                // ou une ligne en 2D
                if (   (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == SURFACE)
                    || ((dim == 2)&& (Type_geom_generique(tab_element(num_e)->Id_geometrie()) == LIGNE))
                   )
                { if (!ind_elem(num_e) || !recursif )
                   { fro_retenu = (*tabmitoy)(1); // enreg
                     // on calcul une normale, pour ensuite avec la projection, savoir si le sens des éléments mitoyens est identique ou pas
                     Tableau <Noeud *>& tab_N_fro_retenu = fro_retenu->Eleme()->TabNoeud(); // récup des noeuds de la frontière ligne
                     int tail_N_fro_retenu=tab_N_fro_retenu.Taille(); // récup de la taille
                     Ap=tab_N_fro_retenu(1)->Coord0(); Bp= tab_N_fro_retenu(tail_N_fro)->Coord0(); // def des extrémités
                     // on récupère les numéros de Ap et Bp
                     int num_Ap=tab_N_fro_retenu(1)->Num_noeud();int num_Bp=tab_N_fro_retenu(tail_N_fro_retenu)->Num_noeud(); 

                     // on cherche un troisième noeud de l'élément, différent des deux noeuds centraux
                     Tableau <Noeud *>& tab_N_elem_mitoy = fro_retenu->PtEI()->Tab_noeud(); // récup des noeuds de l'élément mitoyen
                     int NBN_mitoyen=tab_N_elem_mitoy.Taille();
                     for (int k=1;k<=NBN_mitoyen;k++)
                       { Noeud * pt_n=tab_N_elem_mitoy(k);
                         if ((pt_n->Num_noeud() != num_Ap) && (pt_n->Num_noeud() != num_Bp))
                           { Dp=pt_n->Coord0(); break;}; 
                       };
                     // on différencie ici les cas 2D et 3D
                     ApBp=Bp-Ap; ApDp=Dp-Ap; 
                     if (dim == 3)
                      { // calcul de la nouvelle normale, normée ici pour que ça soit indépendant de la surface de ABD
                        N_mitoy=Util::ProdVec_coor(ApBp,ApDp);N_mitoy.Normer();
                        // si l'élément de référence (num_elem_a_traiter) a eu un sens modifié, on en tient compte à l'aide de tab_sens_element
                        // idem avec l'élément considéré
                        double projection = tab_sens_element(num_elem_a_traiter) * N * tab_sens_element(num_e) * N_mitoy;
                        if ( projection < 0) {mitoyen_meme_sens = false;} // on regarde le sens
                        else					            {mitoyen_meme_sens = true;};
                        // si l'angle est trop grand on ne tiens pas compte de la mitoyenneté
                        if (Abs(projection) < Abs(cos_angle_maxi))
                          fro_retenu = NULL;
     //	fro.Affiche(); fro_retenu->Affiche();
     //	cout << "\n tab_sens_element(num_elem_a_traiter) " << tab_sens_element(num_elem_a_traiter) << " projection "<<projection;			 
     //	cout << "\n ele= "<< fro.PtEI()->Num_elt() << " elem_mitoy= " << fro_retenu->PtEI()->Num_elt()
     //	     << "\n A:" << A << " B: " << B << " C: " << C << " N: " << N 
     //	     << "\n Ap: "<<Ap<< " Bp: " << Bp << " Dp: " << Dp << " N_mitoy: " << N_mitoy << endl;
                      }
                     else // cas 2D, on utilise les déterminants (ici il n'y a pas le pb de l'angle)
                      { double deter_mitoy = Util::Determinant(ApBp,ApDp);
                        if ( (deter_centrale * deter_mitoy) < 0) {mitoyen_meme_sens = false;} // on regarde le sens
                        else					                                {mitoyen_meme_sens = true;};
                      };
                   };
                };
              };
             // on ne traite que s'il y a effectivement un candidat mitoyen recevable
             if (fro_retenu != NULL) 
              { int num_e = fro_retenu->PtEI()->Num_elt(); // récup du numéro de l'élément
                if (!t_front_deja_traite(num_e)(fro_retenu->Num_frontiere()))
                 { // si il faut un changement d'orientation et que c'est possible on change
                   bool suite_traitement_possible = true; // init par défaut
                   if (!mitoyen_meme_sens) // changement d'orientation au cas où
                    { if (!ind_elem(num_e))
                        {tab_element(num_e)->Modif_orient_elem(0); //   "
                         tab_sens_element(num_e)=-1.;
                         compteur_elem_inverse++;
                        }
                      else
                       {suite_traitement_possible = false;
                        #ifdef MISE_AU_POINT
                        if (ParaGlob::NiveauImpression() > 4)
                          { cout << "\n ref "<<nom_base_ref<<" ele:"<<num_elem_a_traiter  <<" ne peut s'associer a "<< num_e
                                 << " car chg de sens demande impossible "<<endl;
                          };
                        #endif
                       };
                     };
                   // si tout est ok on enregistre
                   if (suite_traitement_possible)
                     { ele_oriente.push_back(num_e); // enreg pour la constitution des éléments ayant la même orientation
                       ind_elem(num_e)=true; // on enregistre le fait que l'élément a été traité
   //--debug
   //cout << "\n elem pere " << num_elem_a_traiter << " élément traité qui devient père " << num_e << endl;
   //--fin debug					 
         
         
                      ele_a_traiter.push_back(num_e); // ajout dans la liste des éléments à traiter en tant que père
                      // on indique pour les deux éléments mitoyens que la frontière commune, a été traité
                      t_front_deja_traite(num_elem_a_traiter)(fro.Num_frontiere())=true; // pour l'élément père
                      t_front_deja_traite(num_e)(fro_retenu->Num_frontiere())=true; // pour l'élément fils
                     };
                 }; 
              };
           };
        };
      };
  };  
  
  if (ParaGlob::NiveauImpression() > 3)
   {if (ParaGlob::Francais())
	        {cout << "\n nombre d'element inverses " << compteur_elem_inverse;}
	   else {cout << "\n number of elements with change of orientation : " << compteur_elem_inverse;};  
	  };
  // --- définit une nouvelle référence qui contient tous les éléments qui ont été traité
  // s'il s'agit bien de surface
  // on définit un nom possible pour la référence
  if (   (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) == SURFACE)
        || ((dim == 2)&& (Type_geom_generique(tab_element(num_elem)->Id_geometrie()) == LIGNE))
     )
    {string nom_ref;
     if (nom_base_ref == "_")
      { nom_ref = "E_ref_de_meme_orientation_que_ele_"+ChangeEntierSTring(num_elem);}
     else // cas où l'on spécifie un nom
      { nom_ref = "E_"+nom_base_ref;};
     while (lesRef.Existe(nom_ref,idmail)) // on regarde si le nom existe, si oui on ajoute un tiret
       nom_ref = nom_ref+"-";
     ReferenceNE* refeE = new ReferenceNE(ele_oriente,idmail,2, nom_ref); // création de la ref
     lesRef.Ajout_reference(refeE); // ajout de la ref
     // idem pour une référence de face
     string nom_refS;
     if (nom_base_ref == "_")
      { nom_refS = "F_ref_de_meme_orientation_que_ele_"+ChangeEntierSTring(num_elem);}
     else // cas où l'on spécifie un nom
      { nom_refS = "F_"+nom_base_ref;};
          
     while (lesRef.Existe(nom_refS,idmail)) // on regarde si le nom existe, si oui on ajoute un tiret
       nom_refS = nom_refS+"-";
     // il faut définir une deuxième liste de 1 pour définir des faces
     list <int> list_face(ele_oriente.size(),1);
     ReferenceAF* refeS = new ReferenceAF(ele_oriente,list_face,idmail,2, nom_refS); // création de la ref
     lesRef.Ajout_reference(refeS); // ajout de la ref

     if (ParaGlob::NiveauImpression() > 0)
      {if (ParaGlob::Francais())
         {cout << "\n creation de la reference : " << nom_ref << " ("<<refeE->Taille() <<" elements )";
          cout << "\n creation de la reference : " << nom_refS << " ("<<refeS->Taille() <<" surfaces )";}
       else {cout << "\n creation of the reference : " << nom_ref << " ("<<refeE->Taille() <<" elements )";
           cout << "\n creation of the reference : " << nom_refS << " ("<<refeS->Taille() <<" surfaces )";};
      };
    };
 
  // --- on construit la liste des éléments qui n'ont pas été orienté
  list <int> list_elem_non_orient; // def de la liste des éléments non orientés
  for (int i=1;i<=nb_elem;i++)
    if (!ind_elem(i))
	     list_elem_non_orient.push_back(i);
  // retour
  return list_elem_non_orient;
};

        
// change le numéro de maillage
void Maillage::Change_numero_maillage(int new_num)
{ if (idmail != new_num)
   { idmail = new_num;
     // on s'occupe des noeuds,
     int nbn = tab_noeud.Taille();
     for (int i=1;i<=nbn;i++)
       tab_noeud(i)->Change_num_Mail(new_num);
     // puis les éléments
     int nbelem = tab_element.Taille();
     for (int ie=1;ie<=nbelem;ie++)
       tab_element(ie)->Change_num_maillage(new_num);
     // la liste des noms de maillages
     listeNomMail[nomDuMaillage]=idmail;  
   };
};

 
  // méthode pour orienter des éléments en fonction d'un rayon: AG, A étant un point donné, G étant le centre de
  // gravité d'une facette
  // A : coordonnée d'un point, si indic_G(i) est true, alors A(i) est remplacé par la coordonnée G(i) du centre
  //     de gravité de la facette
  // zone_a_traiter: le nom de la référence des éléments a traiter
  // inverse : si true, l'orientation des normales des facettes est identique à celles de AG, sinon c'est l'inverse
 
void Maillage::Orientation_via_rayon(const Tableau <bool> & indic_G,const  Coordonnee & A
                             ,const  string& zone_a_traiter, LesReferences& lesRef, bool inverse)
{ // on commence par récupérer la liste des éléments sur laquelle on va travailler
  const ReferenceNE & refa = ((ReferenceNE &) lesRef.Trouve(zone_a_traiter,idmail));
  const Tableau<int>& tabN_de_Ref = refa.Tab_num(); // le tableau des éléments
  int dim = ParaGlob::Dimension();
  if (dim != 3)
   { cout << "\n la dimension de l'espace n'est pas 3, le traitement n'est pas possible !! ";
     if (ParaGlob::NiveauImpression() > 2)
       cout << "\n Maillage::Orientation_via_rayon(...";
     cout << endl;
     return;
   };
 
  // on parcours tous les éléments
  int nbn_ref = tabN_de_Ref.Taille();
  for (int i = 1; i <= nbn_ref;i++)
   { int nbE = tabN_de_Ref(i); // on récupère le numéro de l'élément
     // on n'effectue le traitement que s'il s'agit d'une surface
     Element& ele = *(tab_element(nbE));
////--- debug
//if (ele.Num_elt()==316)
//  cout << "\n debug Maillage::Orientation_via_rayon(..." << endl;
//
////--- fin debug
     if (Type_geom_generique(ele.Id_geometrie()) == SURFACE)
      { //calcul du centre de gravité
        Coordonnee3 G(dim);
        Tableau <Noeud *> taN = ele.Tab_noeud();
        int nbn = taN.Taille();
        for (int inn = 1;inn<=nbn;inn++)
         {Noeud* noe = taN(inn);
          G += noe->Coord0();
         };
        G /= nbn;
        // calcul du vecteur rayon
        Coordonnee3 AG(dim);
        for (int ia = 1;ia<=dim;ia++)
         { if (indic_G(ia))
             {AG(ia)=0.; } // c'est le cas où on utilise la coordonnée du centre de gravité
           else {AG(ia) = G(ia) - A(ia);};
         };
        AG.Normer();
//        // on calcul une normale moyenne à la surface
//        // tout d'abord on choisit un premier point pour un premier segment
//        Coordonnee3 B = taN(1)->Coord0();
//        Coordonnee3 GB(B-G);
//        Coordonnee3 N;
//        // on parcours tous les noeuds et on ajoute les normales
//        for (int inn = 2;inn<=nbn;inn++)
//         {Noeud* noe = taN(inn);
//          Coordonnee3 C(noe->Coord0());
//          Coordonnee3 GC(C-G);
//          N += Util::ProdVec_coor(GB,GC);
//         };
//        N /= nbn-1;
       
        // en fait la précédente méthode peut poser des pb,
        // on choisit une méthode plus simple
        //  une première arête
        Coordonnee3 A1A2(taN(2)->Coord0()-taN(1)->Coord0());
        // une seconde
        Coordonnee3 A2A3(taN(3)->Coord0()-taN(2)->Coord0());
        Coordonnee3 N(Util::ProdVec_coor(A1A2,A2A3));
        N.Normer();
        // on test le sens
        bool a_inverser = false; // init
        if ( (AG * N) > 0.) // même sens
         {if (inverse) a_inverser = true;
          else         a_inverser = false;
         }
        else // sens inverse
         {if (inverse) a_inverser = false;
          else         a_inverser = true;
         };
////--- debug
//{if (ele.Num_elt()==1)
//  cout << "\n debug Maillage::Orientation_via_rayon(..." << endl;
// cout << "\n element: " << ele.Num_elt() <<", AG * N = " << AG * N << " a_inverser= "<< a_inverser
//      << " AG= "<<AG <<" N= "<< N;
//}
//
////--- fin debug
       
       
       
        // s'il faut inverser on inverse
        if (a_inverser)
          ele.Modif_orient_elem(0);
      };
   };
};














 
