
// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.

# include <iostream>
using namespace std;  //introduces namespace std
#include <stdlib.h>
#include "Sortie.h"
#include "UtilLecture.h"
#include "Sortie.h"

#include <fstream> 
#include <cstdlib>
#include <iomanip>
#include <algorithm>
#include "ParaGlob.h"
#include <dirent.h> // pour la gestion de l'ouverture de directory
#include <unistd.h>  // idem 
#include "CharUtil.h"
#ifdef UTILISATION_MPI
  #include <boost/mpi/environment.hpp>
  #include <boost/mpi/communicator.hpp>
  #include <boost/serialization/string.hpp>
  #include <boost/serialization/vector.hpp>
  #include <boost/mpi.hpp>
  namespace mpi = boost::mpi;
#endif

// ouverture du fichier base_info après le .info  dans le cas d'un restart par exemple
// s'il est déjà ouvert on ne fait rien
// a priori le fichier est ouvert en lecture  : lecture
// mais il peut également être en écriture : ecriture
void UtilLecture::Ouverture_base_info(string type_entree)
  { char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, pteurnom);
    // on définit des noms explicites
    std::string nom_BI(pteurnom);
    std::string nom_PI(pteurnom);
    nom_BI += ".BI";
    nom_PI += ".PI";
 #ifdef UTILISATION_MPI
    lecture_MPI_BI_en_cours = 0; // initialisation
    num_cpu_en_cours_BI = ParaGlob::Monde()->rank();
 #endif


    if (type_entree == "lecture")
      // cas d'une lecture
      // on regarde si on a déjà une ouverture en écriture si oui on ferme
      //===1) cas du fichier BI ===
     {
     #ifndef UTILISATION_MPI
       {
         //===1) cas du fichier BI ===
         if (sort_BI != NULL)
             Fermeture_base_info();
         // maintenant on regarde si la lecture est déjà en cours
         // si pas de fichier ouvert, on ouvre
         if (ent_BI == NULL)
          { //ent_BI = new fstream(strcat(fileName,".BI"), ios::out | ios::in);
            ent_BI = new fstream(nom_BI.c_str(), ios::out | ios::in);
            if(!(ent_BI->is_open()))
             //  le fichier ne peut être ouvert, message d'erreur
             {  cout << "\n erreur en ouverture pour la lecture du fichier " << nom_BI << "\n"
                     << " UtilLecture::Ouverture_base_info() " << endl;
                Sortie(1);
             };
          };
       }
     #else
       { if (sort_MPI_BI != MPI_FILE_NULL)
             Fermeture_base_info();
         // maintenant on regarde si la lecture est déjà en cours
         // si pas de fichier ouvert, on ouvre (tous les proc doivent le faire car l'ouverture est une opération collective)
         if (ent_MPI_BI == MPI_FILE_NULL)
          { int ierr_ouverture_BI = MPI_File_open((*ParaGlob::Monde()),nom_BI.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &ent_MPI_BI);
            if((ierr_ouverture_BI) && (num_cpu_en_cours_BI == 0))
              //  le fichier ne peut être ouvert, message d'erreur
              {  cout << "\n ***erreur en ouverture pour la lecture du fichier " << nom_BI
                      << "\n proc: " << num_cpu_en_cours_BI
                      << "\n UtilLecture::Ouverture_base_info() " << endl;
                 Sortie(1);
              };
          };
         // sinon ok, on rend exploitable la méthode Nouvelle_enreg_MPI_BI
         lecture_MPI_BI_en_cours = 1; // on peut lire avec Nouvelle_enreg_MPI_BI
       };
     #endif

       // === cas du fichier de pointeur, traitement presque analogue ===
       bool positionPI = false; // pour de la gestion de cas

     #ifndef UTILISATION_MPI
       { ent_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
         if(!(ent_PI->is_open()))
            //  le fichier ne peut être ouvert, message d'erreur
            { ent_PI->clear();
              delete ent_PI;
              ent_PI = NULL;
              cout << "\n erreur en ouverture pour la lecture du fichier " << nom_PI << "\n"
                   << " le fichier de pointeur ne peut etre lu, on essaie de faire uniquement avec le .BI "
                   << endl;
            }
         else
           {
     #else
      // en MPI seule le proc 0 s'occupe du .PI car c'est lui qui transmettra les offsets finaux aux proc i
      // MPI_COMM_SELF pour dire qu'il s'agit du communicator uniquement relié au proc en cours, ici 0
      if(num_cpu_en_cours_BI == 0)
       // ouverture du .PI
       { if (ent_MPI_PI == MPI_FILE_NULL)
           {int ierr_ouverture_PI = MPI_File_open(MPI_COMM_SELF,nom_PI.c_str(),MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &ent_MPI_PI);
   // finalement si !!// non, tous les proc vont faire appel au positionnement d'incrément, du coup le plus simple est que tous proc lisent en bloc
   // par contre seule le proc 0 écrira
   //       { int ierr_ouverture_PI = MPI_File_open((*ParaGlob::Monde()),nom_PI.c_str(),MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &ent_MPI_PI);
            if(ierr_ouverture_PI)
               { ent_MPI_PI = MPI_FILE_NULL;
                 cout << "\n erreur en ouverture pour la lecture du fichier " << nom_PI
                      << "\n proc: " << num_cpu_en_cours_BI
                      << "\n le fichier de pointeur ne peut etre lu, on essaie de faire uniquement avec le .BI "
                      << endl;
               };
           };
         // cas particulier de la lecture en MPI io
         if (ent_MPI_PI!=MPI_FILE_NULL)
           {// on récupère en une seule étape le contenu du fichier,
            // a priori la taille du buffer nécessaire n'est pas grande
            MPI_Offset filesize;
            int ierr = MPI_File_get_size(ent_MPI_PI, &filesize); /* in bytes */
            if(ierr)
               { cout << "\n erreur en appel de MPI_File_get_size pour le fichier " << nom_PI
                      << "\n proc: " << num_cpu_en_cours_BI
                      << "\n le fichier de pointeur ne peut etre lu, arret "
                      << "\n UtilLecture::Ouverture_base_info() " << endl;
                 Sortie(1);
               };
            MPI_Offset taille_fichier_enOctet = filesize;
            char * buffer_car = new char [taille_fichier_enOctet] ; // def du tableau de travail
            MPI_Status status;
            ierr = MPI_File_read(ent_MPI_PI, buffer_car, taille_fichier_enOctet, MPI_CHAR, &status);
            if(ierr)
               { cout << "\n erreur en appel de MPI_File_read pour le fichier " << nom_PI
                      << "\n proc: " << num_cpu_en_cours_BI
                      << "\n le fichier de pointeur ne peut etre lu, arret "
                      << endl;
                 Sortie(1);
               };
            // on crée un flux sur le tableau de caractères: ----> on redéfinit ent_PI en local
            istrstream * ent_PI = new istrstream(buffer_car,taille_fichier_enOctet) ;
     #endif
            // on lit les positions
            // et on récupère les pointeurs d'incrément
            string toto;int nb_position;
            // on lit la première ligne
            (*ent_PI) >> toto >> nb_position;
            // dans le cas ou il n'y a pas d'erreur
            // on effectue la lecture des positions si seulement
            // le nombre de position actuellement en service est différent
            if (ent_PI->rdstate() == 0)
             {// si le nombre de position actuelle est non valide, on lit
              if (liste_posi_BI.size() != nb_position)
               {  // on efface les positions actuelles
                  liste_posi_BI.clear();
                  // lecture des positions
                  for (int i=1;i<= nb_position;i++)
                   { Position_BI truc;
                     (*ent_PI) >> truc;
                     liste_posi_BI.push_back(truc);
                   };
               };
               positionPI = true;
             };
     #ifndef UTILISATION_MPI
          };
      }

     #else
//     #ifdef UTILISATION_MPI
           }
         else
           {  cout << "\n *** erreur, le pointeur de fichier  .PI == MPI_FILE_NULL "
                           << " \n arret  "
                           << "\n UtilLecture::Ouverture_base_info() " << endl;
              Sortie(1);
           };
       }; // fin du test if(num_cpu_en_cours_BI == 0)
      // on transmet positionPI à tous les proc i
      broadcast(*ParaGlob::Monde(), positionPI, 0);
     #endif
      // si les positions n'ont pas été validé, on essaie de les recréer
      if (!positionPI)
       // le fichier de pointeur n'est pas exploitable
       // on redéfinit par lecture le tableau de pointeur à partir du .BI
       {  cout << "\n attention, le fichier de pointeur .PI n'est pas exploitable "
               << " \n on va donc essayer de retrouver les positions des increments "
               << " dans .BI mais ce sera plus long !! " << endl;
     #ifndef UTILISATION_MPI
          if (ent_PI != NULL) {ent_PI->close();ent_PI = NULL;};
          streampos debut_increment(0);
     #else
          if(num_cpu_en_cours_BI == 0)
           // seule le proc 0 gère le fichier PI
           {if (ent_MPI_PI != MPI_FILE_NULL)
             {MPI_File_close(&ent_MPI_PI);};
           }
          // pour tous les proc on met la variable de fichier à NULL
          // ce qui est utile pour les tests à suivre
          ent_MPI_PI = MPI_FILE_NULL;
          MPI_Offset debut_increment(0);
     #endif
          // on efface les positions actuelles
          liste_posi_BI.clear();
          // on se positionne au premier incrément et si c'est ok on continue
          int incre = 0;
          dernier_increment_lu = -1; // rien n'a été lue pour l'instant
          if (Positionnement_base_info(incre))
           { // enregistrement et bouclage
             Position_BI truc(debut_increment,incre);
             liste_posi_BI.push_back(truc);
             while (Increment_suivant_base_info(debut_increment,incre))
                { // dans la fonction il y a l'enregistrement dans la liste
                  // d'où on ne fait rien ici
                };
           };
          // maintenant on se repositionne au début du fichier pour le BI
     #ifndef UTILISATION_MPI
          ent_BI->clear();
          ent_BI->seekg(ios::beg);
     #else
          MPI_File_seek(ent_MPI_BI, 0, MPI_SEEK_SET);
     #endif
          dernier_increment_lu = 0;
     #ifndef UTILISATION_MPI
          {// on va enregistrer les positions pour éviter de refaire la manip à chaque fois
           // nb: on est dans le cas où le .PI n'existe pas
           sort_PI = new fstream(nom_PI.c_str(), ios::out ); // on crée le fichier
           if(!(sort_PI->is_open()))
           //  le fichier ne peut être ouvert, message d'erreur
             {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_PI << "\n"
                     << " UtilLecture::Ouverture_base_info() " << endl;
                Sortie(1);
             };

           list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
           (*sort_PI) << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: "
                      << liste_posi_BI.size() << "\n";
           for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
             (*sort_PI) << (*iter) << "\n";
           (*sort_PI) << endl;
           sort_PI->close();sort_PI=NULL;
          };
     #else
          {// arrivé ici on doit avoir un sort_MPI_PI == MPI_FILE_NULL
           if (sort_MPI_PI != MPI_FILE_NULL)
             {  cout << "\n **** erreur en gestion du fichier " << nom_PI
                     << " sort_MPI_PI est deja different de MPI_FILE_NULL, ce n'est pas normal \n"
                     << " UtilLecture::Ouverture_base_info() " << endl;
                Sortie(1);
             };
           if (num_cpu_en_cours_BI == 0)
             {int ierr_ouverture_PI = MPI_File_open(MPI_COMM_SELF,nom_PI.c_str(),MPI_MODE_RDWR, MPI_INFO_NULL, &sort_MPI_PI);
              if(ierr_ouverture_PI)
                  //  le fichier ne peut être ouvert, message d'erreur
                   {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_PI << "\n"
                           << " UtilLecture::Ouverture_base_info() " << endl;
                      Sortie(1);
                   };
              // on sort les positions
              // on crée un flux intermédiaire pour stocker dans un buffer les infos
              std::ostringstream buf2(std::ios_base::out);
              buf2 << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: "
                   << liste_posi_BI.size() << "\n";
              list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
              int i=0;
              for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++,i++)
                 buf2 << (*iter) << "\n";
              buf2 << endl;
              // le buffer du stream n'est pas pérenne il faut le récupérer
              string buf_inter = buf2.str(); // on récupère le buffer
              MPI_Offset  taille_buf = buf_inter.size();
              MPI_Status status; // pour le retour
              if (num_cpu_en_cours_BI == 0)
                {int ierr = MPI_File_write(sort_MPI_PI,buf_inter.c_str(),taille_buf,MPI_CHAR,&status);
                  if(ierr)
                    { cout << "\n erreur en appel de MPI_File_write pour le fichier " << nom_PI
                           << "\n proc: " << num_cpu_en_cours_BI
                           << "\n le fichier de pointeur ne peut etre ecrit, arret "
                           << endl;
                      Sortie(1);
                    };
                };
              MPI_File_close(&sort_MPI_PI);
              sort_MPI_PI=MPI_FILE_NULL;
             };
          }
     #endif
       }; // fin du test if (!positionPI)
     #ifdef UTILISATION_MPI
      // on doit transmettre liste_posi_BI à tous les proc
      std::vector < Position_BI > inter; // sert pour le transfert interproc
      if (num_cpu_en_cours_BI == 0) // on rempli inter
       {inter.resize(liste_posi_BI.size());
        list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
        int i=0;
        for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++,i++)
           {inter[i].num_incr = (*iter).num_incr;
            inter[i].position = (*iter).position;
           };
       };
      // il faut transmettre à tous les proc le contenu de liste_posi_BI
      broadcast(*ParaGlob::Monde(), inter, 0);
      if (num_cpu_en_cours_BI != 0)
       // on rempli liste_posi_BI pour tous les proc i != 0
       {liste_posi_BI.clear();
           int taille = inter.size();
           for (int i=0;i<taille;i++)
            {Position_BI truc(inter[i].position,inter[i].num_incr);
             liste_posi_BI.push_back(truc);
            };
       };
     #endif
    }
    else if (type_entree == "ecriture")
      // cas d'une ecriture
      // on regarde si on a déjà une ouverture en lecture si oui on ferme
    {
     #ifndef UTILISATION_MPI
       if (ent_BI != NULL)
     #else
       lecture_MPI_BI_en_cours = 0; // on ne peut plus utiliser Nouvelle_enreg_MPI_BI
       if (ent_MPI_BI != MPI_FILE_NULL)
     #endif
          Fermeture_base_info();
          
      // maintenant on regarde si l'écriture est déjà en cours si oui on ne fait rien
      // sinon on ouvre et on se place à la fin
     #ifndef UTILISATION_MPI
      if (sort_BI == NULL)
       { sort_BI = new fstream(nom_BI.c_str(), ios::out | ios::in | ios::ate);
         if(!(sort_BI->is_open()))
          //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre
          { sort_BI = new fstream(nom_BI.c_str(), ios::out  | ios::ate);
            if(!(sort_BI->is_open()))
             //  le fichier ne peut être ouvert, message d'erreur
             {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_BI << "\n"
                  << " UtilLecture::Ouverture_base_info() " << endl;
                Sortie(1);
             }
          };
       };
     #else
      if (sort_MPI_BI == MPI_FILE_NULL)
       {
//// essai
//            int  rank, nprocs, nints, bufsize,count; MPI_File fh; MPI_Status status;
//            MPI_File   truc ; //  "  "
//            sort_MPI_BI = &truc;
//
//            char *buf;
//  //          MPI_Init(&argc, &argv);
//  int FILESIZE = 24;
//            MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &nprocs); bufsize = 24;
//            nints =bufsize/sizeof(int);
//            buf = (char*) malloc(bufsize);
//            MPI_File_open(MPI_COMM_WORLD, nom_BI.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL,&fh);
//  //          MPI_File_seek(fh, 2,MPI_SEEK_SET);
//            MPI_File_read(fh, buf, bufsize, MPI_CHAR, &status);
//            MPI_Get_count(&status, MPI_CHAR, &count);
//            printf("process %d read %d ints\n", ParaGlob::Monde()->rank(), count);
//            MPI_File_close(&fh);
//// fin essai
       
         int ierr_ouverture_BI = MPI_File_open((*ParaGlob::Monde()),nom_BI.c_str(),   MPI_MODE_CREATE | MPI_MODE_RDWR , MPI_INFO_NULL, &sort_MPI_BI);
         if((ierr_ouverture_BI) && (num_cpu_en_cours_BI == 0))
             //  le fichier ne peut être ouvert, message d'erreur
             {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_BI << "\n"
                     << " UtilLecture::Ouverture_base_info() " << endl;
                Sortie(1);
             };
       };
     #endif

      // === même traitement pour le fichier de pointeur d'incrément ===
      // qui est cependant systématiquement mis à 0, on écrit du début
     #ifndef UTILISATION_MPI
      sort_PI = new fstream(nom_PI.c_str(), ios::out | ios::in);
      if(!(sort_PI->is_open()))
         //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
         { sort_PI = new fstream(nom_PI.c_str(), ios::out  | ios::ate);
           if(!(sort_PI->is_open())) 
            //  le fichier ne peut être ouvert, message d'erreur
            {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_PI << "\n"
                 << " UtilLecture::Ouverture_base_info() " << endl;
               Sortie(1);
            };
         };
     #else
       // en MPI seule le proc 0 s'occupe du .PI car c'est lui qui transmettra les offsets finaux aux proc i
       // MPI_COMM_SELF pour dire qu'il s'agit du communicator uniquement relié au proc en cours, ici 0
       if(num_cpu_en_cours_BI == 0)
         { int ierr_ouverture_PI = MPI_File_open(MPI_COMM_SELF,nom_PI.c_str(),MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &sort_MPI_PI);
             if(ierr_ouverture_PI)
                { ent_MPI_PI = MPI_FILE_NULL;
                  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_PI << "\n"
                       << " UtilLecture::Ouverture_base_info() " << endl;
                  Sortie(1);
                };
        };
     #endif

         
    }; // fin du cas de l'écriture
    
  };

// fermeture du fichier base_info 
void UtilLecture::Fermeture_base_info()
  {
  #ifndef UTILISATION_MPI
    if (ent_BI != NULL)
      {// cas du fichier ouvert en lecture
       delete ent_BI;
       ent_BI = NULL;
       if(ent_PI != NULL) delete ent_PI;
       ent_PI = NULL;
      };
    if (sort_BI != NULL)
      {// cas du fichier ouvert en écriture
       delete sort_BI;
       sort_BI = NULL;
       // on sauvegarde le tableau de pointeur d'incrément
       if (sort_PI != NULL)
         {sort_PI->seekp( ios::beg);
          list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
          (*sort_PI) << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: "
                     << liste_posi_BI.size() << "\n";
          for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
             (*sort_PI) << (*iter) << "\n";
          (*sort_PI) << endl;
          // puisque le fichier base_info est fermé, on suprime la liste de pointeur
          // elle sera remise à jour lors de l'ouverture du .BI
          list<Position_BI>::iterator iter_debut = liste_posi_BI.begin();
          liste_posi_BI.erase(iter_debut,iter_fin);
          // fermeture du fichier
          delete sort_PI;
          sort_PI = NULL;
         };
      };
  #else
    lecture_MPI_BI_en_cours = 0; // on ne peut plus utiliser Nouvelle_enreg_MPI_BI
    int proc_en_cours = ParaGlob::Monde()->rank();
    int indic_ent_MPI_BI = 0; // pour le broadcast
    int indic_ent_MPI_PI = 0; //    ""
    ParaGlob::Monde()->barrier(); // on synchronise tous les proc

    if (ent_MPI_BI != MPI_FILE_NULL)
       { // cas du fichier ouvert en lecture
         MPI_File_close(&ent_MPI_BI);
         ent_MPI_BI=MPI_FILE_NULL;indic_ent_MPI_BI = 1;
         if (proc_en_cours==0)
            MPI_File_close(&ent_MPI_PI);
         ent_MPI_PI=MPI_FILE_NULL;indic_ent_MPI_PI = 1;
       };
    if (sort_MPI_BI != MPI_FILE_NULL)
      {// cas du fichier ouvert en écriture
       MPI_File_close(&sort_MPI_BI);
       sort_MPI_BI=MPI_FILE_NULL;indic_ent_MPI_BI = 1;
       
       // on sauvegarde le tableau de pointeur d'incrément
       if (proc_en_cours == 0)
        { MPI_File_seek(sort_MPI_PI, 0, MPI_SEEK_SET);
       
          // on crée un flux intermédiaire pour stocker dans un buffer les infos
          std::ostringstream buf2(std::ios_base::out);
          buf2 << "liste_des_positions_et_de_pointeur_dans_base_info,_taille_: "
                     << liste_posi_BI.size() << "\n";
          list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
          for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
             buf2 << (*iter) << "\n";
          buf2 << endl;
          // le buffer du stream n'est pas pérenne il faut le récupérer
          string buf_inter = buf2.str(); // on récupère le buffer
          MPI_Offset taille_buf = buf_inter.size();
          MPI_Status status; // pour le retour
          
          int ierr = MPI_File_write(sort_MPI_PI,buf_inter.c_str(),taille_buf,MPI_CHAR,&status);
          if (ierr)
            {cout << "\n *** erreur d'acces a MPI_File_write , stop Herezh "
                  << "\n UtilLecture::Fermeture_base_info()" << endl;
             Sortie(1);
            };
         };
       // fermeture du fichier
       if (proc_en_cours==0)
           MPI_File_close(&sort_MPI_PI);
       indic_ent_MPI_PI = 1;
       sort_MPI_PI=MPI_FILE_NULL;
     };
    // le broadcast sur un fichier mpi ne fonctionne pas car a priori non supporté comme structure
    broadcast(*ParaGlob::Monde(), indic_ent_MPI_BI, 0);
    if (indic_ent_MPI_BI)
      ent_MPI_BI =  MPI_FILE_NULL;
    broadcast(*ParaGlob::Monde(), indic_ent_MPI_PI, 0);
    if (indic_ent_MPI_PI)
      ent_MPI_PI =  MPI_FILE_NULL;

  #endif
   
   };
        
//fichier base_info dans lequel sont lus les enregistrements
#ifndef UTILISATION_MPI
 ifstream * UtilLecture::Ent_BI()
  { if (ent_BI == NULL)
#else
 MPI_File * UtilLecture::Ent_BI() // cas MPI
  { if (ent_MPI_BI == MPI_FILE_NULL)
#endif
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_base_info("lecture");
     }
#ifndef UTILISATION_MPI
    return (ifstream*) ent_BI;
#else
    return &ent_MPI_BI;
#endif
   };
   
// et pour l'écriture
#ifndef UTILISATION_MPI
 ofstream * UtilLecture::Sort_BI()
   { if (sort_BI == NULL)
#else
 MPI_File * UtilLecture::Sort_BI()
   { if (sort_MPI_BI == MPI_FILE_NULL)
#endif
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_base_info("ecriture");
     }
#ifndef UTILISATION_MPI
     return (ofstream*) sort_BI;
#else
     return &sort_MPI_BI;
#endif
     } ;
     
// positionnement dans le fichier d'entrès au niveau d'un numéro d'incrément
// si l'on ne trouve pas le numéro on renvoi un indicateur à false
bool UtilLecture::Positionnement_base_info(int inc_voulu)
  {
     // tout d'abord on vérifie que le fichier base_info est disponible en lecture
     // sinon on l'ouvre en lecture
  #ifndef UTILISATION_MPI
     streampos debut_increment(0);
     if (ent_BI == NULL)
  #else
     MPI_Offset debut_increment(0);
     if (ent_MPI_BI == MPI_FILE_NULL)
  #endif
       Ouverture_base_info("lecture");
      
// --- on ne fait pas une recherche en boucle, comme commencé dans les lignes commentées qui suivent
// car on considère que la liste BI doit exister et contenir les info ha doc
//     // on regarde si l'on est au début du fichier sinon dans le cas d'une recherche
//     // infructueuse à la fin il faudra aussi faire une recherche au début
//     bool debut = true;
//     if (std::ios::beg != ( ent_BI->tellg())) debut = false;

     bool retour = false; // init par défaut
     // on regarde si l'incrément demandé n'a pas déjà été enregistré
  #ifndef UTILISATION_MPI
     Position_BI pos_ent(ios::beg,inc_voulu);
     if ((liste_posi_BI.size() == 0) && (inc_voulu == 0))
       // cas très particulier : pas de liste existante et on veut démarrer
       { ent_BI->clear(); // on remet à 0 les bits de contrôle car si lors d'une précédente lecture
                         // on est par exemple arrivée à la fin du fichier, la fonction seekg ne fonctionnera
                         // pas !! car le bit de eof est activé
         ent_BI->seekg(0, ios::beg); // on se place au début du fichier
         int inc_lu=0; // init
         streampos debut_increment(ios::beg);
         bool succes = Increment_suivant_base_info(debut_increment,inc_lu);
         if (!succes)
          // on n'a pas réussi à se positionner au début.. on ne peut pas aller plus loin !
          {  cout << "\n *** erreur, on n'a pas reussi a se positionner a l'increment 0 "
                  << " \n arret  "
                  << "\n UtilLecture::Positionnement_base_info(0) " << endl;
             Sortie(1);
          };
       };

  #else
     Position_BI pos_ent(debut_increment,inc_voulu);
     // dans le cas où ((liste_posi_BI.size() == 0) && (inc_voulu == 0))
     // il faut reconstruire la liste, dans ce cas on utilise la version mono proc
  #endif
  
     list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
     if (iposi != liste_posi_BI.end())
  #ifndef UTILISATION_MPI
        // dans le cas ou l'incrément existe, on se positionne à l'adresse mémorisée
        { ent_BI->clear(); // on remet à 0 les bits de contrôle car si lors d'une précédente lecture
                          // on est par exemple arrivée à la fin du fichier, la fonction seekg ne fonctionnera
                          // pas !! car le bit de eof est activé 
          ent_BI->seekg((*iposi).position, ios::beg);
          // maintenant on lit
          string toto; int titi; int inc; bool inc_trouve = false;
          // def d'un tableau d'entrée en flot d'entrée pour faire de la lecture non formaté
          char * tableau; int longueur =  250;
          tableau = new char [longueur] ; // def du tableau intermediaire
          istrstream * intar;
          // on définit une position intermédiaire dans le fichier pour bien se positionner
          // pour l'écriture ensuite éventuelle des incréments
          streampos position_inter=0;
          // lecture tant que l'on n'a pas atteint la fin du fichier
          do
            { // tout d'abord on mémorise l'ancienne position et on récupère la nouvelle
              debut_increment = position_inter;
              position_inter = ent_BI->tellg();
              // si la ligne est la bonne debut_increment sera positionné sur le début
              // de la ligne qui contiend des ====
                   
              ent_BI->getline(tableau,longueur,'\n'); // lecture d'une ligne dans le fichier
              if (strstr(tableau,"INCREMENT_DE_CHARGE_:")!=NULL)
                { // on repositionne le flot au debut du tableau de carractere
                  // ouverture du flot a la longueur sans blanc
                  intar = new istrstream(tableau,short(strlen (tableau))) ;
                  (*intar) >> toto >> inc;
                  if (inc == inc_voulu)
                    // ok on a l'incrément voulu
                    // fin de la préparation de la lecture pour l'incrément
                    {(*intar)  >> toto >> titi
                               >> toto ;
                      inc_trouve = true;
                     }
                   delete intar;
                  }
               // test pour vérifier l'intégrité du flot
               if (ent_BI->rdstate() != 0)
                 // si l'on est arrivé  à la fin du fichier il n'y a rien à faire
                 // sinon on remet à flot le flot (cas par exemple d'entier au lieu de caractère)!
                 if (!(ent_BI->eof()))
                     ent_BI->clear();
              }
              while ((!(ent_BI->eof()))&& (!inc_trouve));
            delete[] tableau;
           
         if (!inc_trouve)
             retour = false;
         else
           { // on passe la ligne des ===
             (*ent_BI) >> toto;
             // on met à jour la variable dernier_increment_lu
             dernier_increment_lu = inc_voulu;
             retour = true;
           };

        };
  #else
        {// on se positionne à l'offset voulu
// non          // on considère l'opération collective
//         cout << "\n debug UtilLecture::Positionnement_base_info( : (*iposi).position= "<<(*iposi).position<<endl;
//         int ierr = MPI_File_seek_shared(ent_MPI_BI, (*iposi).position, MPI_SEEK_SET);
         int ierr = MPI_File_seek(ent_MPI_BI, (*iposi).position, MPI_SEEK_SET);
         if (ierr)
           {cout << "\n *** erreur d'acces a MPI_File_seek , stop Herezh "
                 << "\n UtilLecture::Positionnement_base_info(...";
            Sortie(1);
           };
         // on récupère une ligne dans .BI
         string buf_ligne;
         string indic_string("INCREMENT_DE_CHARGE_:");
         string toto;int inc; bool inc_trouve = false;
         bool pas_fin_fichier = false; // init

         // lecture tant que l'on n'a pas atteint la fin du fichier
         MPI_Offset posi_suivant=0;
         do
           { // lecture d'une ligne dans le fichier
             pas_fin_fichier = Nouvelle_enreg_MPI_BI(&ent_MPI_BI,buf_ligne,false,posi_suivant);
             std::size_t found = buf_ligne.find(indic_string);
             if (found!=std::string::npos)
               { // on a trouvé l'indicateur "INCREMENT_DE_CHARGE_:"
                 // on lit l'incrément
                 std::istringstream inbuf(buf_ligne);
                 inbuf >> toto >> inc;
                 if (inc == inc_voulu)
                   // ok on a l'incrément voulu
                   // fin de la préparation de la lecture pour l'incrément
                   inc_trouve = true;
                 }

             } while (pas_fin_fichier && (!inc_trouve));
             
         if (!inc_trouve)
             retour = false;
         else
           { // on passe la ligne des ===
             pas_fin_fichier = Nouvelle_enreg_MPI_BI(&ent_MPI_BI,buf_ligne,false,posi_suivant);
             // on met à jour la variable dernier_increment_lu
             dernier_increment_lu = inc_voulu;
             // on repositionne le pointeur de fichier
             ierr = MPI_File_seek(ent_MPI_BI, posi_suivant, MPI_SEEK_SET);
             if (ierr)
              {cout << "\n *** erreur2 d'acces a MPI_File_seek , stop Herezh "
                    << "\n UtilLecture::Positionnement_base_info(...";
               Sortie(1);
              };

             retour = true;
           };
        };
//  //--- debug
//            { char * buffer_car = new char [34] ; // def du tableau de travail
//              for (int i=0;i<34;i++)
//                buffer_car[i]='\0';
//              MPI_Status status;
//              MPI_File_read(ent_MPI_BI, buffer_car, 34, MPI_CHAR, &status);
//              cout << "\n debug UtilLecture::Positionnement_base_info( :"
//                   << "\n buffer_car= ";
//              for (int i=0;i<34;i++)
//                   cout <<  buffer_car[i];
//              cout  <<  endl;
//            }
//  //--- fin debug
  #endif
  
    // retour unique
    return retour;

};

     // retour de l'offset du début de l'incrément s'il existe
     // retour d'un nombre négatif s'il n'existe pas
#ifndef UTILISATION_MPI
 streampos  UtilLecture::OffsetPosition(int inc_voulu)
   { streampos retour=-1; // init par défaut
     Position_BI pos_ent(ios::beg,inc_voulu);
     list <Position_BI>::iterator iposi
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
     if (iposi != liste_posi_BI.end())
       retour = (*iposi).position;
     // retour
     return retour;
   };
#else
 MPI_Offset  UtilLecture::OffsetPosition(int inc_voulu)
   {  streampos retour=-1; // init par défaut
      if (inc_voulu == 0)
        {retour = ParaGlob::param->Taille_buffer_sortie_BI(); }
      else
       {streampos debut_increment(0);
        Position_BI pos_ent(debut_increment,inc_voulu);
        list <Position_BI>::iterator iposi
                  = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
        if (iposi != liste_posi_BI.end())
           retour = (*iposi).position;
       };
      // retour
      return retour;
   };
#endif

    
// positionnement dans le fichier d'entrès au niveau du numéro d'incrément suivant
// si l'on ne trouve pas de numéro on renvoi un indicateur à false
// la méthode renvoie également la position du début de l'incrément
// et le numéro trouvé d'incrément
#ifndef UTILISATION_MPI
  bool UtilLecture::Increment_suivant_base_info(streampos& debut_increment,int& inc_lu)
   { // tout d'abord on vérifie que le fichier base_info est disponible en lecture
     // sinon on l'ouvre en lecture
     if (ent_BI == NULL)
#else
  // il s'agit d'une méthode interne utilisée uniquement par la classe
  // et en MPI par proc 0, on fait donc des appels non collectifs à Nouvelle_enreg_MPI_BI
  bool UtilLecture::Increment_suivant_base_info(MPI_Offset& debut_increment,int& inc_lu)
   { // tout d'abord on vérifie que le fichier base_info est disponible en lecture
     // sinon on l'ouvre en lecture
     if (ent_MPI_BI == MPI_FILE_NULL)
#endif
       Ouverture_base_info("lecture");
     // on regarde si dans la liste des incréments enregistrés, la position du suivant 
     // s'il existe
     Position_BI pos_int(ios::beg,dernier_increment_lu);
     list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_int);
     // iposi représente la position du dernier incrément enregistré
     
   #ifndef UTILISATION_MPI
     if (iposi != liste_posi_BI.end())
      // cas ou l'incrément existe, on prend le suivant
      {list <Position_BI>::iterator iposa = iposi; // sauvegarde
       iposi++;
       // on vérifie qu'il existe et dans ce cas on se positionne correctement
       if (iposi != liste_posi_BI.end())
          {ent_BI->seekg((*iposi).position, ios::beg);}
       else
          // sinon on se met à la dernière position lue
          {ent_BI->seekg((*iposa).position, ios::beg);};
       }
     else
       // si c'était le dernier enregistré on se met à la dernière position
       // au cas ou le fichier de pointeur n'est pas complet
       {if (dernier_increment_lu != -1)
         {  ent_BI->seekg(pos_int.position, ios::beg);}
        else // cas particulier de démarrage avec le fichier .PI qui pose pb, par exemple qui n'existait pas
             // on se place au tout début
         {  ent_BI->seekg(0, ios::beg);
         };
       }
   #else
     int ierr;
     if (iposi != liste_posi_BI.end())
      // cas ou l'incrément existe, on prend le suivant
      {list <Position_BI>::iterator iposa = iposi; // sauvegarde
       iposi++;
       // on vérifie qu'il existe et dans ce cas on se positionne correctement
       if (iposi != liste_posi_BI.end())
          ierr = MPI_File_seek(ent_MPI_BI, (*iposi).position, MPI_SEEK_SET);
       else
          // sinon on se met à la dernière position lue
          ierr = MPI_File_seek(ent_MPI_BI, (*iposa).position, MPI_SEEK_SET);
       }
     else
       // si c'était le dernier enregistré on se met à la dernière position
       // au cas ou le fichier de pointeur n'est pas complet
       {ierr = MPI_File_seek(ent_MPI_BI, pos_int.position, MPI_SEEK_SET);};
     if (ierr)
         {cout << "\n *** erreur d'acces a MPI_File_seek , stop Herezh "
               << "\n UtilLecture::Increment_suivant_base_info(..." << endl;
          Sortie(1);
         };

   #endif


     bool retour = false; // init par défaut
     // maintenant on lit
   #ifndef UTILISATION_MPI
     string toto;   bool inc_trouve = false;
     // def d'un tableau d'entrée en flot d'entrée pour faire de la lecture non formaté
     char * tableau; int longueur =  250;
     tableau = new char [longueur] ; // def du tableau intermediaire
     istrstream * intar;
     // on définit une position intermédiaire dans le fichier pour bien se positionner 
     // pour l'écriture ensuite éventuelle des incréments
     streampos position_inter=0;        
     // lecture tant que l'on n'a pas atteint la fin du fichier
     do
       { // tout d'abord on mémorise l'ancienne position et on récupère la nouvelle
         debut_increment = position_inter;
         position_inter = ent_BI->tellg();
         // si la ligne est la bonne debut_increment sera positionné sur le début
         // de la ligne qui contiend des ====
              
         ent_BI->getline(tableau,longueur,'\n'); // lecture d'une ligne dans le fichier
         if (strstr(tableau,"INCREMENT_DE_CHARGE_:")!=NULL)
           { // on repositionne le flot au debut du tableau de carractere  
             // ouverture du flot a la longueur sans blanc
             intar = new istrstream(tableau,short(strlen (tableau))) ;
             (*intar) >> toto >> inc_lu;
             // le nouvel incrément n'est valide que s'il est différent de l'ancien
             if (inc_lu != dernier_increment_lu)
               inc_trouve = true;
             delete intar;  
             }
          // test pour vérifier l'intégrité du flot
          if (ent_BI->rdstate() != 0)
            // si l'on est arrivé  à la fin du fichier il n'y a rien à faire
            // sinon on remet à flot le flot (cas par exemple d'entier au lieu de caractère)!
            if (!(ent_BI->eof()))
                ent_BI->clear();
         }                 
         while ((!(ent_BI->eof()))&& (!inc_trouve));
     delete[] tableau;
     // dans le cas où on n'a pas trouvé de bon incrément       
	    if (!inc_trouve)
	       { inc_lu = -1;
	         retour= false;
	        } 
	    else
	     { // on passe la ligne des ===
	       (*ent_BI) >> toto;
      };
   #else
     // préparation
     string buf_ligne;
     string indic_string("INCREMENT_DE_CHARGE_:");
     string toto; bool inc_trouve = false;
     bool pas_fin_fichier = false; // init
     // on définit une position intermédiaire dans le fichier pour bien se positionner
     // pour l'écriture ensuite éventuelle des incréments
     MPI_Offset posi_suivant=0;
     MPI_Offset position_inter=0;
     ierr = MPI_File_get_position(ent_MPI_BI, &position_inter);
     if (ierr)
       {cout << "\n *** erreur d'acces a MPI_File_get_position , stop Herezh "
             << "\n UtilLecture::Enregistrement_position_increment_base_info(..." << endl;
        Sortie(1);
       };
     // lecture tant que l'on n'a pas atteint la fin du fichier
     do
       { // tout d'abord on mémorise l'ancienne position et on récupère la nouvelle
         debut_increment = position_inter;
         ierr = MPI_File_get_position(ent_MPI_BI, &position_inter);
         if (ierr)
           {cout << "\n *** erreur d'acces a MPI_File_get_position , stop Herezh "
                 << "\n UtilLecture::Enregistrement_position_increment_base_info(..." << endl;
            Sortie(1);
           };
         // lecture d'une ligne dans le fichier
         pas_fin_fichier = Nouvelle_enreg_MPI_BI(&ent_MPI_BI,buf_ligne,false,posi_suivant);
         std::size_t found = buf_ligne.find(indic_string);
         if (found!=std::string::npos)
           { // on a trouvé l'indicateur "INCREMENT_DE_CHARGE_:"
             // cela veut dire que position_inter est l'offset de la ligne précédente
             // de ==== donc c'est l'offset habituel de l'incrément
             // on lit l'incrément
             std::istringstream inbuf(buf_ligne);
             inbuf >> toto >> inc_lu;
             // le nouvel incrément n'est valide que s'il est différent de l'ancien
             if (inc_lu != dernier_increment_lu)
               // ok on a récupéré un début d'incrément
               inc_trouve = true;
             }
       } while (pas_fin_fichier && (!inc_trouve));

     if (!inc_trouve)
         retour = false;
     else
       { // on passe la ligne des ===
         pas_fin_fichier = Nouvelle_enreg_MPI_BI(&ent_MPI_BI,buf_ligne,false,posi_suivant);
         // il faut repositionner le pointeur de fichier, car avec Nouvelle_enreg_MPI_BI
         // on utilise un gros buffer inter, qui fait que le pointeur en cours n'est pas du tout situé
         // après les ===
         ierr = MPI_File_seek(ent_MPI_BI, posi_suivant, MPI_SEEK_SET);
         if (ierr)
          {cout << "\n *** erreu2 d'acces a MPI_File_seek , stop Herezh "
                << "\n UtilLecture::Enregistrement_position_increment_base_info(...";
           Sortie(1);
          };
       };
   #endif
      
     if (inc_trouve)
      { // on enregistre la position dans la liste de position
        // on regarde si l'incrément demandé n'a pas déjà été enregistré
        Position_BI pos_ent(debut_increment,inc_lu);
        list <Position_BI>::iterator iposi_end = liste_posi_BI.end();
        list <Position_BI>::iterator iposi
            = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
        if (iposi == liste_posi_BI.end())
          {// le nouvel incrément n'existait pas mais
           // éventuellement le nouvel incrément peut-être intercalé entre des anciens
           // -- on ré-ordonne la liste, qui normalement ne doit avoir que des singletons
           liste_posi_BI.sort();
           iposi_end = liste_posi_BI.end(); // au cas où
           // -- on regarde si effectivement on est intercalé
           if ((* liste_posi_BI.begin() < (*iposi)  ) && ((*iposi) < (*iposi_end )))
            {// on recherche l'encadrement ad hoc
             list <Position_BI>::iterator ipopo;
             for (ipopo = liste_posi_BI.begin(); ipopo != iposi_end; ipopo++)
               if ((* ipopo) > (*iposi))
                 break;
             if (ipopo != liste_posi_BI.end())
              {// dans le cas où la position existe déjà on efface le reste de la liste
               // qui est maintenant inutile
               liste_posi_BI.erase(ipopo,liste_posi_BI.end());
              };
            };
           liste_posi_BI.push_back(pos_ent);
          };
        // on met à jour la variable dernier_increment_lu
        dernier_increment_lu = inc_lu;
        // retour
        retour = true;
      };
      
     // retour unique
     return retour;
};
    
// enregistrement de la position 
// normalement correspond à un début d'incrément
void UtilLecture::Enregistrement_position_increment_base_info(int incr)
 {
   // récup de la position
 #ifndef UTILISATION_MPI
   streampos position_inter=0;        
   position_inter = sort_BI->tellp();
 #else
   MPI_Offset position_inter=0;
   int ierr = MPI_File_get_position(sort_MPI_BI, &position_inter);
   if (ierr)
     {cout << "\n *** erreur d'acces a MPI_File_get_position , stop Herezh "
           << "\n UtilLecture::Enregistrement_position_increment_base_info(..." << endl;
      Sortie(1);
     };
 #endif
   // on enregistre la position dans la liste de position
   // on regarde si l'incrément demandé n'a pas déjà été enregistré
   Position_BI pos_ent(position_inter,incr);
   list <Position_BI>::iterator iposi 
               = find(liste_posi_BI.begin(),liste_posi_BI.end(),pos_ent);
   if (iposi != liste_posi_BI.end())            
     {// dans le cas où la position existe déjà on efface le reste de la liste
      // qui est maintenant inutile
      liste_posi_BI.erase(iposi,liste_posi_BI.end());
      };
   // on écrit la nouvelle position
   liste_posi_BI.push_back(pos_ent);
  };

// renvoi tous les incréments actuellements enregistré
list <int>  UtilLecture::Liste_increment()
  {  // création de la liste de retour
     list<int> list_incr;
     // on parcourt la liste des positions d'incréments
     // et on remplit la liste des numéros d'incréments
     list<Position_BI>::iterator iter,iter_fin = liste_posi_BI.end();
     for (iter =  liste_posi_BI.begin();iter != iter_fin;iter++)
          list_incr.push_back((*iter).num_incr);
     // retour
     return list_incr;
    };        

  // -------------- cas des temps de calcul ----------------
     // ouverture du fichier spécifique des temps cpu
void UtilLecture::Ouverture_fichier_temps_cpu()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort__temps_cpu != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    
    // on définit des noms explicites
    std::string nom_CPU(ptnomCVisu);
  #ifdef UTILISATION_MPI
    // cas d'un  calcul //,
    // on prend en compte le numéro du CPU
    int num_cpu = ParaGlob::Monde()->rank();
    nom_CPU += ChangeEntierSTring(num_cpu);
  #endif
    nom_CPU += "_temps.cpu";
    
    sort__temps_cpu = new ofstream(nom_CPU.c_str());
    if(!(sort__temps_cpu->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << nom_CPU << "\n"
             << " UtilLecture::Ouverture_fichier_temps_cpu() " << endl;
        Sortie(1);
     };
 };
     // fermeture du fichier des temps cpu
void UtilLecture::Fermeture_fichier_temps_cpu()
  { if (sort__temps_cpu != NULL)
      { delete(sort__temps_cpu);
        sort__temps_cpu = NULL;
      };
  };

  // -------------- cas de la visualisation ----------------
    //        +++ vrml ++++_____________________________________  
// ouverture du fichier principal vrml
void UtilLecture::Ouverture_fichier_principal_vrml()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_vrml != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_vrml = new ofstream(strcat(fileName,"_princ.wrl"));
    if(!(sort_princ_vrml->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_vrml() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal vrml
void UtilLecture::Fermeture_fichier_principal_vrml()
  { if (sort_princ_vrml != NULL) 
      { delete(sort_princ_vrml);
        sort_princ_vrml = NULL;
        }
    };    
// ouverture du fichier de légendes vrml
void UtilLecture::Ouverture_fichier_legende_vrml()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_legende_vrml != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_legende_vrml = new ofstream(strcat(fileName,"_legende.wrl"));
    if(!(sort_legende_vrml->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_legende_vrml() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier légendes vrml
void UtilLecture::Fermeture_fichier_legende_vrml()
  { if (sort_legende_vrml != NULL) 
      { delete(sort_legende_vrml);
        sort_legende_vrml = NULL;
        }
    };    
    //        +++ maple ++++ ____________________________________________
// ouverture du fichier maple
void UtilLecture::Ouverture_fichier_principal_maple()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_maple != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_maple = new ofstream(strcat(fileName,"_princ.maple"));
    if(!(sort_princ_maple->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_maple() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal maple
void UtilLecture::Fermeture_fichier_principal_maple()
  { if (sort_princ_maple != NULL) 
      { delete(sort_princ_maple);
        sort_princ_maple = NULL;
        }
    };    
    //        +++ geomview ++++_____________________________________  
// ouverture du fichier principal geomview
void UtilLecture::Ouverture_fichier_principal_geomview()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_princ_geomview != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_princ_geomview = new ofstream(strcat(fileName,"_princ.oogl"));
    if(!(sort_princ_geomview->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_principal_geomview() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier principal geomview
void UtilLecture::Fermeture_fichier_principal_geomview()
  { if (sort_princ_geomview != NULL) 
      { delete(sort_princ_geomview);
        sort_princ_geomview = NULL;
        }
    };    
// ouverture du fichier de légendes geomview
void UtilLecture::Ouverture_fichier_legende_geomview()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_legende_geomview != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_legende_geomview = new ofstream(strcat(fileName,"_legende.oogl"));
    if(!(sort_legende_geomview->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_legende_geomview() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier légendes geomview
void UtilLecture::Fermeture_fichier_legende_geomview()
  { if (sort_legende_geomview != NULL) 
      { delete(sort_legende_geomview);
        sort_legende_geomview = NULL;
        }
    }; 
       
    //        +++ Gid ++++_____________________________________  
// ouverture du fichier maillage initial Gid
void UtilLecture::Ouverture_fichier_initial_Gid()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_initial_Gid != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_initial_Gid = new ofstream(strcat(fileName,"_Gid.msh"));
    if(!(sort_initial_Gid->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_initial_Gid() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gid
void UtilLecture::Fermeture_fichier_initial_Gid()
  { if (sort_initial_Gid != NULL) 
      { delete(sort_initial_Gid);
        sort_initial_Gid = NULL;
        }
    };    
          
// ouverture du fichier maillage initial Gid
void UtilLecture::Ouverture_fichier_resultat_Gid()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_resultat_Gid != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_resultat_Gid = new ofstream(strcat(fileName,"_Gid.res"));
    if(!(sort_resultat_Gid->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_resultat_Gid() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gid
void UtilLecture::Fermeture_fichier_resultat_Gid()
  { if (sort_resultat_Gid != NULL) 
      { delete(sort_resultat_Gid);
        sort_resultat_Gid = NULL;
        }
    };    
          
       
    //        +++ Gmsh ++++_____________________________________  
// ouverture du fichier maillage initial Gmsh
void UtilLecture::Ouverture_fichier_initial_Gmsh()
 {  // si le fichier est déjà ouvert on ne fait rien
    if (sort_initial_Gmsh != NULL) return;
    // sinon on ouvre le fichier
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    sort_initial_Gmsh = new ofstream(strcat(fileName,"_Gmsh.msh"));
    if(!(sort_initial_Gmsh->is_open()))
      //  le fichier ne peut être ouvert, message d'erreur
     {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
             << " UtilLecture::Ouverture_fichier_initial_Gmsh() " << endl;
        Sortie(1);
      }
  };
// fermeture du fichier maillage initial Gmsh
void UtilLecture::Fermeture_fichier_initial_Gmsh()
  { if (sort_initial_Gmsh != NULL) 
      { delete(sort_initial_Gmsh);
        sort_initial_Gmsh = NULL;
        }
    };    
// création du répertoire contenant tous les fichiers résultats
void UtilLecture::CreationRepertoireResultat()
 {  // création du nom
    char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
//    system(strcat(fileName,"_Gmsh"));  // fonctionne mais on ne peut pas savoir
//     si le répertoire existe déjà, on utilise donc opendir (mais qui n'est pas 
//     présent partout !!
    DIR * ouvre_dir = opendir(strcat(fileName,"_Gmsh"));
    if(ouvre_dir == NULL)
     { // la première fois cela veut dire que le répertoire n'existe pas on le crée avec
       // un ordre système
      // int toto = mkdir(fileName, 775);
       char ordre[132];
       char* pordre  = ordre;
       strcpy(pordre, "mkdir ");strcat(pordre,fileName);
       system(pordre); 
       // et on retente une ouverture
       ouvre_dir = opendir(fileName);		
     };
    // maintenant s'il y a pb, c'est vraiment un pb
    if(ouvre_dir == NULL)
      //  le répertoire ne peut être créé, message d'erreur
     {  cout << "\n erreur en creation du repertoire  " << fileName << "\n"
             << " UtilLecture::CreationRepertoireResultat(.. " << endl;
        Sortie(1);
      }    
	};
          
// ouverture d'un fichier résultat Gmsh, comprenant un nom particulier
void UtilLecture::Ouverture_fichier_resultat_Gmsh(const string& nom)
 {   // on commence par voir si le fichier existe déjà
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier existe déjà on ne fait rien          
     if (ili == sort_resultat_Gmsh.end())
   	   {// --- cas où le fichier n'existe pas 
        // on construit le nom de fichier
        char nomm[132];
        char*fileName  = nomm;
        strcpy(fileName, ptnomCVisu);
        strcat(fileName,"_Gmsh/"); // là il contient la racine du répertoire
        strcat(fileName,ptnomCVisu); // on rajoute le début du nom du fichier
        strcat(fileName,"_"); // on rajoute un séparateur
        strcat(fileName,nom.c_str()); // on rajoute le nom passé en paramètre
        strcat(fileName,"_Gmsh.pos"); // ajout de la fin
        noms_base_fichiers_gmsh.push_back(nom);
        sort_resultat_Gmsh[nom] = new ofstream(fileName);
        if (ParaGlob::NiveauImpression()> 7)
          cout << "\n ouverture du fichier "<< fileName << endl;
        if(!(sort_resultat_Gmsh[nom]->is_open()))
          //  le fichier ne peut être ouvert, message d'erreur
          {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                  << " UtilLecture::Ouverture_fichier_resultat_Gmsh(list <string>) " << endl;
             Sortie(1);
          };
   	   };
  };
  
// ouverture d'un ensemble de fichiers: ces fichiers seront ensuite accessibles
void UtilLecture::Ouverture_fichier_resultat_Gmsh(const list <string>& t_nom)
{ // on va itérer sur les noms
  list <string>::const_iterator iti,itifin=t_nom.end();
  for (iti=t_nom.begin();iti != itifin; iti++)
   { const string & nom = (*iti); // pour simplifier
     // on commence par voir si le fichier existe déjà
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier existe déjà on ne fait rien          
     if (ili == sort_resultat_Gmsh.end())
   	   {// --- cas où le fichier n'existe pas 
        // on construit le nom de fichier
        char nomm[132];
        char*fileName  = nomm;
        strcpy(fileName, ptnomCVisu);
        strcat(fileName,"_Gmsh/"); // là il contient la racine du répertoire
        strcat(fileName,ptnomCVisu); // on rajoute le début du nom du fichier
        strcat(fileName,"_"); // on rajoute un séparateur
        strcat(fileName,nom.c_str()); // on rajoute le nom passé en paramètre
        strcat(fileName,"_Gmsh.pos"); // ajout de la fin
        noms_base_fichiers_gmsh.push_back(nom);
        sort_resultat_Gmsh[nom] = new ofstream(fileName);
        if (ParaGlob::NiveauImpression()> 7)
          cout << "\n ouverture du fichier "<< fileName << endl;
        if(!(sort_resultat_Gmsh[nom]->is_open()))
          //  le fichier ne peut être ouvert, message d'erreur
          {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                  << " UtilLecture::Ouverture_fichier_resultat_Gmsh(list <string>) " << endl;
             Sortie(1);
          };
   	   };
   }; 
};
  
// fermeture du fichier résultat Gmsh  
void UtilLecture::Fermeture_fichier_resultat_Gmsh(const string& nom)
  {  // on commence par voir si le fichier existe 
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier n'existe pas on ne fait rien
     // mais on sort un message          
     if (ili == sort_resultat_Gmsh.end())
  	  { cout << "\n erreur en fermeture du fichier relatif au nom " << nom 
  	         << " ce fichier n'existe pas ??? , on continue mais ...."
  	         << "\n UtilLecture::Fermeture_fichier_resultat_Gmsh(string nom)";
  	  }
  	 else// sinon fct normal 
      { delete(ili->second);
  	     sort_resultat_Gmsh.erase(ili);
        // suppression du nom de la liste
        noms_base_fichiers_gmsh.remove(nom);
      };
  }; 
     
// fermeture de tous les fichiers résultat
void UtilLecture::Fermeture_TousLesFichiersResultats_Gmsh()
  {  map < string, ofstream * , std::less <string> >::iterator ili,ilifin 
                     = sort_resultat_Gmsh.end();
     for (ili=sort_resultat_Gmsh.begin();ili != ilifin;ili++)
        { delete(ili->second);
         };
     sort_resultat_Gmsh.erase(sort_resultat_Gmsh.begin(),sort_resultat_Gmsh.end());
     noms_base_fichiers_gmsh.clear();
  };
  
// récupération d'un fichier résultats Gmsh
ofstream & UtilLecture::Sort_resultat_Gmsh(const string& nom)
  {  
   #ifdef MISE_AU_POINT
     // on commence par voir si le fichier existe 
     map < string, ofstream * , std::less <string> >::iterator ili 
                     = sort_resultat_Gmsh.find(nom);
     // dans le cas où le fichier n'existe pas on  sort un message          
     if (ili == sort_resultat_Gmsh.end())
  	  { cout << "\n erreur en recuperation du fichier relatif au nom " << nom 
  	         << " ce fichier n'existe pas ??? "
  	         << "\n UtilLecture::Sort_resultat_Gmsh(string nom)";
  	    Sortie(1);
  	    return *(sort_resultat_Gmsh[nom]); // pour faire taire le compilo     
  	  }
  	 else// sinon fct normal 
   #endif
      { return *(sort_resultat_Gmsh[nom]);
      };
  }; 
          
// ouverture du fichier CommandeVisu s'il est déjà ouvert on ne fait rien
// a priori le fichier est ouvert en lecture  : lecture
// mais il peut également être en écriture : ecriture
void UtilLecture::Ouverture_CommandeVisu(string type_entree)
  { char nomm[132];
    char*fileName  = nomm;
    strcpy(fileName, ptnomCVisu);
    if (type_entree == "lecture")
      // cas d'une lecture
      // on regarde si on a déjà une ouverture en écriture si oui on ferme
    { if (sort_CommandeVisu != NULL)
          Fermeture_CommandeVisu();
      // maintenant on regarde si la lecture est déjà en cours si oui on ne fait rien
      // si le flot est correcte, sinon on ouvre
      if (ent_CommandeVisu == NULL)
      { ent_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in);
        if(!(ent_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur en ouverture pour la lecture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
            throw (ErrNouvelleDonneeCVisu(0)); // erreur en ouverture fichier pour la lecture
            Sortie(1);
          }
       }
      else if ( ent_CommandeVisu->rdstate() != 0) // pb éventuelle on redémarre le flux     
       {Fermeture_CommandeVisu();       
        ent_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in);
        if(!(ent_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, message d'erreur
         {  cout << "\n erreur2 en ouverture pour la lecture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
            throw (ErrNouvelleDonneeCVisu(0)); // erreur en ouverture fichier pour la lecture
            Sortie(1);
          }
       }
      }
    else if (type_entree == "ecriture")
      // cas d'une ecriture
      // on regarde si on a déjà une ouverture en lecture si oui on ferme
    { if (ent_CommandeVisu != NULL)
          Fermeture_CommandeVisu();
      // maintenant on regarde si la lecture est déjà en cours si oui on ne fait rien
      // sinon on ouvre et on se place à la fin
      if (sort_CommandeVisu == NULL)
      { sort_CommandeVisu = new fstream(strcat(fileName,".CVisu"), ios::out | ios::in );
        if(!(sort_CommandeVisu->is_open()))
         //  le fichier ne peut être ouvert, il n'existe pas donc on l'ouvre 
         { sort_CommandeVisu = new fstream(fileName, ios::out  | ios::ate);
           if(!(sort_CommandeVisu->is_open())) 
            //  le fichier ne peut être ouvert, message d'erreur
            {  cout << "\n erreur en ouverture pour l'ecriture du fichier " << fileName << "\n"
                 << " UtilLecture::Ouverture_CommandeVisu() " << endl;
               throw (ErrNouvelleDonneeCVisu(10)); // erreur en ouverture fichier pour l'écriture
               Sortie(1);
            };      
         };
      };
    }; //-- fin du cas écriture
    
   };
          
// fermeture du fichier CommandeVisu 
void UtilLecture::Fermeture_CommandeVisu()
  { if (ent_CommandeVisu != NULL)
      {// cas du fichier ouvert en lecture
       delete ent_CommandeVisu;
       ent_CommandeVisu = NULL;
       }
    if (sort_CommandeVisu != NULL)
      {// cas du fichier ouvert en écriture
       delete sort_CommandeVisu;
       sort_CommandeVisu = NULL;
       }   
   };
   
// changement du nom de fichier .CVisu
// entraîne la fermeture du fichier en cours, en lecture et en écriture
// il n'y a pas de vérification à ce niveau d'existence éventuelle
// car on ne sait pas ce que l'on veut en faire
void UtilLecture::Changement_NomCVisu(string nouveauNomCvisu)
	{ // on commence par fermer le fichier en cours
	  Fermeture_CommandeVisu();
	  
	  // maintenant on regarde si la chaine passée en paramètre est non nulle
	  if (nouveauNomCvisu != "")
	    // on définit directement le nouveau nom
	  	{nomRacineCVisu = nouveauNomCvisu;}
	  else // sinon on passe en interactif
	  	{ cout << "\n entrez le nouveau nom:  ";
	      string nom;
	      nom= lect_chaine();
	      cout << " nom_lue: " << nom;
	      // dans le cas où ".CVisu" figure dans la racine, on supprime cette chaine
          int posi = nomRacine.find(".CVisu");
          if (posi != string::npos)
             { string nom_inter = nomRacine.substr(0,posi);
			   nom = nom_inter;
              };
          nomRacineCVisu = nom;
	  	};	
      // on met à jour le pointeur      
      ptnomCVisu = (char*)nomRacineCVisu.c_str(); 
	};
            
// lecture d'une nouvelle ligne de donnee utilisable pour l'entree de donnee
// dans le fichier de commande de visualisation (idem NouvelleDonnee mais en plus simple
// car il n'y a pas de fichier inclus) 
void UtilLecture::NouvelleDonneeCVisu()
   { // on lit jusqu'à la fin de fichier(boucle infini)
//     int boucle=0;
     try  
        { 
               Nouvel_enregCvisu (); // lecture d'un enreg ds le fichier courant
               // on repositionne le flot au debut du tableau de carractere  
               // ouverture du flot a la longueur sans blanc
               delete entCVisu;  
               #ifndef ENLINUX_STREAM
                   entCVisu = new istringstream(tablcarCVisu,strlen (tablcarCVisu)) ; 
               #else 
                   entCVisu = new istrstream(tablcarCVisu,(long)strlen (tablcarCVisu)) ;
               #endif    
              
          }    
     // sortie anormale du programme  
     catch (ErrNouvelEnregCVisu erreur)
         {  if ( erreur.lecture == 1) // on a atteind une fin de fichier
                    throw (ErrNouvelleDonneeCVisu(1)); 
            else
                   throw (ErrNouvelleDonneeCVisu(-1)); // erreur inconnue
         }    
  };
  
// recherche dans le fichier de commande la chaine de caractère passée en paramètre
// retour false: si on ne trouve pas la chaine
// retour true: si on la trouve, et dans ce cas le pointeur courant du fichier est 
//              positionné sur la ligne de la chaine
bool UtilLecture::PositionEtExisteCVisu(const string chaine)
 { // on ouvre le fichier en lecture si ce n'est pas fait
   try{
      Ouverture_CommandeVisu("lecture");
      // on commence par se positionner en début du fichier
      ent_CommandeVisu->seekg(ios::beg);   
      // on effectue la lecture jusqu'à trouver la chaine
      while (strstr(tablcarCVisu,chaine.c_str())==NULL)
          NouvelleDonneeCVisu();          
      // arrêt, on a trouvé la chaine et on est bien positionné
      return true; 
     }
   // sortie  de la lecture  hors du while
   catch (UtilLecture::ErrNouvelleDonneeCVisu erreur)
         {  if ( erreur.lecture != 1) 
              { // erreur en lecture
                cout << "\n **** ERREUR en lecture du fichier de  commande de visualisation "
                     << "\n on continue quand meme, mais il y aura peut-etre un probleme de coherence pour la suite";
                if (ParaGlob::NiveauImpression() >= 4)     
                  cout  << "\n UtilLecture::PositionEtExisteCVisu(..";
               }      
         }    
   catch (ErrSortieFinale)
        // cas d'une direction voulue vers la sortie
        // on relance l'interuption pour le niveau supérieur
      { ErrSortieFinale toto;
        throw (toto);
      }
   catch (...)// erreur inconnue
      {  cout << "\n **** ERREUR inconnuee en lecture du fichier de  commande de visualisation "
              << "\n on continue quand meme, mais il y aura peut-etre un probleme de coherence pour la suite";
         if (ParaGlob::NiveauImpression() >= 4)     
             cout  << "\n 2 UtilLecture::PositionEtExisteCVisu(..";
        }      
   // quelque soit la cause, on n'a pas trouvé la chaine
   return false;    
  };
   
//fichier CommandeVisu dans lequel sont lus les enregistrements
// en lecture directe
ifstream * UtilLecture::Ent_CommandeVisu() 
  { if (ent_CommandeVisu == NULL)
     { // cas ou le fichier n'est pas ouvert on l'ouvre
       Ouverture_CommandeVisu("lecture");
      }
    return (ifstream*) ent_CommandeVisu; 
   };     
         
 //------------ utilitaire de lecture d'un parametre précédé d'un mot clé, avec une restriction
 // sur les valeurs
 // lecture_effective: indique si oui ou non il y a eu lecture
 // val_defaut: si la grandeur n'est pas lue, elle est mise par défaut = val_defaut
 // nom_class_methode: le nom de la methode qui appel l'utilitaire -> sortie dans le  message si pb
 // min max : les bornes entre lesquelles doit se trouver le parametre lue sinon -> génération d'une erreur et arrêt
 //           si max < min alors la condition n'est pas prise en compte
 // mot_cle : mot_cle devant précéder le parametre
 // parametre: le parametre à lire
 // retourne le parametre lue ou la valeur par défaut
 bool UtilLecture::Lecture_un_parametre_int(int val_defaut,const string& nom_class_methode
								                   ,int min, int max, string& mot_cle, int& parametre ) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du parametre "<< mot_cle
                  << "\n on attendait la chaine " << mot_cle << " au lieu de: " << nom
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
         //sinon c'est ok
         *(entree) >> parametre;
			      if (max > min)
          {if ((parametre < min ) || (parametre > max )) 
           { cout << "\n erreur en lecture du parametre " << mot_cle
                  << "\n pour l'instant seuls les types " << min << " a " << max << " sont implantes, valeur lue:  " << parametre
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
			       };
         lecture_effective = true;
       }
      else // sinon on met la valeur par défaut
        { parametre  = val_defaut;};
		    // retour
		    return lecture_effective;
   };

 // idem pour un double										 
 bool UtilLecture::Lecture_un_parametre_double(double val_defaut,const string& nom_class_methode
									                     ,double min, double max,const string& mot_cle, double& parametre ) const
    { string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du parametre "<< mot_cle
                  << "\n on attendait la chaine " << mot_cle << " au lieu de: " << nom
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
         //sinon c'est ok
         *(entree) >> parametre;
			      if (max > min)
          {if ((parametre < min ) || (parametre > max )) 
           { cout << "\n erreur en lecture du parametre " << mot_cle
                  << "\n pour l'instant seuls les types " << min << " a " << max << " sont implantes, valeur lue:  " << parametre
                  << "\n " << nom_class_methode << "( ... " << endl ;
             Sortie(1);
           };
			       };
         lecture_effective = true;
       }
      else // sinon on met la valeur par défaut
        { parametre  = val_defaut;};
		    // retour
		    return lecture_effective;
    };

// lecture et passage d'un mot clé: il y a simplement vérification que c'est le bon mot clé qui est lue
// ramène si oui ou non le mot clé à été lue
bool UtilLecture::Lecture_et_verif_mot_cle(const string& nom_class_methode,const string& mot_cle) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du mot cle "<< mot_cle
                  << "\n on a lue  " << nom
                  << nom_class_methode << "( ... ";
             Sortie(1);
           };
         //sinon c'est ok
         lecture_effective = true;
       }
      else // sinon problème
       { cout << "\n erreur en lecture du mot cle "<< mot_cle
              << "\n il n'existe pas sur la ligne  " << tablcar
              << nom_class_methode << "( ... ";
         Sortie(1);
       };
		    // retour
		    return lecture_effective;
   };

// idem pour un mot clé et un string: nom
bool UtilLecture::Lecture_mot_cle_et_string(const string& nom_class_methode,const string& mot_cle,string& nom_ret) const
   {  string nom; bool lecture_effective=false;
      if (strstr(tablcar,mot_cle.c_str())!=NULL)
       { *(entree) >> nom;
         if (nom != mot_cle)
           { cout << "\n erreur en lecture du mot cle "<< mot_cle
                  << "\n on a lue  " << nom
                  << nom_class_methode << "( ... ";
             Sortie(1);
           };
         //sinon c'est ok
         lecture_effective = true;
       }
      else // sinon problème
       { cout << "\n erreur en lecture du mot cle "<< mot_cle
              << "\n il n'existe pas sur la ligne  " << tablcar
              << nom_class_methode << "( ... ";
         Sortie(1);
       };
      // puis lecture du string
      *(entree) >> nom_ret;
		    // retour
		    return lecture_effective;
   };

// ------------------------------- méthodes protégées ---------------------------------
        
//fichier CommandeVisu dans lequel sont lus les enregistrements
//  en écriture
ofstream * UtilLecture::Sort_CommandeVisu() 
   { if (sort_CommandeVisu == NULL)
       { // cas ou le fichier n'est pas ouvert on l'ouvre
         Ouverture_CommandeVisu("ecriture");
        }
     return (ofstream*) sort_CommandeVisu;
   } ;
