
// 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 "Charge.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "ReferenceNE.h"
#include "ReferenceAF.h"
#include "CourbePolyLineaire1D.h"

// --------------- méthodes particulière pour les conteneurs de chargement ----------
  // == cas de la classe PHydro
  // certaines fonctions sont redéfinies en suivant le caneva de Bloc.h
Charge::PHydro::PHydro()
  :BlocGeneEtVecMultType(2,1),N(),M(),normer(false)
    {};
Charge::PHydro::PHydro(const Charge::PHydro & a) : // constructeur par defaut
   BlocGeneEtVecMultType(a),N(a.N),M(a.M),normer(a.normer)
     {};
Charge::PHydro::~PHydro ()  // destructeur
     {};  // les courbes éventuelles existent par ailleurs, elles n'ont pas à être supprimées
// mise en place de l'association des courbes
// en retour indique si l'association est ok
bool Charge::PHydro::Mise_en_place_des_courbes(LesCourbes1D& lesCourbes1D)
 { // on passe en revue la liste de nom pour associer éventuellement avec les courbes
   int dim = ParaGlob::Dimension();
   // cas du vecteur N
   for (int i=1;i<=dim;i++)
     { const string& nom = Nom_vect(1,i);
       if (nom != "NULL")
        { // cas d'une coordonnée gérée par une courbe
          if (N.Taille() == 0) N.Change_taille(dim,NULL);
          if (lesCourbes1D.Existe(nom))
            { N(i) = lesCourbes1D.Trouve(nom);}
          else
            { cout << "\n erreur, on ne trouve pas la courbe coefficient " << i << "pour la direction normale N !!! "
                   << " de nom: " << nom
                   << "\n  Charge::PHydro::Mise_en_place_des_courbes(...";
              return false;
            };
        };
    };
   // cas du vecteur M
   for (int i=1;i<=dim;i++)
     { const string& nom = Nom_vect(2,i);
       if (nom != "NULL")
        { // cas d'une coordonnée gérée par une courbe
          if (M.Taille() == 0) M.Change_taille(dim,NULL);
          if (lesCourbes1D.Existe(nom))
            { M(i) = lesCourbes1D.Trouve(nom);}
          else
            { cout << "\n erreur, on ne trouve pas la courbe coefficient " << i << "pour le point A de la surface libre  !!! "
                   << " de nom: " << nom
                   << "\n  Charge::PHydro::Mise_en_place_des_courbes(...";
              return false;
            };
        };
    };
   // si on arrive là c'est que tous c'est bien passé
   return true;       
  };
// récup de la direction N normée
const Coordonnee& Charge::PHydro::Direction_N()
 {  // on regarde s'il y a des courbes de charges
    Coordonnee N_vect = Vect_de_coordonnee(1); // init
    if (N.Taille() == 0)
      // pas de courbe, on norme la première fois
      { if (!normer)
          { double norme = N_vect.Norme();
            if (norme != 1.)
                { N_vect.Normer();  Change_vect_de_coordonnee(1,N_vect);}
            normer = true;
          };
      }
    else // sinon il faut voir avec le temps
      {int dim = N.Taille();
       // récup des valeurs
       for (int i=1;i <= dim; i++)
        {if (N(i) != NULL)
          N_vect(i) = (N(i)->Valeur(ParaGlob::Variables_de_temps().TempsCourant()));
        };
       // on norme le vecteur
       double norme = N_vect.Norme();
       if (norme != 1.)
           { N_vect.Normer();};
       // on met à jour le vecteur
       Change_vect_de_coordonnee(1,N_vect);
      };
   // retour du vecteur qui continue à exister
   return Vect_de_coordonnee(1);
 };
// récup du point de la surface libre
const Coordonnee& Charge::PHydro::Point_M()
 {  // on regarde s'il y a des courbes de charges
    Coordonnee M_vect = Vect_de_coordonnee(2); // init
    if (M.Taille() != 0)
      // il faut voir avec le temps
      {int dim = M.Taille();
       // récup des valeurs
       for (int i=1;i <= dim; i++)
        {if (M(i) != NULL)
          M_vect(i) = (M(i)->Valeur(ParaGlob::Variables_de_temps().TempsCourant()));
        };
       // on met à jour le vecteur
       Change_vect_de_coordonnee(2,M_vect);
      };
   // retour du vecteur qui continue à exister
   return Vect_de_coordonnee(2);
 };

  // == cas de la classe PHydrodyna
       // --- mise en place de l'association des courbes pour PHydrodyna
       // en retour indique si l'association est ok
bool Charge::PHydrodyna::Mise_en_place_des_courbes(LesCourbes1D& lesCourbes1D)
 { // on passe en revue la liste de nom pour associer avec les courbes
   // cas du frottement fluid
   const string& nom = Nom(3); 
   if (nom != "NULL")
    { // cas où le frottement fluide est actif
      if (lesCourbes1D.Existe(nom)) 
         { frot_fluid = lesCourbes1D.Trouve(nom);}
      else
         { cout << "\n erreur, on ne trouve pas la courbe coefficient pour le frottement fluide !!! "
                << " de nom: " << nom
                << "\n  Charge::PHydrodyna::Mise_en_place_des_courbes(...";
           return false;
          };
      };     
   // cas de l'effort de traînée
   const string& nom1 = Nom(4); 
   if (nom1 != "NULL")
    { // cas où l'effort de traînée  est actif
      if (lesCourbes1D.Existe(nom1)) 
         { coef_aero_n = lesCourbes1D.Trouve(nom1);}
      else
         { cout << "\n erreur, on ne trouve pas la courbe coefficient pour l'effort de trainee !!! "
                << " de nom: " << nom1
                << "\n  Charge::PHydrodyna::Mise_en_place_des_courbes(...";
           return false;
          };
      };     
   // cas de l'effort de portance
   const string& nom2 = Nom(5); 
   if (nom2 != "NULL")
    { // cas où l'effort de portance  est actif
      if (lesCourbes1D.Existe(nom2)) 
         { coef_aero_t = lesCourbes1D.Trouve(nom2);}
      else
         { cout << "\n erreur, on ne trouve pas la courbe coefficient pour l'effort de portance !!! "
                << " de nom: " << nom2
                << "\n  Charge::PHydrodyna::Mise_en_place_des_courbes(...";
           return false;
          };
      };
   // si on arrive là c'est que tous c'est bien passé    
   return true;       
  };

// cas des torseurs de charges ponctuelles


// --------------- fin méthodes particulière pour les conteneurs de chargement ----------

// ------------- fin des variables static -----------------

Charge::Charge () :  // constructeur par defaut
   tabFsurfac(),tabPresUnif(),tabPonctuel(),PresUniDir(),PresHydro(),coefHydroDyna(),tabFlineique()
   ,tabFlineiqueSuiv(),tabFvol(),f_charge(NULL),interne_f_charge(false)
   ,tabTorseurPonct(),tab_P(),t_force()
   ,multi(0.),coeff(0.),temps_sauve(0.),multi_sauve(0.),coeff_sauve(0.)
   ,temps_fin_non_stricte(0)
   ,nomtypeCharge(),ancien_num_pt_type5(0),num_pt_courant_type5(0)
   ,temps_cpu_chargement()
   #ifdef UTILISATION_MPI
    ,temps_transfert_court(),temps_transfert_long(),temps_attente()
    ,tab_reqs1(),tab_reqs2(),tab_reqs3()
    ,tabV_transfert(),tabMat_transfert(),tab_six_faux_entiers()
    // pour les i/o
    ,buffer_ioBI_MPI(),tailles_buffer_ioBI_MPI(),offset_Charge()
    ,nb_buffer(1),taille_offset(2)
   #endif

   {// mise à jour de la valeur par défaut du chargement au cas où aucun chargement
    // n'est définit
    nomtypeCharge ="TYPE1";
    tabType.Change_taille(1);
    tabType(1) = 1.;
    
   #ifdef UTILISATION_MPI
     // on définit les conteneurs de passage d'info
     int taille_passage = 8;
     tab_reqs1.Change_taille(taille_passage);
     tab_reqs2.Change_taille(taille_passage);
     tab_reqs3.Change_taille(taille_passage);
     tabV_transfert.Change_taille(taille_passage);
     tabMat_transfert.Change_taille(taille_passage);
     tab_six_faux_entiers.Change_taille(taille_passage);
     for (int i=1;i<=taille_passage;i++) tab_six_faux_entiers(i).Change_taille(6);
     // pour les i/o
     buffer_ioBI_MPI.Change_taille(nb_buffer);
     tailles_buffer_ioBI_MPI.resize(nb_buffer,0);
     offset_Charge.resize(taille_offset);
   #endif
    
    } 
Charge::~Charge () 
{ if (f_charge != NULL) 
    { // on utilise un deuxième indicateur, car si la courbe est globale, et quelle est déjà supprimée
      // on ne peut plus la tester 
      if (interne_f_charge)
          delete f_charge;
     };     
  };
   
// affichage des differents chargements
void Charge::Affiche()  const  // affiche la totalite
  { Affiche1();
    Affiche2();
  };  
void Charge::Affiche1()  const // affiche que la premiere lecture
   { cout << "\n ******** Charges  ******** \n";
     if (tabFvol.Taille() != 0) 
      {cout << tabFvol.Taille() << " reference de force volumique lue  \n";
       for (int i=1; i<=tabFvol.Taille(); i++)
            tabFvol(i).Affiche();
       cout << "\n\n";
      }   
     if (tabFsurfac.Taille() != 0) 
      {cout << tabFsurfac.Taille() << " reference de densite de force surfacique lue  \n";
       for (int i=1; i<=tabFsurfac.Taille(); i++)
            tabFsurfac(i).Affiche();
       cout << "\n\n";
      }   
     if (tabPresUnif.Taille() != 0) 
      {cout << tabPresUnif.Taille() << " reference de pression uniformement reparti lue  \n";
       for (int i=1; i<=tabPresUnif.Taille(); i++)
                tabPresUnif(i).Affiche();
       cout << "\n\n";
      }
     if (tabPonctuel.Taille() != 0) 
      {cout << tabPonctuel.Taille() << " reference de force ponctuelle lue  \n";
       for (int i=1; i<=tabPonctuel.Taille(); i++)
                tabPonctuel(i).Affiche();
       cout << "\n\n";
      }
     if (PresUniDir.Taille() != 0) 
      {cout << PresUniDir.Taille() << " reference de pression unidirectionnelle"
            << " type pression dynamique des fluides lue  \n";
       for (int i=1; i<=PresUniDir.Taille(); i++)
                PresUniDir(i).Affiche();
       cout << "\n\n";
      }
     if (PresHydro.Taille() != 0) 
      {cout << PresHydro.Taille() << " reference de pression hydrostatique lue  \n";
       for (int i=1; i<=PresHydro.Taille(); i++)
                PresHydro(i).Affiche();
       cout << "\n\n";
      }
     if (coefHydroDyna.Taille() != 0) 
      {cout << coefHydroDyna.Taille() << " reference de pression hydrodynamique lue  \n";
       for (int i=1; i<=coefHydroDyna.Taille(); i++)
                coefHydroDyna(i).Affiche();
       cout << "\n\n";
      }
     if (tabFlineique.Taille() != 0) 
      {cout << tabFlineique.Taille() << " reference de densite de force lineique lue  \n";
       for (int i=1; i<=tabFlineique.Taille(); i++)
            tabFlineique(i).Affiche();
       cout << "\n\n";
      };
     if (tabFlineiqueSuiv.Taille() != 0) 
      {cout << tabFlineiqueSuiv.Taille() << " reference de densite de force lineique suiveuse lue  \n";
       for (int i=1; i<=tabFlineiqueSuiv.Taille(); i++)
            tabFlineiqueSuiv(i).Affiche();
       cout << "\n\n";
      };
     if (tabTorseurPonct.Taille() != 0)
      {cout << tabTorseurPonct.Taille() << " reference de torseur de forces ponctuelles lue  \n";
       for (int i=1; i<=tabTorseurPonct.Taille(); i++)
            tabTorseurPonct(i).Affiche();
       cout << "\n\n";
      };
    
     cout << endl;
    };     
void Charge::Affiche2()  const // affiche que la seconde lecture
  { cout << "\n ******** Type de Chargement  ******** \n";
    if ((nomtypeCharge == "TYPE1") || (nomtypeCharge == "TYPE2") ) 
      { cout << " type de chargement : " << nomtypeCharge << ", parametre : ";
        for (int i=1; i<=tabType.Taille(); i++) 
          cout << tabType(i) << " " ;
        cout << endl;
       }  
    else if (nomtypeCharge == "TYPE3")      
      { cout << " type de chargement : " << nomtypeCharge << ", pas de parametre  " << endl ;}
    else if ((nomtypeCharge == "TYPE4") || (nomtypeCharge == "TYPE5"))  
      { cout << " type de chargement : " << nomtypeCharge << ", fonction de charge:  ";
        if (interne_f_charge) 
           {f_charge->Affiche();}
        else { cout << " courbe1D " << f_charge->NomCourbe() << " ";};
       }        
    else  
      { cout << " **** type de chargement non défini !! **** " << endl ;}
    // cas de l'application du contrôle de temps fin
    if (temps_fin_non_stricte)
      cout << "\n la limite de temps est non stricte ";
    else
      cout << "\n la limite de temps est stricte ";
   };
               
// lecture des  actions exterieurs imposees
void Charge::Lecture1(UtilLecture & entreePrinc,LesReferences& lesRef,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  { if (ParaGlob::NiveauImpression() >= 4)
      cout << " debut de la lecture du chargement " << endl;  
    MotCle motCle; // ref aux mots cle
      { // on se positionne sur un mot cle
        while ( !motCle.SimotCle(entreePrinc.tablcar))
            entreePrinc.NouvelleDonnee();
        // definition de la liste de sous mot cle specifique
        Tableau<string> tsousMotref(10);
        tsousMotref(1) = "UNIFORME";tsousMotref(2) = "PRESSION";
        tsousMotref(3) = "PONCTUELLE";tsousMotref(4) = "PRESSDIR";
        tsousMotref(5) = "PHYDRO"; tsousMotref(6) = "LINEIQUE";
        tsousMotref(7) = "VOLUMIQUE"; tsousMotref(8) = "LINEIC_SUIVEUSE";
        tsousMotref(9) = "P_HYDRODYNA"; tsousMotref(10) = "TORSEUR_PONCT";
        Tableau<string> tsousMot(tsousMotref); // copie qui varie selon l'utilisation
        
        // lecture pour se positionner sur un  premier sous mot cle
        entreePrinc.NouvelleDonnee();
            
        // def d'une classe de lecture de bloc  BlocCharge<BlocVecType>   
        LectBloc < BlocCharge< BlocDdlLim<BlocForces> > > lecVecType;
        // def d'une classe de lecture de bloc BlocScalType   
        LectBloc < BlocCharge< BlocDdlLim<BlocIntensite> > > lecScalType;
        // def d'une classe de lecture de bloc PHydro   
        LectBloc < BlocCharge< BlocDdlLim<PHydro> > > lecPHydro;
        // def d'une classe de lecture de bloc PHydrodyna   
        LectBloc < BlocCharge< BlocDdlLim<PHydrodyna> > > lecPHydrodyna;
        // def d'une classe de lecture de bloc PTorseurPonct
        LectBloc < BlocCharge< BlocDdlLim<PTorseurPonct> > > lecPTorseurPonct;

        bool avance = true;
        while ( !motCle.SimotCle(entreePrinc.tablcar) && avance) 
        // lecture jusqu'au prochain mot cle
         { string inter(entreePrinc.tablcar); // pour eviter la boucle infini qui n'avance pas
           // lecture eventuelle des densite de force surfacique
           tsousMot = tsousMotref; 
           tsousMot.Enleve (1); // on enleve "UNIFORME"
           lecVecType.Lecture(entreePrinc,lesRef,"UNIFORME",
                     "lecture des densite de force surfacique",tabFsurfac,tsousMot,false);
                                                          
           // lecture eventuelle des pressions uniformement reparti
           tsousMot = tsousMotref; 
           tsousMot.Enleve (2); // on enleve "PRESSION"        
           lecScalType.Lecture(entreePrinc,lesRef,"PRESSION",
                     "lecture des pressions uniformement reparti",tabPresUnif,tsousMot,false); 
                             
           // lecture eventuelle des forces ponctuelles 
           tsousMot = tsousMotref;
           tsousMot.Enleve (3); // on enleve "PONCTUELLE"
           lecVecType.Lecture(entreePrinc,lesRef,"PONCTUELLE",
                     "lecture des forces ponctuelles",tabPonctuel,tsousMot,false);
                             
           // lecture eventuelle des pression unidirectionnelle
           tsousMot = tsousMotref; 
           tsousMot.Enleve (4); // on enleve "PRESSDIR"                 
           lecVecType.Lecture(entreePrinc,lesRef,"PRESSDIR",
                     "lecture des pressions unidirectionnelles",PresUniDir,tsousMot,false);
                                         
           // lecture eventuelle des pressions hydrostatiques 
           tsousMot = tsousMotref; 
           tsousMot.Enleve (5); // on enleve "PHYDRO"        
           lecPHydro.Lecture(entreePrinc,lesRef,"PHYDRO",
                     "lecture des pressions hydrostatiques",PresHydro,tsousMot,false);
           // initialisation  éventuelle
           int taj= PresHydro.Taille(); for (int i=1;i<=taj;i++)
             { if (!(PresHydro(i).Mise_en_place_des_courbes(lesCourbes1D))) // mise en place et test
                 { entreePrinc.MessageBuffer("** lecture des pressions hydrostatiques **");
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie (1);
                   };
              };            
          
           // lecture eventuelle des coeffs pour les efforts hydrodynamiques 
           tsousMot = tsousMotref; 
           tsousMot.Enleve (9); // on enleve "P_HYDRODYNA"        
           lecPHydrodyna.Lecture(entreePrinc,lesRef,"P_HYDRODYNA",
                     "lecture des pressions hydrodynamique",coefHydroDyna,tsousMot,false);
           // initialisation  éventuelle
           int tai= coefHydroDyna.Taille(); for (int i=1;i<=tai;i++) 
             { if (!(coefHydroDyna(i).Mise_en_place_des_courbes(lesCourbes1D))) // mise en place et test
                 { entreePrinc.MessageBuffer("** lecture des pressions hydrodynamiques **");
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie (1);
                   };
              };            
                                                         
           // lecture eventuelle des forces linéique uniformement reparti
           tsousMot = tsousMotref; 
           tsousMot.Enleve (6); // on enleve "LINEIQUE"        
           lecVecType.Lecture(entreePrinc,lesRef,"LINEIQUE",
                     "lecture des forces lineique uniformement reparti",tabFlineique,tsousMot,false); 
                                                          
           // lecture eventuelle des forces linéique uniformement reparti suiveuses
           tsousMot = tsousMotref; 
           tsousMot.Enleve (8); // on enleve "LINEIC_SUIVEUSE"        
           lecVecType.Lecture(entreePrinc,lesRef,"LINEIC_SUIVEUSE",
                     "lecture des forces lineique suiveuses uniformement reparti",tabFlineiqueSuiv,tsousMot,false); 
                                                          
           // lecture eventuelle des forces volumiques
           tsousMot = tsousMotref; 
           tsousMot.Enleve (7); // on enleve "VOLUMIQUE"        
           lecVecType.Lecture(entreePrinc,lesRef,"VOLUMIQUE",
                     "lecture des forces volumique",tabFvol,tsousMot,false);                              
                                                          
          
           // lecture eventuelle des torseurs de forces ponctuelles
           tsousMot = tsousMotref;
           tsousMot.Enleve (10); // on enleve "TORSEUR_PONCT"
           lecPTorseurPonct.Lecture(entreePrinc,lesRef,"TORSEUR_PONCT",
                     "lecture des torseurs de forces ponctuelles ",tabTorseurPonct,tsousMot,false);
          
            string sortie(entreePrinc.tablcar); // pour eviter la boucle infini
            if (inter == sortie)
              {avance = false;
               cout << " erreur dans la lecture des chargements, on ne trouve pas"
                    << " de sous mot cle"; 
               entreePrinc.MessageBuffer("** lecture des divers chargements **");
               Affiche1();
               throw (UtilLecture::ErrNouvelleDonnee(-1));
               Sortie (1);
              }     
          }                             

       }
    if (ParaGlob::NiveauImpression() >= 4)
      cout << " fin de la lecture du chargement " << endl;
    // on dimensionne certains tableaux de travail
    int taille_tors = tabTorseurPonct.Taille();
    tab_P.Change_taille(taille_tors);
    t_force.Change_taille(taille_tors);
   };

// lecture du type d'application du chargement
void Charge::Lecture2(UtilLecture & entreePrinc,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
  { if (ParaGlob::NiveauImpression() >= 4)
      cout << " debut de la lecture du type d'application du chargement " << endl;  
    MotCle motCle; // ref aux mots cle
    while ( !motCle.SimotCle(entreePrinc.tablcar))
            entreePrinc.NouvelleDonnee();
    if (strstr(entreePrinc.tablcar,"typecharge")!=NULL)
         { entreePrinc.NouvelleDonnee();
           *(entreePrinc.entree) >> nomtypeCharge;
           if (nomtypeCharge == "TYPE1")
             { tabType.Change_taille(1);
               *(entreePrinc.entree) >> tabType(1);
               // verif de la coherence des donnees
               if ( (Dabs(tabType(1)) <= ConstMath::trespetit) )
                 { cout << " \n erreur : type de chargement 1, le temps final lu "
                        << tabType(1) << " est trop petit " ;
                   entreePrinc.MessageBuffer("** lecture du type d\'application du chargement **");
                   Affiche2();
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie (1);
                  }                               
              }
           else if (nomtypeCharge == "TYPE2")
             { tabType.Change_taille(2);
               for (int i=1; i<=2; i++)
                 *(entreePrinc.entree) >> tabType(i);
               // verif de la coherence des donnees
               if ( (Dabs(tabType(1)) <= ConstMath::trespetit) )
                 { cout << " \n erreur : type de chargement 2, le temps t1 lu "
                        << tabType(1) << " est trop petit " ;
                   entreePrinc.MessageBuffer("** lecture du type d\'application du chargement **");
                   Affiche2();
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie (1);
                  } 
               if ( (Dabs(tabType(2)) <= ConstMath::trespetit) )
                 { cout << " \n erreur : type de chargement 2, le temps t2 lu "
                        << tabType(2) << " est trop petit " ;
                   entreePrinc.MessageBuffer("** lecture du type d\'application du chargement **");
                   Affiche2();
                   throw (UtilLecture::ErrNouvelleDonnee(-1));
                   Sortie (1);
                  }
             }                                    
           else if (nomtypeCharge == "TYPE3")
             { // rien à faire                           
              }
           else if ((nomtypeCharge == "TYPE4") || (nomtypeCharge == "TYPE5")) 
             { // cas d'une courbe de charge donnée par une courbe1D
               string nom;
               *(entreePrinc.entree) >>  nom;  // lecture du nom de la courbe   
               // on regarde si la courbe existe, si oui on récupère la référence 
               if (lesCourbes1D.Existe(nom)) 
                { f_charge = lesCourbes1D.Trouve(nom);
                  interne_f_charge = false;
                 }
               else
                { // sinon il faut la lire maintenant
                  string non_courbe("_");   
                  f_charge = Courbe1D::New_Courbe1D(non_courbe,Id_Nom_Courbe1D (nom.c_str()));
                  // lecture de la courbe
                  f_charge->LectDonnParticulieres_courbes (non_courbe,&entreePrinc);
                  interne_f_charge = true;
                 };
               // dans le cas ou le type est 5, on vérifie que la courbe est de type de liste de points
               if (nomtypeCharge == "TYPE5")
                { if ( (f_charge->Type_courbe() != COURBEPOLYLINEAIRE_1_D)
                     && (f_charge->Type_courbe() != CPL1D))
                   {cout << "\n **** erreur en lecture de la courbe de charge associee au type TYPE5"
                       << "\n la courbe doit etre de type poly-lineaire classique ou simplifie (cf. doc) ";
                    entreePrinc.MessageBuffer("** erreur en lecture du type de chargement **");
                    throw (UtilLecture::ErrNouvelleDonnee(-1));
                    Sortie (1);
                    };
                 };   
              }
           else if (nomtypeCharge == "TYPE6")
             { entreePrinc.NouvelleDonnee();
               typedef double inter ;
               list <inter> lili;
               inter t1,t2;
               while ( !motCle.SimotCle(entreePrinc.tablcar))
                 {  *(entreePrinc.entree) >> t1 >> t2;
                    lili.push_back(t1);
                    lili.push_back(t2);
                    entreePrinc.NouvelleDonnee();
                  }  
              // enregistrement des infos 
              tabType.Change_taille((int) lili.size());
              list <inter>::iterator i;
              int j;
              for (i=lili.begin(),j=1 ; i != lili.end(); i++,j++)
                 tabType(j) = (*i);
             }
           else if (nomtypeCharge == "TYPE7")
             { entreePrinc.NouvelleDonnee();
               typedef double inter ;
               list <inter> lili;
               inter t1,t2;
               while ( !motCle.SimotCle(entreePrinc.tablcar))
                 {  *(entreePrinc.entree) >> t1 >> t2;
                    lili.push_back(t1);
                    lili.push_back(t2);
                    entreePrinc.NouvelleDonnee();
                  }  
              // enregistrement des infos 
              tabType.Change_taille((int) lili.size());
              list <inter>::iterator i;
              int j;
              for (i=lili.begin(),j=1 ; i != lili.end(); i++,j++)
                 tabType(j) = (*i);
             }
               
         } 
       else
        { if (ParaGlob::NiveauImpression() >= 4)
            { cout << " \n warning : pas de mot cle typecharge, utilisation des valeurs par defaut ";
              Affiche2();}
        }             
    if (ParaGlob::NiveauImpression() >= 4)
      cout << " fin de la lecture du du type d'application du chargement " << endl;  
   };
     
// initialisation du chargement
//  on verifie egalement la bonne adequation des references
void Charge::Initialise(LesMaillages * lesmail,LesReferences* lesRef,ParaAlgoControle& pa
                        ,const LesCourbes1D& lesCourbes1D,const LesFonctions_nD&  lesFonctionsnD)
  { // initialisation des parametres temps
    paAlgo = & pa; // paAlgo->Multiplicateur()
 //-//   deltatmaxi = pa.Deltatmaxi() ;  // increment de temps maxi
 //-//   prectemps = pa.Prectemps(); // precision sur le temps final
 //-//   deltat = pa.Deltat();  // increment de temps
 //-//   tempsfin = pa.Tempsfin(); // temps de fin de calcul
 //-//   maxincre = pa.Maxincre(); // maximum d'increments de temps
 //-//   max_essai_incre = pa.Max_essai_incre(); // maximum de tentatives d'increments de temps
 //-//   multiplicateur = pa.Multiplicateur(); // multiplicateur de la charge
    // initialisation des pointeurs de fonction
    if (nomtypeCharge == "TYPE1")
      { PtDebut = &Charge::Debut1;
        PtAvance = &Charge::Avance1;
        PtPrecedent = &Charge::Precedent1;
        PtFin = &Charge::Fin1; 
       }
    else if (nomtypeCharge == "TYPE2")
      { PtDebut = &Charge::Debut2;
        PtAvance = &Charge::Avance2;
        PtPrecedent = &Charge::Precedent2;
        PtFin = &Charge::Fin2; 
       }
    else if (nomtypeCharge == "TYPE3")
      { PtDebut = &Charge::Debut3;
        PtAvance = &Charge::Avance3;
        PtPrecedent = &Charge::Precedent3;
        PtFin = &Charge::Fin3; 
       }
    else if (nomtypeCharge == "TYPE4")
      { PtDebut = &Charge::Debut4;
        PtAvance = &Charge::Avance4;
        PtPrecedent = &Charge::Precedent4;
        PtFin = &Charge::Fin4; 
       }
    else if (nomtypeCharge == "TYPE5")
      { PtDebut = &Charge::Debut5;
        PtAvance = &Charge::Avance5;
        PtPrecedent = &Charge::Precedent5;
        PtFin = &Charge::Fin5; 
       }
    else if (nomtypeCharge == "TYPE6")
      { PtDebut = &Charge::Debut6;
        PtAvance = &Charge::Avance6;
        PtPrecedent = &Charge::Precedent6;
        PtFin = &Charge::Fin6; 
       }
    else if (nomtypeCharge == "TYPE7")
      { PtDebut = &Charge::Debut7;
        PtAvance = &Charge::Avance7;
        PtPrecedent = &Charge::Precedent7;
        PtFin = &Charge::Fin7; 
       }
    else
      { cout << "\n cas non prevu, ne devrait pas arriver, nomtypeCharge = ";
        cout << nomtypeCharge << ", void Charge::Initialise(ParaAlgoControle& pa) " << endl;
        Sortie (1);
       }
    // appel de la fonction ad hoc
    coeff = 0.; // charge courante	a priori, en fait si type3 elle vaut 1 tout le temps, même au début
    (this->*PtDebut)();
   
    // ====  verification des references ===
   
    // --- cas des forces ponctuelles
    // on parcours le tableau tabPonctuel
    for (int i=1;i<= tabPonctuel.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& ref = lesRef->Trouve(tabPonctuel(i).NomRef(),tabPonctuel(i).NomMaillage());
        const ReferenceNE & refN = ((ReferenceNE &) ref);
        if (ref.Indic() != 1)
          // cas où la référence ne correspond pas à des noeuds
          { cout << "\n ERREUR la reference: " << ref.Nom() 
                 << " ne correspond pas a des noeuds !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                 << "\n cas des forces ponctuelles " << endl;
            Sortie (1);
           }
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre de noeuds
        if (tabPonctuel(i).Champ() != 0)
          { if (tabPonctuel(i).DimVect() != refN.Taille())
              { cout << "\n ERREUR la reference: " << ref.Nom()
                     << " contiens "<<refN.Taille() << "   noeuds  "
                     << " alors que le champ de valeurs lues stocke  "
                     << tabPonctuel(i).DimVect() << " vecteurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des forces ponctuelles " << endl;
                Sortie (1);
              };
          };
      };

    // --- cas des forces surfaciques uniformes
    // on parcours le tableau tabFsurfac dans le repère absolu
    for (int i=1;i<= tabFsurfac.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(tabFsurfac(i).NomRef(),tabFsurfac(i).NomMaillage());
        if (   ((refi.Indic() != 3)&& (ParaGlob::Dimension() == 3))
            || ((refi.Indic() != 3)&&(refi.Indic() != 4)&&(ParaGlob::Dimension() == 2))
            || (ParaGlob::Dimension() == 1))
          // cas d'element
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres d'element,"
                 << " ce qui est  necessaire pour les chargements surfacique !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
           }
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les surfaces en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
         { // on regarde si l'on est en 2D ou en 3D
           bool surface_existe = false;
           if (ParaGlob::Dimension() == 3)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).SurfExiste(ref.NumeroFA(ns));
           else if (ParaGlob::Dimension() == 2)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns));
           if (!surface_existe)
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                 << " correspondant à l'element :" << ref.NumeroElem(ns)
                 << " n'accepte pas de numero de surface/arête : " << ref.NumeroFA(ns);
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                 << "\n cas des forces surfaciques uniformes " << endl;
            Sortie (1);
             }
          };
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre de noeuds
        if (tabFsurfac(i).Champ() != 0)
          { if (tabFsurfac(i).DimVect() != ref.Taille())
              { cout << "\n ERREUR la reference: " << ref.Nom()
                     << " contiens "<<ref.Taille() << "  facette  "
                     << " alors que le champ de valeurs lues stocke  "
                     << tabFsurfac(i).DimVect() << " vecteurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des forces surfaciques uniformes " << endl;
                Sortie (1);
              };
          };
      };
    
    // --- cas des pression uniformes
    // on parcours le tableau tabPresUnif 
    for (int i=1;i<= tabPresUnif.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(tabPresUnif(i).NomRef(),tabPresUnif(i).NomMaillage());
        if (  ( ((refi.Indic() != 3)&& (ParaGlob::Dimension() == 3)) // ce n'est pas une surface et on est en dim 3
                  // et ce n'est pas : une arête + dim 3 + axisymétrie
                && !((refi.Indic() == 4)&&((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
              )
            || ((refi.Indic() != 3)&&(refi.Indic() != 4)&&(ParaGlob::Dimension() == 2))
            || (ParaGlob::Dimension() == 1))
          // cas d'element
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres surfaciques d'element,"
                 << " ce qui est  necessaire pour les chargements de pression !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
           }
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les surfaces en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
         { // on regarde si l'on est en 2D ou 2D axisymétrique ou en 3D, 
           bool surface_existe = false;
           if (  (ParaGlob::Dimension() == 2)  
                   || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns));
           else if (ParaGlob::Dimension() == 3)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).SurfExiste(ref.NumeroFA(ns));
           if (!surface_existe)
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                   << " correspondant à l'element :" << ref.NumeroElem(ns)
                   << " n'accepte pas de numero de surface/arête : " << ref.NumeroFA(ns);
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                   << "\n cas des pressions uniformes " << endl;
              Sortie (1);
            };
         };
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre de noeuds
        if (tabPresUnif(i).Champ() != 0)
          { if (tabPresUnif(i).DimVal() != ref.Taille())
              { cout << "\n ERREUR la reference: " << ref.Nom()
                     << " contiens "<<ref.Taille() << "  facette  "
                     << " alors que le champ de valeurs lues stocke  "
                     << tabPresUnif(i).DimVal() << " valeurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des pressions uniformes " << endl;
                Sortie (1);
              };
          };
      };
   
    // --- cas des pression unidirectionnelle
    // on parcours le tableau PresUniDir dans le repère absolu
    for (int i=1;i<= PresUniDir.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(PresUniDir(i).NomRef(),PresUniDir(i).NomMaillage());
        if (   ((refi.Indic() != 3)&& (ParaGlob::Dimension() == 3))
            || ((refi.Indic() != 3)&&(refi.Indic() != 4)&&(ParaGlob::Dimension() == 2))
              || (ParaGlob::Dimension() == 1))
          // cas d'element
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres surfaciques d'element,"
                 << " ce qui est  necessaire pour les chargements de pression unidirectionnelle!!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
           }
        const ReferenceAF & ref = ((ReferenceAF &) refi);
        // a priori pour l'instant ce type de chargement n'est valide que pour la 3D, et plus
        // non axisymétrique. On laisse cependant les tests pour les autres dimensions, au cas où
        // plus-tard on change d'avis
        if (ParaGlob::Dimension() !=3)
        	{ cout << "\n ERREUR: a priori le type de chargement suiveur en surfacique ne s'utilise que dans "
        	       << " un espace de travail 3D (classique), pour les autres dimensions il existe des chargements"
        	       << " equivalents specifiques : cf. la documentation ! ";
              cout << "\n ==== reference du chargement: " << ref.Nom();
              Sortie (1);
        	}
        else if (ParaGlob::AxiSymetrie())	
        	{ cout << "\n ERREUR: le type de chargement suiveur en surfacique ne s'utilise que dans "
        	       << " un espace de travail 3D (classique), en axisymetrique il existe des chargements"
        	       << " equivalents specifiques : cf. la documentation ! ";
              cout << "\n ==== reference du chargement: " << ref.Nom();
              Sortie (1);
        	};
        // Maintenant il faut vérifier que les surfaces en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
         { // on regarde si l'on est en 2D ou en 3D
           bool surface_existe = false;
           if (ParaGlob::Dimension() == 3)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).SurfExiste(ref.NumeroFA(ns));
           else if (ParaGlob::Dimension() == 2)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns));
           if (!surface_existe)
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                   << " correspondant à l'element :" << ref.NumeroElem(ns)
                   << " n'accepte pas de numero de surface/arête : " << ref.NumeroFA(ns);
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                   << "\n cas des forces forces qui varies localement avec la déformation " << endl;
              Sortie (1);
            };
           // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
           // de valeurs enregistrées correspond bien au nombre de noeuds
           if (PresUniDir(i).Champ() != 0)
             { if (PresUniDir(i).DimVect() != ref.Taille())
                { cout << "\n ERREUR la reference: " << ref.Nom()
                       << " contiens "<<ref.Taille() << "  facette  "
                       << " alors que le champ de valeurs  lues stocke "
                       << PresUniDir(i).DimVect() << " vecteurs !!" ;
                  cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                       << "\n cas des pression unidirectionnelle " << endl;
                  Sortie (1);
                };
             };
         };
      };
    
    // --- cas des pression hydrostatique
    // on parcours le tableau PresHydro dans le repère absolu
    for (int i=1;i<= PresHydro.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(PresHydro(i).NomRef(),PresHydro(i).NomMaillage());
        if (  ( ((refi.Indic() != 3)&& (ParaGlob::Dimension() == 3)) // ce n'est pas une surface et on est en dim 3
                  // et ce n'est pas : une arête + dim 3 + axisymétrie
                && !((refi.Indic() == 4)&&((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
              )
            || ((refi.Indic() != 3)&&(refi.Indic() != 4)&&(ParaGlob::Dimension() == 2))
            || (ParaGlob::Dimension() == 1))
          // cas d'element
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres surfaciques d'element,"
                 << " ce qui est  necessaire pour les chargements surfacique hydrostatique!!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
          };
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les surfaces en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
         { // on regarde si l'on est en 2D ou en 3D
           bool surface_existe = false;
           if (  (ParaGlob::Dimension() == 2)
                   || ((ParaGlob::Dimension() == 3)&&(ParaGlob::AxiSymetrie())))
             surface_existe =
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns));
           else if (ParaGlob::Dimension() == 3)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).SurfExiste(ref.NumeroFA(ns));
           if (!surface_existe)
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                   << " correspondant à l'element :" << ref.NumeroElem(ns)
                   << " n'accepte pas de numero de surface/arete : " << ref.NumeroFA(ns);
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                   << "\n cas de la pression hydrostatique " << endl;
              Sortie (1);
            };
         };
      };
    
    // --- cas des pression hydrodynamique
    // on parcours le tableau coefHydroDyna dans le repère absolu
    for (int i=1;i<= coefHydroDyna.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(coefHydroDyna(i).NomRef(),coefHydroDyna(i).NomMaillage());
        if (   ((refi.Indic() != 3)&& (ParaGlob::Dimension() == 3))
            || ((refi.Indic() != 3)&&(refi.Indic() != 4)&&(ParaGlob::Dimension() == 2))
            || (ParaGlob::Dimension() == 1))
          // cas d'element
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres surfaciques d'element,"
                 << " ce qui est  necessaire pour les chargements hydrosdynamiques !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
           }
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les surfaces en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
         { // on regarde si l'on est en 2D ou en 3D
           bool surface_existe = false;
           if (ParaGlob::Dimension() == 3)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).SurfExiste(ref.NumeroFA(ns));
           else if (ParaGlob::Dimension() == 2)
             surface_existe = 
                (lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns));
           if (!surface_existe)
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                 << " correspondant à l'element :" << ref.NumeroElem(ns)
                 << " n'accepte pas de numero de surface/arete : " << ref.NumeroFA(ns);
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                 << "\n cas de la pression hydrodynamique " << endl;
            Sortie (1);
             }
           }  
         }

    // --- cas des forces linéqiue uniformes
    // on parcours le tableau tabFlineique dans le repère absolu
    for (int i=1;i<= tabFlineique.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(tabFlineique(i).NomRef(),tabFlineique(i).NomMaillage());
        if (refi.Indic() != 4)
          // cas d'arrêtes
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres d'arête d'element,"
                 << " ce qui est  necessaire pour les chargements lineique !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
          };
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les aretes en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
          if (!(lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns)))
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                   << " correspondant à l'element :" << ref.NumeroElem(ns)
                   << " n'accepte pas de numero d'arete : " << ref.NumeroFA(ns);
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                   << "\n cas des forces linéiques uniformes " << endl;
              Sortie (1);
            };
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre d'éléments
        if (tabFlineique(i).Champ() != 0)
          { if (tabFlineique(i).DimVect() != ref.Taille())
              { cout << "\n ERREUR la reference: " << ref.Nom()
                     << " contiens "<<ref.Taille() << "   aretes  "
                     << " alors que le champ de valeurs  lues stocke "
                     << tabFlineique(i).DimVect() << " vecteurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des forces linéqiue uniformes " << endl;
                Sortie (1);
              };
          };
      };
         
    // --- cas des forces linéiques suiveuses uniformes
    // tout d'abord on vérifie que l'on est en 2D ou 1D si ces forces existent ou 3D axi
    int tabFlineiqueSuiv_Taille = tabFlineiqueSuiv.Taille();
    if ((tabFlineiqueSuiv_Taille > 0)&&(ParaGlob::Dimension() != 2)&&(!ParaGlob::AxiSymetrie()))
       { cout << "\n ERREUR la dimension est différente de 2 et il y a des forces linéiques suiveuses défini" 
              << " \n ceci n'est pas possible !! (indétermination de direction)"
              << " \n Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
         Sortie (1);
        }

    // on parcours le tableau tabFlineiqueSuiv dans le repère global
    for (int i=1;i<= tabFlineiqueSuiv.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(tabFlineiqueSuiv(i).NomRef(),tabFlineiqueSuiv(i).NomMaillage());
        if (refi.Indic() != 4)
          // cas d'arrêtes
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des frontieres d'arête d'element,"
                 << " ce qui est  necessaire pour les chargements lineique !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " << endl;
            Sortie (1);
           }
        const ReferenceAF & ref = ((ReferenceAF &) refi);  
        // Maintenant il faut vérifier que les aretes en question sont possible pour l'élément
        int nbref = ref.Taille();
        for (int ns=1;ns<= nbref;ns++)
          if (!(lesmail->Element_LesMaille(ref.Nbmaille(), ref.NumeroElem(ns))).AreteExiste(ref.NumeroFA(ns)))
            { cout << "\n ERREUR l'enregistrement " <<ns<< " de la reference: " << ref.Nom() 
                 << " correspondant à l'element :" << ref.NumeroElem(ns)
                 << " n'accepte pas de numero d'arete : " << ref.NumeroFA(ns);
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                   << "\n cas des forces linéiques suiveuses uniformes " << endl;
              Sortie (1);
            };
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre d'éléments
        if (tabFlineiqueSuiv(i).Champ() != 0)
          { if (tabFlineiqueSuiv(i).DimVect() != ref.Taille())
              { cout << "\n ERREUR la reference: " << ref.Nom()
                     << " contiens "<<ref.Taille() << "   aretes  "
                     << " alors que le champ de valeurs  lues stocke "
                     << tabFlineiqueSuiv(i).DimVect() << " vecteurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des forces linéiques suiveuses uniformes " << endl;
                Sortie (1);
              };
          };
      };
    
    // --- cas des forces volumiques
    // on parcours le tableau tabFvol dans le repère absolu
    for (int i=1;i<= tabFvol.Taille();i++)
      { // recup de la reference correspondant au mot cle
        const Reference& refi = lesRef->Trouve(tabFvol(i).NomRef(),tabFvol(i).NomMaillage());
        if (refi.Indic() != 2)
          // cas d'elements
          { cout << "\n ERREUR la reference: " << refi.Nom() 
                 << " ne correspond pas a des element,"
                 << " ce qui est  necessaire pour les chargements volumique !!";
            cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  " 
                 << "\n cas des forces volumiques uniformes " << endl;
            Sortie (1);
          };
        // dans le cas où il s'agit d'une ref relative à un champ, on vérifie que le nombre
        // de valeurs enregistrées correspond bien au nombre d'éléments
        const ReferenceNE & refE = ((ReferenceNE &) refi);
        if (tabFvol(i).Champ() != 0)
          { if (tabFvol(i).DimVect() != refE.Taille())
              { cout << "\n ERREUR la reference: " << refE.Nom()
                     << " contiens "<<refE.Taille() << "   elements  "
                     << " alors que le champ de valeurs  lues stocke "
                     << tabFvol(i).DimVect() << " vecteurs !!" ;
                cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des forces volumiques " << endl;
                Sortie (1);
              };
          };
      };
    // --- cas des torseurs de forces ponctuelles
    // on parcours le tableau tabTorseurPonct et on renseigne les torseurs pour les prochains calculs
    for (int i=1;i<= tabTorseurPonct.Taille();i++)
      { { // recup de la reference correspondant au mot cle
          const Reference& ref = lesRef->Trouve(tabTorseurPonct(i).NomRef(),tabTorseurPonct(i).NomMaillage());
          //const ReferenceNE & refN = ((ReferenceNE &) ref);
          if (ref.Indic() != 1)
            // cas où la référence ne correspond pas à des noeuds
            { cout << "\n ERREUR la reference: " << ref.Nom()
                   << " ne correspond pas a des noeuds !!";
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                   << "\n cas des torseurs de forces ponctuelles " << endl;
              Sortie (1);
             };
         }
         // on met à jour les fonctions nD internes si nécessaire
         if (!tabTorseurPonct(i).Mise_en_place_des_fonction_nD(lesFonctionsnD))
          { cout << "\n ERREUR d'association de fonction nD: pour la condition " << tabTorseurPonct(i)
                 << " revoir la mise en donnees !!";
            if (ParaGlob::param->NiveauImpression() > 3)
              cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                 << "\n cas des torseurs de forces ponctuelles " << endl;
            Sortie (1);
           };
         { //On s'occupe maintenant des noeuds éventuellement à rattacher
           //   récup du nom de la ref éventuelle de noeuds pour le centre du moment
           Deux_String nom_ref = tabTorseurPonct(i).Nom_Ref_pour_Ce();
           if ( nom_ref.nom2.length())
            {// cas du centre de gravité d'une référence de noeuds
             int num_mail = 1; // init par défaut
             if ( nom_ref.nom1.length()) // s'il y a un nom de maillage
                lesmail->NumMaillage(nom_ref.nom2); // on en récupère le numéro
             const Reference& ref  =
                ((Reference &) lesRef->Trouve(nom_ref.nom2,num_mail));
             if (ref.Indic() != 1)
               // cas où la référence ne correspond pas à des noeuds
               { cout << "\n ERREUR la reference: " << ref.Nom()
                      << " prevu pour un centre de gravite pour le calcul de torseur d'action, "
                      << " ne correspond pas a des noeuds !!";
                 if (ParaGlob::param->NiveauImpression() > 3)
                   cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                        << "\n cas des torseurs de forces ponctuelles " << endl;
                 Sortie (1);
               };
             const ReferenceNE & refN = ((ReferenceNE &) ref);
             // on va constituer une liste de noeuds que l'on va transmettre au torseur
             list < const Noeud * > liNoe;
             int reftaille = refN.Taille();
             for (int nn =1; nn<= reftaille;nn++)  // nn = position des  num de noeud
                liNoe.push_back(&(lesmail->Noeud_LesMaille(refN.Nbmaille(),refN.Numero(nn))));
             // mise en place des infos pour le centre si celui-ci dépend des noeuds
             if (!tabTorseurPonct(i).Def_tab_noeud_pour_centre(liNoe))
              { cout << "\n ERREUR dans la definition du centre de ref du momemt pour la condition " << tabTorseurPonct(i)
                     << " revoir la mise en donnees !!";
                if (ParaGlob::param->NiveauImpression() > 3)
                  cout << " Charge::Initialise(LesMaillages * lesMail,etc ...  "
                     << "\n cas des torseurs de forces ponctuelles " << endl;
                Sortie (1);
               };
            }
          };
          {//On définit des places de stockage intermédiaire pour optimiser les temps de calcul
           BlocCharge< BlocDdlLim<PTorseurPonct> >& tabTorseurPonct_i = tabTorseurPonct(i);
           const ReferenceNE & ref =
                 ((ReferenceNE &) lesRef->Trouve(tabTorseurPonct_i.NomRef(),tabTorseurPonct_i.NomMaillage()));
           int reftaille = ref.Taille();
           tab_P(i).Change_taille(reftaille);
           t_force(i).Change_taille(reftaille);
          };

      };

  };
    
//----- lecture écriture de base info -----
//   lecture base info
// = 1 : on récupère tout
// = 2 : on récupère uniquement les données variables (supposées comme telles)
void Charge::Lecture_base_info(istream& entr,const int cas,LesReferences& ,LesCourbes1D& lesCourbes1D
                                             ,LesFonctions_nD& lesFonctionsnD)
{  string toto;
   bool mono_proc_on_lit_un_BI_multiProc = false;
 #ifdef UTILISATION_MPI
   int proc_en_cours = ParaGlob::Monde()->rank();
   // === première partie commune à tous les proc
   // normalement tous les buffers ont été rempli, on se contente de rediriger les flux
    
   if (tailles_buffer_ioBI_MPI[0] > 0)
    {// on crée le flux sur le premier buffer:
     istrstream * entrons = new istrstream(buffer_ioBI_MPI(1).c_str(),tailles_buffer_ioBI_MPI[0]) ;
     istream& entr = *entrons; // on redéfinit ent
 #endif

     entr >> toto ; // entête dans le cas non MPI
     // dans le cas où on lit un fichier créé avec MPI io, et que l'on n'est pas
     // en MPI, on passe les offsets et tailles
   #ifndef UTILISATION_MPI
     if (toto == "buf0_Charge")
      {for (int i=0;i<3;i++) //
        {toto.clear();
         std::getline(entr, toto);
        };
       mono_proc_on_lit_un_BI_multiProc = true;
      };
   #endif

   if (mono_proc_on_lit_un_BI_multiProc)
      entr >> toto ; // lecture en tête
   #ifdef MISE_AU_POINT
     if (toto != "****chargement")
      {cout << "\n *** erreur en lecture, on attendait ****chargement "
            << " et on a lue " << toto;
       Sortie(1);
      };
   #endif
      switch (cas)
       { case 1 : // ------- on récupère tout -------------------------
         
         { if (ParaGlob::NiveauImpression() >= 6)
             cout << "== lecture du chargement \n";
           string type; entr >> type; // lecture du premier type
           while (type != "type_de_charge")
             {  if (type == "force_volumique")
                 // cas des densites de force volumique dans le repère absolu
                     entr >> tabFvol;
                if (type == "force_surfacique")
                 // cas des densites de force surfacique dans le repère absolu
                     entr >> tabFsurfac;
                if (type == "force_pression_uniforme")
                 // cas des pressions uniformement repartis, appliquee normalement a la surface
                     entr >> tabPresUnif;
                if (type == "forces_ponctuelles")
                 // cas des forces ponctuelles sur un noeud
                     entr >> tabPonctuel;
                if (type == "pression_unidirectionnelle")
                 // pression unidirectionnelle type pression dynamique des fluides
                     entr >> PresUniDir;
                if (type == "pression_hydrostatique")
                 // pression hydrostatique
                     entr >> PresHydro;
                if (type == "pression_hydrodynamique")
                 // pression hydrodynamique
                     entr >> coefHydroDyna;
                if (type == "forces_lineiques")
                 // densite de force lineique dans le repère absolu
                     entr >> tabFlineique;
                if (type == "forces_lineiques_suiveuses")
                 // densite de force lineique suiveuse
                     entr >> tabFlineiqueSuiv;
                if (type == "torseurs_forces_ponctuelles" )
                 // densite de torseurs de forces ponctuelles
                     entr >> tabTorseurPonct;
                entr >> type;
             }
           // type d'application du chargement
           entr  >> nomtypeCharge;
           int tabType_taille;
           entr >> toto >> tabType_taille;
           tabType.Change_taille(tabType_taille);
           for (int i=1;i<= tabType_taille;i++)
              entr >>  tabType(i);
           // cas particulier d'une fonction de charge
           if ((nomtypeCharge == "TYPE4") || (nomtypeCharge == "TYPE5"))
            { string nom; entr >> nom;
           if (nom != " fonction_de_charge: ")
                     { cout << "\n erreur en lecture de la fonction de charge, "
                            << " on attendait fonction_de_charge: et on a lue " << nom
                            << "\n Charge::Lecture_base_info(...";
                       Sortie(1);
                     };
              f_charge = lesCourbes1D.Lecture_pour_base_info(entr,cas,f_charge);
              {if (f_charge->NomCourbe() == "_") interne_f_charge=true; else interne_f_charge=false;};
             };
           // on lit éventuellement  les paramètres particuliers de gestion des types de chargement
           if (nomtypeCharge == "TYPE5")
              entr >> toto >> num_pt_courant_type5;
           // on écrit le type de gestion du temps fin
           entr >> toto >>  temps_fin_non_stricte;
       break;
       }
         case  2 : // ----------- lecture uniquement de se qui varie --------------------
         {
           // le parametre global d'avancement de la charge
//           string toto;
//           entr >> toto; // lecture de l'entête
           // compteur_essai_increment d'increment
           entr >> toto >> compteur_essai_increment;
           // multi = l'increment courant de multiplication de la charge
           // coeff =  niveau actuel de la charge
           entr >> toto >> multi >> coeff;
           // on lit également le numéro du type pour la gestion éventuelle de reprise
           // avec des types différents
           short int numtype; entr >> numtype;
           if ((numtype != 5) && (nomtypeCharge == "TYPE5"))
            { // cas d'une reprise avec le type 5, à la suite d'un autre type -> a priori impossible
              cout << "\n erreur en restart !! on ne peut pas redemarrer avec le type 5 de chargement "
                   << " a la suite d'un autre type !! ";
              if (ParaGlob::NiveauImpression() >= 4){ cout << "\n Charge::Lecture_base_info(.... ";};
              Sortie(1);
             };
           // on lit éventuellement  les paramètres particuliers de gestion des types de chargement
           if (nomtypeCharge == "TYPE5")
              entr >> toto >> num_pt_courant_type5;
           // temps cpu
           entr >> toto >>  temps_cpu_chargement;
          break;
          }
         default :
           { cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n";
             cout << "Charge::Lecture_base_info(istream& entr,const int cas)"
                  << " cas= " << cas << endl;
             Sortie(1);
           }
        };
 #ifdef UTILISATION_MPI
    }; // fin lecture  buffer
 #endif


};
        
//   écriture base info   
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Charge::Ecriture_base_info(ostream& sort,const int cas)
{
 #ifdef UTILISATION_MPI
   {int proc_en_cours = ParaGlob::Monde()->rank();
    // 1) dans le cas d'un proc 0 ou i, on redéfinit le flux de sortie, pour bufferiser les infos en sortie
    // qui sont ensuite sortie via MPI i-o à l'aide de la méthode Ecriture_base_info_MPI_IO
    // les récupérations et les sorties sont effectuées de manière asynchrone par rapport aux autres proc
    // 2) seul le proc 0 sort pour le cas 1, rien pour cas 2
    std::ostringstream sort; // redéfinition de sort
    if (proc_en_cours == 0) // partie dédiée proc 0
     {
 #endif
      switch (cas)
       { case 1 : // ------- on sauvegarde tout -------------------------
         { sort << "\n ****chargement \n" ;
           // cas des densites de force volumique dans le repère absolu
           if (tabFvol.Taille() != 0)
              sort << " force_volumique "  << tabFvol;
           // cas des densites de force surfacique dans le repère absolu
           if (tabFsurfac.Taille() != 0)
              sort << " force_surfacique " << tabFsurfac;
           // cas des pressions uniformement repartis, appliquee normalement a la surface
           if (tabPresUnif.Taille() != 0)
              sort << " force_pression_uniforme " <<  tabPresUnif;
           // cas des forces ponctuelles sur un noeud
           if (tabPonctuel.Taille() != 0)
              sort << " forces_ponctuelles " <<  tabPonctuel;
           // pression unidirectionnelle type pression dynamique des fluides
           if (PresUniDir.Taille() != 0)
              sort << " pression_unidirectionnelle " <<  PresUniDir;
           // pression hydrostatique
           if (PresHydro.Taille() != 0)
              sort << " pression_hydrostatique " <<  PresHydro;
           // pression hydrodynamique
           if (coefHydroDyna.Taille() != 0)
              sort << " pression_hydrodynamique " <<  coefHydroDyna;
           // densite de force lineique dans le repère absolu
           if (tabFlineique.Taille() != 0)
              sort << " forces_lineiques " <<  tabFlineique;
           // densite de force lineique suiveuses
           if (tabFlineiqueSuiv.Taille() != 0)
              sort << " forces_lineiques_suiveuses " <<  tabFlineiqueSuiv;
           // densite de torseurs de forces ponctuelles
           if (tabTorseurPonct.Taille() != 0)
              sort << " torseurs_forces_ponctuelles " <<  tabTorseurPonct;
           // type d'application du chargement
           sort << " type_de_charge " << nomtypeCharge;
           int tabType_taille = tabType.Taille();
           sort << " parametres " << tabType_taille;
           for (int i=1;i<= tabType_taille;i++)
              sort << "  " <<  tabType(i);
           // cas particulier d'une fonction de charge
           if ((nomtypeCharge == "TYPE4") || (nomtypeCharge == "TYPE5"))
            { sort << " fonction_de_charge:  " ;
              LesCourbes1D::Ecriture_pour_base_info(sort,cas,f_charge);
             }
           // on écrit également  les paramètres particuliers de gestion des types de chargement
           if (nomtypeCharge == "TYPE5")
              sort << " para_type5 " << num_pt_courant_type5 << " ";
           // on écrit le type de gestion du temps fin
           sort << "\n gestion_temps_fin " << temps_fin_non_stricte;
       break;
       }
         case  2 : // ----------- sauvegarde uniquement de se qui varie --------------------
         {
           // le parametre global d'avancement de la charge
     //      sort << "\n temps " << temps << " ";
           // compteur_essai_increment d'increment
           sort << "\n ****chargement " ;
           sort <<"\n compteur_essai_increment " <<   compteur_essai_increment << " ";
           // multi = l'increment courant de multiplication de la charge
           // coeff =  niveau actuel de la charge
           sort << "\n multi_et_coeff " << multi << " " << coeff << " ";
           // on sort également le numéro du type pour la gestion éventuelle de reprise
           // avec des types différents
           sort << nomtypeCharge.substr(4,nomtypeCharge.length()-4) << " ";
           if (nomtypeCharge == "TYPE5")
              {sort << " para_type5 " << num_pt_courant_type5 << " ";};
     //      else { sort << "---" << 0 ; }; // de manière à ne pas avoir de pb si on change
           // temps cpu
           sort << "\n temps_cpu_charge: "<< temps_cpu_chargement;
          break;
          }
         default :
       { cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n";
         cout << "Charge::Ecriture_base_info(ostream& sort,const int cas)"
        << " cas= " << cas << endl;
         Sortie(1);
         }
        };
 #ifdef UTILISATION_MPI
     };
    buffer_ioBI_MPI(1) = sort.str(); // on sauvegarde
    tailles_buffer_ioBI_MPI[0] = buffer_ioBI_MPI(1).size();
   };
 #endif

};

#ifdef UTILISATION_MPI
// retour de la taille globale des sorties retardées
// concernant les sorties sur .BI
MPI_Offset  Charge::Taille_buffer_sortie_BI()
  {MPI_Offset  taille_totale = 0; // init
   int proc_en_cours = ParaGlob::Monde()->rank();
   if (proc_en_cours == 0) // partie dédiée proc 0
     {// tout d'abord on prend en compte les buffers propres
      for (MPI_Offset  i=1;i<= nb_buffer;i++) // normalement 1
        taille_totale += buffer_ioBI_MPI(i).size();
      // puis on intègre la taille de l'ensemble des offsets:
      MPI_Offset  taille_entete = 42 + (taille_offset)*21+27; // cf. Charge::Ecriture_base_info_MPI_IO
      taille_totale += taille_entete;
     };
   // retour
   return taille_totale; // seule la valeur retournée par proc 0 est licite
  };

// récupération de l'offset global sur .BI pour la classe
// et mise à jour des offsets de classes dérivées si besoin
void Charge::Mise_a_jour_Offset_BI_ecriture(MPI_Offset offset,const int cas)
 {// seul le proc 0 calcule les offsets qui sont ensuites transmis à tous les proc
  // mais il faut que tous les proc passent par toutes les méthodes
  int proc_en_cours = ParaGlob::Monde()->rank();
  if (proc_en_cours == 0)
   {
    // on commence par prendre en compte l'offset général puis ceux propres à proc 0
    // ce sont des données qui se situent avant ceux des proc i
    offset_Charge[0] = offset;
    // puis la première partie propre à proc 0
    MPI_Offset a_ajouter = offset+tailles_buffer_ioBI_MPI[0];
    // puis on intègre la taille de l'ensemble des offsets:
    MPI_Offset taille_entete = 42 + (taille_offset)*21+27; // cf. Charge::Ecriture_base_info_MPI_IO
    offset_Charge[1] = taille_entete+a_ajouter; // position final +1
   };
     
  // on transmets à tous les proc i les offsets
  broadcast(*ParaGlob::Monde(), offset_Charge, 0);
 };
// idem en lecture, mais là il s'agit uniquement de la mise à jour
// de l'offset seul puis c'est la classe qui s'en débrouille
void Charge::Mise_a_jour_Offset_BI_lecture(MPI_Offset offset,const int cas)
  { offset_Charge[0] = offset;
  };

// lecture MPI des infos bufferisées
void Charge::Lecture_base_info_MPI_IO(MPI_File * ent_MPI,const int cas)
 { int proc_en_cours = ParaGlob::Monde()->rank();

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

   };

  // 3) ==== on dimensionne  les_taille_buffer_ioBI_MPI
  { MPI_Offset taille_entete = 42 + (taille_offset)*21+27; // cf. Ecriture_base_info_MPI_IO

    tailles_buffer_ioBI_MPI[0] = offset_Charge[1] - (offset_Charge[0]+taille_entete);
   };
  
  // 3) ==== lecture du  buffer
  if (tailles_buffer_ioBI_MPI[0] > 0)
  { char * buffer_car = new char [tailles_buffer_ioBI_MPI[0]] ; // def du tableau de travail
    MPI_Status status;
    int ierr = MPI_File_read_all(*ent_MPI, buffer_car, tailles_buffer_ioBI_MPI[0], MPI_CHAR, &status);
    if (ierr)
      {cout << "\n *** erreur d'acces a MPI_File_read_all: code " << ierr << " , stop Herezh "
            << "\n proc "<<proc_en_cours << ", lecture  buffer1 "
            << "\n Charge::Lecture_base_info_MPI_IO(..." << endl;
       Sortie(1);
      };
    buffer_ioBI_MPI(1).resize(tailles_buffer_ioBI_MPI[0]);
    buffer_ioBI_MPI(1).replace(0,tailles_buffer_ioBI_MPI[0],buffer_car);
  };
 };

  
// écriture MPI des infos bufferisées
void Charge::Ecriture_base_info_MPI_IO(MPI_File * sort_MPI, const int cas)
  { int proc_en_cours = ParaGlob::Monde()->rank();
    // si proc 0, on sort les ref
    if (proc_en_cours == 0)
     {//  === écriture dans flot string de la taille des buffers propres
      // pour avoir une sortie lisible, on crée tout d'abord un buffer string avec les infos
      std::ostringstream buf2(std::ios_base::out);
      buf2 << "\n offset_base_info_MPI_IO \n"; // 27 char
      for (MPI_Offset i=0;i<taille_offset;i++)
        // on sort donc (1)*21 char
        buf2 << std::right << setw(20) << offset_Charge[i] << " ";
       
      // 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();
      #ifdef MISE_AU_POINT
       if (taille_buf != (taille_offset)*21+27)
         {cout << "\n *** sans doute erreur, taille_buf "<<taille_buf
               << " est  different de (taille_offset)*21+27 = " << (taille_offset)*21+27
               << "\n  Charge::Ecriture_base_info_MPI_IO(..." << endl;
          Sortie(1);
         };
      #endif

      // 1) ==== écriture de la taille de l'ensemble des offsets propres
      // on encapsule pour ré-utiliser la même trame
      {
        std::ostringstream bufdeb(std::ios_base::out);
        bufdeb << "\n       buf0_Charge  "; // 21 char
        bufdeb << std::right << setw(20) << taille_buf; // on justifie à droite et on utilise 20 char
        bufdeb << " "; // 1 char
        string buf_inter = bufdeb.str(); // normalement 42 char
        // sortie sur fichier de la taille de buf2
        MPI_Offset offset = offset_Charge[0]; // récup de l'offset
        int ierr = MPI_File_seek(*sort_MPI, offset, MPI_SEEK_SET); // positionnement
        if (ierr) // traitement erreur éventuelle
            {cout << "\n *** erreur de positionnement MPI_File_seek: code " << ierr << " , stop Herezh "
                  << "\n proc 0, ecriture buf0_Charge "
                  << "\n  Charge::Ecriture_base_info_MPI_IO(..." << endl;
             Sortie(1);
            };
        MPI_Status status; // pour le retour
        ierr = MPI_File_write(*sort_MPI,buf_inter.c_str(),42,MPI_CHAR,&status);
        if (ierr)
          {cout << "\n *** erreur d'acces a MPI_File_write: code " << ierr << " , stop Herezh "
                << "\n proc 0, ecriture entete buffer "
                << "\n  Charge::Ecriture_base_info_MPI_IO(..." << endl;
           Sortie(1);
          };

      };

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


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

#ifdef UTILISATION_MPI
// transfert du second membre "SM_transfert" et mise à jour
// de l'index des tableaux "index_transfert" par rotation cyclique
// NB: tous les tableaux doivent avoir la même taille
void Charge::Transfert_SM(bool& premier_passage,
                             const int& tyfront,
                             const int& num_front,
                             Vecteur  & SM_transfert,
                             int& index_transfert,
                             const int & numail,
                             const int & numelem
                            )
    {
      temps_attente.Mise_en_route_du_comptage(); // comptage cpu
      mpi::request & reqs1 = tab_reqs1(index_transfert); // pour simplifier
      mpi::request & reqs2 = tab_reqs2(index_transfert); // pour simplifier
      int taille_tableau = tab_six_faux_entiers.Taille();
      // on récupère un signal du process 0
      if (premier_passage) {premier_passage = false;}
      else // on regarde l'activité , car au début avant le balayage de tous les éléments des tableaux
         {if (reqs1.active()) reqs1.wait(); // les requests ne sont pas alimentés
 //  les requests sont déjà testés vide dans charge3.cc
 //         if (reqs2.active()) reqs2.wait(); // car aucun transfert n'a encore été effectué
         };
      temps_attente.Arret_du_comptage(); // fin comptage cpu
      temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
      Vecteur& six_faux_entiers = tab_six_faux_entiers(index_transfert); // pour simplifier
      six_faux_entiers(1) = (double) numelem;
      six_faux_entiers(2) = (double)  numail;
      six_faux_entiers(3) =  (double) tyfront;
      six_faux_entiers(4) =  (double) num_front;
      six_faux_entiers(5) =  (double) SM_transfert.Taille();
      six_faux_entiers(6) =  (double) index_transfert;
      // on transmet les numéros d'élément et de maillage etc.
      reqs1 = six_faux_entiers.Ienvoi_MPI(0, 34);
      temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
      temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
      
      // puis on transmets le vecteur résidu sauf si tyfront est négatif
      if (tyfront > 0)
       {reqs2 = SM_transfert.Ienvoi_MPI(0,35);
        // // debug
        // cout << "\n debug Charge::Transfert_SM(  proc= "<< ParaGlob::Monde()->rank()
        //      << " six_faux_entiers= " << six_faux_entiers
        //      << " SM_transfert= " << SM_transfert << flush;
        // // fin debug
       };
      // ici on utilise un nouveau élément de tableau pour éviter d'écraser la précédente version qui peut être encore
      // en transfert vers le proc 0
      index_transfert++;
      if (index_transfert > taille_tableau) // on fait une permutation circulaire
          index_transfert = 1;// on revient au premier élément des tableaux de transfert
      temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
    };
    
// transfert du second membre "SM_transfert" et de la matrice "MAT_transfert" et mise à jour
// de l'index des tableaux "index_transfert" par rotation cyclique
// NB: tous les tableaux doivent avoir la même taille
void Charge::Transfert_MatSm(bool& premier_passage,
                     const int& tyfront,
                     const int& num_front,
                     Vecteur  & SM_transfert,
                     Mat_pleine * MAT_transfert,
                     int& index_transfert,
                     const int & numail,
                     const int & numelem
                    )
    {
      temps_attente.Mise_en_route_du_comptage(); // comptage cpu
      mpi::request & reqs1 = tab_reqs1(index_transfert); // pour simplifier
      mpi::request & reqs2 = tab_reqs2(index_transfert); // pour simplifier
      mpi::request & reqs3 = tab_reqs3(index_transfert); // pour simplifier
      int taille_tableau = tab_six_faux_entiers.Taille();
      // on récupère un signal du process 0
      if (premier_passage) {premier_passage = false;}
      else // on regarde l'activité , car au début avant le balayage de tous les éléments des tableaux
         {if (reqs1.active()) reqs1.wait(); // les requests ne sont pas alimentés
 //  les requests sont déjà testés vide dans charge3.cc
 //         if (reqs2.active()) reqs2.wait(); // car aucun transfert n'a encore été effectué
 //         if (reqs3.active()) reqs3.wait(); // car aucun transfert n'a encore été effectué
         };
      temps_attente.Arret_du_comptage(); // fin comptage cpu
      temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
      Vecteur& six_faux_entiers = tab_six_faux_entiers(index_transfert); // pour simplifier
      six_faux_entiers(1) = (double) numelem;
      six_faux_entiers(2) = (double)  numail;
      six_faux_entiers(3) =  (double) tyfront;
      six_faux_entiers(4) =  (double) num_front;
      six_faux_entiers(5) =  (double) SM_transfert.Taille();
      int indique_matrice = (MAT_transfert != NULL);
      six_faux_entiers(6) =  (double) indique_matrice;
      // on transmet les numéros d'élément et de maillage etc.
      reqs1 = six_faux_entiers.Ienvoi_MPI(0, 34);
   // // debug
   // cout << "\n debug Charge::Transfert_SM(  proc= "<< ParaGlob::Monde()->rank()
   //      << " six_faux_entiers= " << six_faux_entiers
   //      << " SM_transfert= " << SM_transfert << flush;
   // // fin debug
      temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
      temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
      
      // puis on transmets le vecteur résidu sauf si tyfront est négatif
      if (tyfront > 0)
       {reqs2 = SM_transfert.Ienvoi_MPI(0,35);
        // puis on transmets éventuellementla matrice de raideur
        if (MAT_transfert != NULL)
        reqs3 = MAT_transfert->Ienvoi_MPI(0,36);
       };
      // ici on utilise un nouveau élément de tableau pour éviter d'écraser la précédente version qui peut être encore
      // en transfert vers le proc 0
      index_transfert++;
      if (index_transfert > taille_tableau) // on fait une permutation circulaire
          index_transfert = 1;// on revient au premier élément des tableaux de transfert
      temps_transfert_long.Arret_du_comptage(); // fin comptage cpu
    };
    
    
#endif

    
