
// 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 "BlocCharge.h"
#include "ConstMath.h"
#include "CharUtil.h"
#include "Util.h"
#include <limits>

//================================================ 
//    cas d'un bloc scalaire type
//================================================
// un bloc scalaire type correspond a une reference
// un mot cle, et une seule valeur

// Constructeur    
BlocScalVecTypeCharge::BlocScalVecTypeCharge () :   // par defaut
 BlocGeneEtVecMultType(0,1) // 0 vecteur et 1 scalaire
 ,champ(false)
  { 
   };

// avec : n: le nombre de vecteurs, m le nombre de scalaires , n le nombre de ptnom
BlocScalVecTypeCharge::BlocScalVecTypeCharge(int n,int m)
 : BlocGeneEtVecMultType(n,m),champ(false)
   {};

BlocScalVecTypeCharge::BlocScalVecTypeCharge (const BlocScalVecTypeCharge& a) : // de copie
 BlocGeneEtVecMultType(a),champ(a.champ)
  { 
   };


// lecture d'un bloc
void BlocScalVecTypeCharge::Lecture(UtilLecture & entreePrinc)
    {
      // tout d'abord les cas particuliers
      if (strstr(entreePrinc.tablcar,"champ_de_valeurs:")!=NULL)
      // on regarde si c'est un champ de valeur c'est-à-dire une valeur par item de la ref
      // dans ce cas appel de la procédure a doc
       { BlocGeneEtVecMultType::Lecture_entete(entreePrinc);
         Lecture_champ_de_valeurs(entreePrinc);
         champ = 1;
       }
      else if (strstr(entreePrinc.tablcar,"champ_de_fonctions:")!=NULL)
       { BlocGeneEtVecMultType::Lecture_entete(entreePrinc);
         Lecture_champ_de_fonctions(entreePrinc);
         champ = 2;
       }
      else // sinon cas d'une simple valeur
       // lecture de la classe mère
       { BlocGeneEtVecMultType::Lecture(entreePrinc);
         champ = 0;
       };
     };

//--------------- méthodes protégées ------

// lecture dans le cas particulier d'un champ de valeurs
void BlocScalVecTypeCharge::Lecture_champ_de_valeurs(UtilLecture & entreePrinc)
  {// si initialement on a un vecteur ce sera un champ de vecteur à lire
   // idem si c'est un scalaire
   int dima = ParaGlob::Dimension();
   if (DimVect() == 0)
     // cas d'un champ de scalaire
    { list <double> lili; // une liste de travail
      // on va lire tant que l'on n'aura pas trouvé le mot clé de fin de champ
      entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
      while (strstr(entreePrinc.tablcar,"fin_champ_de_valeurs:")==NULL)
        { double grandeur;
          *(entreePrinc.entree) >> grandeur;
          // on contrôle le flux
          if ((entreePrinc.entree)->rdstate() == 0)
          // pour mémoire ici on a
           /*       enum io_state
                    {  badbit   = 1<<0, // -> 1 dans rdstate()
                       eofbit   = 1<<1, // -> 2 
                       failbit  = 1<<2, // -> 4 
                       goodbit  = 0     // -> O 
                     };*/
              {lili.push_back(grandeur); }// lecture normale
          #ifdef ENLINUX
            else  if ((entreePrinc.entree)->fail())
               // on a atteind la fin de la ligne et on appelle un nouvel enregistrement 
              {   entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
                  *(entreePrinc.entree) >> grandeur;
                  lili.push_back(grandeur); // lecture normale
              }
          #else
            else  if ((entreePrinc.entree)->eof())
              // la lecture est bonne mais on a atteind la fin de la ligne
              {  lili.push_back(grandeur); // lecture
                 entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
              }
          #endif
            else // cas d'une erreur de lecture
              { cout << "\n erreur de lecture inconnue  ";
                entreePrinc.MessageBuffer("** lecture champ de chargement **");
                cout << "\n BlocScalVecTypeCharge::Lecture_champ_de_valeurs(..." << endl;
                Sortie (1);
              };
         
        };
      BlocGeneEtVecMultType::Change_tab_val(lili);
    }
   else
     // cas d'un champ de vecteur
    { list <Coordonnee> lico; // une liste de travail
      // on va lire tant que l'on n'aura pas trouvé le mot clé de fin de champ
      entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
      Coordonnee coo(dima); // variable de travail
      while (strstr(entreePrinc.tablcar,"fin_champ_de_valeurs:")==NULL)
        { coo.Lecture(entreePrinc);
          // on contrôle le flux
          if ((entreePrinc.entree)->rdstate() == 0)
          // pour mémoire ici on a
           /*       enum io_state
                    {  badbit   = 1<<0, // -> 1 dans rdstate()
                       eofbit   = 1<<1, // -> 2 
                       failbit  = 1<<2, // -> 4 
                       goodbit  = 0     // -> O 
                     };*/
              {lico.push_back(coo); }// lecture normale
          #ifdef ENLINUX
            else  if ((entreePrinc->entree)->fail())
               // on a atteind la fin de la ligne et on appelle un nouvel enregistrement 
              {   entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
                  coo.Lecture(entreePrinc);
                  lico.push_back(coo); // lecture normale
              }
          #else
            else  if ((entreePrinc.entree)->eof())
              // la lecture est bonne mais on a atteind la fin de la ligne
              {  lico.push_back(coo); // lecture
                 entreePrinc.NouvelleDonnee();  // lecture d'un nouvelle enregistrement
              }
          #endif
            else // cas d'une erreur de lecture
              { cout << "\n erreur de lecture inconnue  ";
                entreePrinc.MessageBuffer("** lecture champ de chargement **");
                cout << "\n BlocScalVecTypeCharge::Lecture_champ_de_valeurs(..." << endl;
                Sortie (1);
              };
         
        };
      BlocGeneEtVecMultType::Change_vect_coorpt(lico);
    };
  };

// lecture dans le cas particulier d'un champ de fonctions
void BlocScalVecTypeCharge::Lecture_champ_de_fonctions(UtilLecture & entreePrinc)
  { // en attente pour l'instant
    cout << "\n **** pour l'instant la methode : "
         << " BlocScalVecTypeCharge::Lecture_champ_de_fonctions(..."
         << " n'est pas implemente ! "<< endl;
  };

// affichage des infos     
void BlocScalVecTypeCharge::Affiche()  const
  { // tout d'abord affichage des infos de la classe mère
    BlocGeneEtVecMultType::Affiche();
    // puis les valeurs propres 
    cout << "\n champ: " << champ << endl;
  };

BlocScalVecTypeCharge& BlocScalVecTypeCharge::operator = ( const BlocScalVecTypeCharge& a)
    { // tout d'abord la classe mère
      // pour être sûr de ne pas utiliser le constructeur
      const BlocGeneEtVecMultType& b =  *((const BlocGeneEtVecMultType*) & a);
      // une addition de l'opérateur du bloc BlocGeneEtVecMultType
      // en fait cela marche en remplaçant b par a directement
      this->BlocGeneEtVecMultType::operator=(b);
      // puis les valeurs propres 
      champ = a.champ;
      return *this;
    };

    
istream & operator >> (istream & entree, BlocScalVecTypeCharge & coo)
  { // tout d'abord la classe mère
    entree >> ((BlocGeneEtVecMultType&)(coo));
    // puis les valeurs propres
    string toto; 
    entree >> toto >> coo.champ ;
    return entree;      
  };
  
ostream & operator << ( ostream & sort,const  BlocScalVecTypeCharge & coo)
  { // tout d'abord la classe mère
    sort << ((BlocGeneEtVecMultType&)(coo));
    // puis les valeurs propres 
    sort << "\n champ: " << coo.champ << endl;
    return sort;
  };

//------------ cas des torseurs de forces ponctuelles ------------

istream & operator >> (istream & entree, PTorseurPonct & a)
    { entree >> ((BlocGen&)(a));
      string nom;string mot_cle;
      entree >> nom >> a.Re >> nom >> a.Mo;
      // lecture éventuelle d'une fonction nD sur la résultante
      entree >> nom >> mot_cle;
      if (mot_cle != "_") {a.nom_fnD_Re = mot_cle;}
      else                {a.nom_fnD_Re = "";a.fnD_Re=NULL;}
       // idem pour le moment
      entree >> nom >> mot_cle;
      if (mot_cle != "_") {a.nom_fnD_Mo = mot_cle;}
      else                {a.nom_fnD_Mo = "";a.fnD_Mo=NULL;}
      // le centre
      entree >> nom >> a.type_centre;
      switch (a.type_centre)
         {case 1: {entree >> nom;a.nom_fnD_Ce = "";a.fnD_Ce=NULL; break;}
          case 2: {entree >> nom >> a.nom_fnD_Ce; break;}
          case 3: {entree >> nom >> a.nom_mail_ref_pour_Ce
                          >> nom >> a.num_noeud ;
                   break;
                  }
          case 4: {entree >> nom >> mot_cle >> a.nom_mail_ref_pour_Ce
                          >> nom >> a.nom_ref_pour_Ce;
                   break;
                  }
          default: break;
         };
      // fonction poids
      entree >> nom >> mot_cle;
      if (mot_cle != "_") {a.nom_fnD_poids = mot_cle;}
      else                {a.nom_fnD_poids = "";a.fnD_poids=NULL;}

      return entree;
    };
       // surcharge de l'operator d'ecriture
ostream & operator << (ostream & sort, const PTorseurPonct & a)
   { sort << ((const BlocGen&)(a));
     sort << "\n TORSEUR_PONCT__Re= " << a.Re << " Mo= " << a.Mo;
     if (a.nom_fnD_Re.length())
          {sort << " nom_fnD_Re= "<< a.nom_fnD_Re << " ";}
     else {sort << " nom_fnD_Re= _ ";};
       // idem pour le moment
     if (a.nom_fnD_Mo.length())
          {sort  << " nom_fnD_Mo= " << a.nom_fnD_Mo;}
     else {sort  << " nom_fnD_Mo= _ ";};
     // le centre
     sort << " type_centre= " << a.type_centre;
     switch (a.type_centre)
         {case 1: sort << " centre_fixe: "; break;
          case 2: {sort << " Fonction_nD_centre_: "
                        << " nom_fnD_Ce= " << a.nom_fnD_Ce;
                   break;
                  }
          case 3: {sort << " centre_noeud:_nom_mail_ref_pour_Ce= "
                        << a.nom_mail_ref_pour_Ce
                        << " num_noeud= " << a.num_noeud ;
                   break;
                  }
          case 4: {sort << " centre_de_gravite_d'un_groupe_de_noeuds: "
                        << " nom_mail_ref_pour_Ce= " << a.nom_mail_ref_pour_Ce
                        << " nom_ref_pour_Ce= " << a.nom_ref_pour_Ce;
                   break;
                  }
          default: break;
         };
     if (a.nom_fnD_poids.length())
          {sort  << " nom_fnD_poids= " << a.nom_fnD_poids;}
     else {sort  << " nom_fnD_poids= _ ";};
     return sort;
  };

//Constructeur par défaut
PTorseurPonct::PTorseurPonct() :
  BlocGen(1,0) // 1 nom = nom de la ref
  ,Re(ParaGlob::Dimension()),nom_fnD_Re(""),fnD_Re(NULL)
  ,Mo(ParaGlob::Dimension()),nom_fnD_Mo(""),fnD_Mo(NULL)
  ,Ce(ParaGlob::Dimension()),fnD_Ce(NULL),nom_fnD_Ce("")
  ,noe_Ce(NULL),temps_noe_Ce(TEMPS_0),nom_ref_pour_Ce("")
  ,nom_mail_ref_pour_Ce(""),tab_noe_ref_centre(),type_centre(1)
  ,nom_fnD_poids(""),fnD_poids(NULL),t_poids(),t_vec()
   {};

// constructeur de copie
PTorseurPonct::PTorseurPonct (const PTorseurPonct & a):
  BlocGen(a) // 1 nom = nom de la ref
  ,Re(a.Re),nom_fnD_Re(a.nom_fnD_Re),fnD_Re(a.fnD_Re),Mo(a.Mo),nom_fnD_Mo(a.nom_fnD_Mo)
  ,fnD_Mo(a.fnD_Mo),Ce(a.Ce),fnD_Ce(a.fnD_Ce),nom_fnD_Ce(a.nom_fnD_Ce)
  ,noe_Ce(a.noe_Ce),temps_noe_Ce(a.temps_noe_Ce),nom_ref_pour_Ce(a.nom_ref_pour_Ce)
  ,nom_mail_ref_pour_Ce(a.nom_mail_ref_pour_Ce)
  ,tab_noe_ref_centre(a.tab_noe_ref_centre),type_centre(a.type_centre)
  ,nom_fnD_poids(a.nom_fnD_poids),fnD_poids(a.fnD_poids),t_poids(a.t_poids),t_vec()
   {};

// surcharge d'affectation
PTorseurPonct& PTorseurPonct::operator = (const  PTorseurPonct& a)
 { BlocGen* b = ((BlocGen* ) this);
//   const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
   (*b) = a; // affectation des grandeurs de bloc gen
   Re = a.Re; nom_fnD_Re = a.nom_fnD_Re; fnD_Re = a.fnD_Re; Mo = a.Mo; nom_fnD_Mo = a.nom_fnD_Mo;
   fnD_Mo = a.fnD_Mo; Ce = a.Ce; fnD_Ce = a.fnD_Ce; nom_fnD_Ce = a.nom_fnD_Ce;
   noe_Ce = a.noe_Ce; temps_noe_Ce = a.temps_noe_Ce; nom_ref_pour_Ce = a.nom_ref_pour_Ce;
   nom_mail_ref_pour_Ce = a.nom_mail_ref_pour_Ce;
   tab_noe_ref_centre = a.tab_noe_ref_centre; type_centre = a.type_centre;
   nom_fnD_poids=a.nom_fnD_poids;fnD_poids = a.fnD_poids;
   t_poids.Change_taille(a.t_poids.Taille());
   t_vec.Change_taille(a.t_vec.Taille());
   return *this;
 };

// surcharge de l'operateur d'égalité
bool PTorseurPonct::operator == (const PTorseurPonct& a) const
 { BlocGen* b = ((BlocGen* ) this);
   if ( ((*b) == a)
       && (Re == a.Re) && (nom_fnD_Re == a.nom_fnD_Re) && (fnD_Re == a.fnD_Re) && (Mo == a.Mo)
       && (nom_fnD_Mo == a.nom_fnD_Mo) && (fnD_Mo == a.fnD_Mo) && (Ce == a.Ce) && (fnD_Ce == a.fnD_Ce)
       && (nom_fnD_Ce == a.nom_fnD_Ce) && (noe_Ce == a.noe_Ce) && (temps_noe_Ce == a.temps_noe_Ce)
       && (nom_fnD_poids == a.nom_fnD_poids)&&(fnD_poids == a.fnD_poids)
       && (nom_ref_pour_Ce == a.nom_ref_pour_Ce) && (nom_mail_ref_pour_Ce == a.nom_mail_ref_pour_Ce)
       && (tab_noe_ref_centre == a.tab_noe_ref_centre) && (type_centre == a.type_centre)
      )
     return true;
    else
     return false;
 };

// lecture d'un bloc
void PTorseurPonct::Lecture(UtilLecture & entreePrinc)
 { BlocGen* b = ((BlocGen* ) this);
   // on commence par lire le bloc gen, ce qui correspondra à la ref
   b->Lecture(entreePrinc);
   // arrivée ici le nom de maillage puis celui de la ref sont lue
   // lecture du mot clé
   string nom_charge;
   string nom_class_methode(" PTorseurPonct::Lecture(");
   string mot_cle("TORSEUR_PONCT");
   // 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
   entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
  
   //------- lecture de la résultante ----
   // idem pour le mot clé R=
   mot_cle="Re=";
   entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
   // maintenant on fait le choix entre valeur ou fonction nD
   if (strstr(entreePrinc.tablcar,"Fonction_nD_Re:")!=NULL)
        {// cas d'une fonction nD, on se positionne sur le mot clé
         string titi4; bool bonnefin4=false;
         while ((!entreePrinc.entree->rdstate())&& // lecture tant qu'il n'y a pas d'erreur
                        (!(entreePrinc.entree->eof())))
             { // lecture du prochain mot
              *(entreePrinc.entree) >> titi4 ;
              if (titi4 == "Fonction_nD_Re:"){bonnefin4=true; break;};
             };
         if (!bonnefin4)
            {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD pour la resultante ";
             cout << "\n PTorseurPonct::Lecture(.. " << endl ;
             entreePrinc.MessageBuffer("**erreur**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
            }
         else
             //lecture du nom de la fonction nD
            { *(entreePrinc.entree) >> nom_fnD_Re; };
        } //-- fin récup de la fonction de charge
   else // sinon on lit directement les coordonnées de la résultante
    { Re.Lecture(entreePrinc);};
  
   //------- lecture du moment ----
   // idem pour le mot clé M=
   mot_cle="Mo=";
   entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
   // maintenant on fait le choix entre valeur ou fonction nD
   if (strstr(entreePrinc.tablcar,"Fonction_nD_Mo:")!=NULL)
        {// cas d'une fonction nD, on se positionne sur le mot clé
         string titi4; bool bonnefin4=false;
         while ((!entreePrinc.entree->rdstate())&& // lecture tant qu'il n'y a pas d'erreur
                        (!(entreePrinc.entree->eof())))
             { // lecture du prochain mot
              *(entreePrinc.entree) >> titi4 ;
              if (titi4 == "Fonction_nD_Mo:"){bonnefin4=true; break;};
             };
         if (!bonnefin4)
            {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD pour le moment ";
             cout << "\n PTorseurPonct::Lecture(.. " << endl ;
             entreePrinc.MessageBuffer("**erreur**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
            }
         else
             //lecture du nom de la fonction nD
            { *(entreePrinc.entree) >> nom_fnD_Mo; };
        } //-- fin récup de la fonction de charge
   else // sinon on lit directement les coordonnées du moment
    { Mo.Lecture(entreePrinc);};
  
   //------- lecture du centre ----
   // idem pour le mot clé centre_=
   mot_cle="centre_=";
   entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
   // maintenant on fait le choix entre valeur, fonction nD, noeud, groupe de noeud
   //  1) cas d'une fonction nD décrivant le centre
   if (strstr(entreePrinc.tablcar,"Fonction_nD_centre_:")!=NULL)
        {// cas d'une fonction nD, on se positionne sur le mot clé
         string titi4; bool bonnefin4=false;
         while ((!entreePrinc.entree->rdstate())&& // lecture tant qu'il n'y a pas d'erreur
                        (!(entreePrinc.entree->eof())))
             { // lecture du prochain mot
              *(entreePrinc.entree) >> titi4 ;
              if (titi4 == "Fonction_nD_centre_:"){bonnefin4=true; break;};
             };
         if (!bonnefin4)
            {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD pour le centre d'application du moment ";
             cout << "\n PTorseurPonct::Lecture(.. " << endl ;
             entreePrinc.MessageBuffer("**erreur**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
            }
         else
             //lecture du nom de la fonction nD
            { *(entreePrinc.entree) >> nom_fnD_Ce; };
         type_centre = 2;
        } //-- fin récup de la fonction de charge
   //  2) cas d'un noeud  décrivant le centre
   else if (strstr(entreePrinc.tablcar,"centre_noeud_=")!=NULL)
        { // cas d'un centre donné par un numero de noeud
          mot_cle="centre_noeud_=";
          entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
          string nom_mail;
          *(entreePrinc.entree) >> nom_mail;
          if (nom_mail == "nom_mail=")
              { // cas où il y a un nom de maillage
                *(entreePrinc.entree) >> nom_mail_ref_pour_Ce; // lecture du nom
                *(entreePrinc.entree) >> num_noeud; // lecture du numero de noeud
              }
          else
           { // sinon cela veut dire que l'on vient de lire un numéro de noeud du premier maillage
             nom_mail_ref_pour_Ce = "";
             num_noeud = ChangeEntier(nom_mail);
           };
          // puis on lit le temps pour lequel on considère les coordonnées du noeud:
          string dure;
          *(entreePrinc.entree) >> dure;
          temps_noe_Ce = Id_nom_dure (dure);
          type_centre = 3;
         }
   //  3) cas du centre de gravité d'une ref de noeuds
   else if (strstr(entreePrinc.tablcar,"centre_gravite_ref_=")!=NULL)
        { // cas d'un centre donné par un centre de gravité d'une ref de noeuds
          mot_cle="centre_gravite_ref_=";
          entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
          string nom_mail;
          *(entreePrinc.entree) >> nom_mail;
          if (nom_mail == "nom_mail=")
              { // cas où il y a un nom de maillage
                *(entreePrinc.entree) >> nom_mail_ref_pour_Ce; // lecture du nom
                *(entreePrinc.entree) >> nom_ref_pour_Ce; // lecture du nom de la ref de noeud
              }
          else
           { // sinon cela veut dire que l'on vient de lire la référence de noeud du premier maillage
             nom_mail_ref_pour_Ce = "";
             nom_ref_pour_Ce = nom_mail;
           };
          // puis on lit le temps pour lequel on considère les coordonnées du noeud:
          string dure;
          *(entreePrinc.entree) >> dure;
          temps_noe_Ce = Id_nom_dure (dure);
          type_centre = 4;
         }
   //  4) cas du centre de gravité fixe
   else // on lit directement les coordonnées
    { Ce.Lecture(entreePrinc);
      type_centre=1;
    };
  
   //------- lecture d'une fonction poids éventuelle moment ----

   if (strstr(entreePrinc.tablcar,"Fonction_nD_Poids:")!=NULL)
        {// cas d'une fonction nD, on se positionne sur le mot clé
         string titi4; bool bonnefin4=false;
         while ((!entreePrinc.entree->rdstate())&& // lecture tant qu'il n'y a pas d'erreur
                        (!(entreePrinc.entree->eof())))
             { // lecture du prochain mot
              *(entreePrinc.entree) >> titi4 ;
              if (titi4 == "Fonction_nD_Poids:"){bonnefin4=true; break;};
             };
         if (!bonnefin4)
            {cout << "\n erreur de syntaxe en lecture du nom de la fonction nD pour la repartition de poids ";
             cout << "\n PTorseurPonct::Lecture(.. " << endl ;
             entreePrinc.MessageBuffer("**erreur**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
            }
         else
             //lecture du nom de la fonction nD
            { *(entreePrinc.entree) >> nom_fnD_poids; };
        } //-- fin récup de la fonction de charge
   else // sinon on vide le nom
    { nom_fnD_poids="";};
  
//nom_mail= petit_prisme  N_bas_arriere TORSEUR_PONCT Re= 10 0 0 \
//    Mo= 0 0 0 centre_= 45 45 1070

 };

// mise en place de l'association des fonctions nD, dont ensuite on garde un pointeur
// en retour indique si l'association est ok
bool PTorseurPonct::Mise_en_place_des_fonction_nD(const LesFonctions_nD& lesFonctionsnD)
{ bool retour = true;
  // on regarde et on récupère s'il le faut la fct nD associée avec la résultante du torseur
  if (nom_fnD_Re.length())
    {fnD_Re = lesFonctionsnD.Trouve(nom_fnD_Re);
     int dima = ParaGlob::Dimension();
     if (fnD_Re != NULL)
      {// on vérifie qu'en retour on a un vecteur de dimension = la dimension de l'espace
       if (fnD_Re->NbComposante() != dima)
         {cout << "\n *** erreur dans  l'utilisation d'une fonction nD avec grandeur(s) globale(s)"
               << " cas du calcul de la resultante d'un torseur"
               << " en retour, le nombre de composante"<< fnD_Re->NbComposante()
               << " est different de la dimension de l'espace : "
               << dima << endl;
          Sortie(1);
         };
      };
    };
  // idem pour le moment
  if (nom_fnD_Mo.length())
    {fnD_Mo = lesFonctionsnD.Trouve(nom_fnD_Mo);
     int dima = ParaGlob::Dimension();
     if (fnD_Mo != NULL)
      {// on vérifie qu'en retour on a un vecteur de dimension = la dimension de l'espace
       if (fnD_Mo->NbComposante() != dima)
         {cout << "\n *** erreur dans  l'utilisation d'une fonction nD avec grandeur(s) globale(s)"
               << " cas du calcul du moment d'un torseur"
               << " en retour, le nombre de composante"<< fnD_Mo->NbComposante()
               << " est different de la dimension de l'espace : "
               << dima << endl;
          Sortie(1);
         };
      };
    };
  // idem pour le centre
  if (nom_fnD_Ce.length())
    {fnD_Ce = lesFonctionsnD.Trouve(nom_fnD_Ce);
     int dima = ParaGlob::Dimension();
     if (fnD_Ce != NULL)
      {// on vérifie qu'en retour on a un vecteur de dimension = la dimension de l'espace
       if (fnD_Ce->NbComposante() != dima)
         {cout << "\n *** erreur dans  l'utilisation d'une fonction nD avec grandeur(s) globale(s)"
               << " cas du calcul du centre d'un torseur"
               << " en retour, le nombre de composante"<< fnD_Ce->NbComposante()
               << " est different de la dimension de l'espace : "
               << dima << endl;
          Sortie(1);
         };
      };
     if (  (type_centre == 1) // 1 c'est la valeur par défaut
         ||(type_centre == 2)
        )
       {type_centre = 2;}
     else // cas pb
      {cout << "\n erreur de definition du centre de calcul du moment (torseur ponctuel) ";
       cout << " le centre a deja ete defini comme :";
       switch (type_centre)
         {case 3: cout << " centre noeud "; break;
          case 4: cout << " centre de gravite d'un groupe de noeuds "; break;
          default: break;
         };
      retour=false;
      };
    };
  if (nom_fnD_poids.length())
    {fnD_poids = lesFonctionsnD.Trouve(nom_fnD_poids);
     if (fnD_poids != NULL)
      {// on vérifie qu'en retour on a un vecteur de dimension = 1
       if (fnD_poids->NbComposante() != 1)
         {cout << "\n *** erreur dans  l'utilisation d'une fonction nD avec grandeur(s) globale(s)"
               << " cas du calcul des poids aux points, pour le centre de gravite  d'un torseur"
               << " en retour, le nombre de composante"<< fnD_poids->NbComposante()
               << " est different de 1 ! " << endl;
          Sortie(1);
         };
      };
    };
  // la méthode de la fonction mère n'existe pas donc rien d'autre à faire
 
  return retour;
};

// mise en place des infos pour le centre si celui-ci dépend des noeuds
// en retour indique si c'est ok
bool PTorseurPonct::Def_tab_noeud_pour_centre(const list <const Noeud * > li_noe_ref_centre)
  {bool retour = true;
   // on initialise à partir de la liste
   tab_noe_ref_centre.Init_from_list(li_noe_ref_centre);
   int nbn = tab_noe_ref_centre.Taille();
   t_poids.Change_taille(nbn);
   t_vec.Change_taille(nbn);
   if ((type_centre == 2) && (tab_noe_ref_centre.Taille() != 0))
    {cout << "\n erreur de definition du centre de calcul du moment (torseur ponctuel) ";
      cout << " le centre a deja ete defini comme : fonction nD ";
      retour=false;
    }
   else if (tab_noe_ref_centre.Taille() != 0)
     {if (tab_noe_ref_centre.Taille()==1)
        { type_centre = 3;
          noe_Ce=tab_noe_ref_centre(1);
        }
      else
        { type_centre = 4;};
     };
  return retour;
 };

// calcul éventuel et retour de la résultante (qui peut varier)
// M: indique un point dont peut dépendre les éléments du torseur
Coordonnee& PTorseurPonct::Resultante(const Coordonnee& M )
  {int dima = ParaGlob::Dimension();
   if (fnD_Re != NULL)
      {if (fnD_Re->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          { Tableau <double> & tava = fnD_Re->Valeur_pour_variables_globales(); // pour simplifier
            switch (dima)
                   { case 3 : Re(3) = tava(3);
                     case 2 : Re(2) = tava(2);
                     case 1 : Re(1) = tava(1);
                   };
          }
       else if (fnD_Re->Depend_M() != 0) // signifie qu'il y a une dépendance au point M
          { if (fnD_Re->Depend_M()<0)
             {// comme pt_fonct->Depend_M()<0, cela signifie que la fonction dépend que de M
              // donc dans les paramètres d'appel on ne transmet que M
              Tableau <Coordonnee> tab_M(1,M);
              Tableau <double> & tava = fnD_Re->Val_FnD_Evoluee(NULL,&tab_M,NULL); // pour simplifier
              switch (dima)
                   { case 3 : Re(3) = tava(3);
                     case 2 : Re(2) = tava(2);
                     case 1 : Re(1) = tava(1);
                   };
             }
            else
             { if ((fnD_Re->Depend_M()>0)|| fnD_Re->Nom_variables().Taille() != dima)
                 {cout << "\n *** erreur en retour de l'utilisation d'une fonction nD utilisant les coordonnees du point"
                       << " cas du calcul de la resultante d'un torseur"
                       << " actuellement la fonction doit avoir uniquement comme parametres, les coordonnees du point et/ou    eventuellement des variables globales ";
                  cout << "\n fonction nD: "; fnD_Re->Affiche();this->Affiche();
                  Sortie(1);
                 };
              };
          }
        };
   return Re;
 };

// calcul éventuel et retour du moment (qui peut varier)
// M: indique un point dont peut dépendre les éléments du torseur
Coordonnee& PTorseurPonct::Moment(const Coordonnee& M )
  {int dima = ParaGlob::Dimension();
   if (fnD_Mo != NULL)
      {if (fnD_Mo->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          { Tableau <double> & tava = fnD_Mo->Valeur_pour_variables_globales(); // pour simplifier
            switch (dima)
                   { case 3 : Mo(3) = tava(3);
                     case 2 : Mo(2) = tava(2);
                     case 1 : Mo(1) = tava(1);
                   };
          }
       else if (fnD_Mo->Depend_M() != 0) // signifie qu'il y a une dépendance au point M
          { if (fnD_Mo->Depend_M()<0)
             {// comme pt_fonct->Depend_M()<0, cela signifie que la fonction dépend que de M
              // donc dans les paramètres d'appel on ne transmet que M
              Tableau <Coordonnee> tab_M(1,M);
              Tableau <double> & tava = fnD_Mo->Val_FnD_Evoluee(NULL,&tab_M,NULL); // pour simplifier
              switch (dima)
                   { case 3 : Mo(3) = tava(3);
                     case 2 : Mo(2) = tava(2);
                     case 1 : Mo(1) = tava(1);
                   };
              }
            else
              { if ((fnD_Mo->Depend_M()>0)|| fnD_Mo->Nom_variables().Taille() != dima)
                 {cout << "\n *** erreur en retour de l'utilisation d'une fonction nD utilisant les coordonnees du point"
                       << " cas du calcul du moment d'un torseur"
                       << " actuellement la fonction doit avoir uniquement comme parametres, les coordonnees du point et eventuellement des variables globales ";
                  cout << "\n fonction nD: "; fnD_Mo->Affiche();this->Affiche();
                  Sortie(1);
                 };
              };
          }
        };
   return Mo;
 };

// calcul éventuel et retour du centre du moment (qui peut varier)
// M: indique un point dont peut dépendre les éléments du torseur
 Coordonnee& PTorseurPonct::Centre( )
 { int dima = ParaGlob::Dimension();
   switch (type_centre)
   {case 1:  break; // rien n'a faire
    case 2: // cas d'une fonction nD
      {if (fnD_Ce->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
          { Tableau <double> & tava = fnD_Ce->Valeur_pour_variables_globales(); // pour simplifier
            switch (dima)
                   { case 3 : Ce(3) = tava(3);
                     case 2 : Ce(2) = tava(2);
                     case 1 : Ce(1) = tava(1);
                   };
          }
        else
          {cout << "\n *** erreur en retour de l'utilisation d'une fonction nD utilisant les coordonnees du point"
                << " cas du calcul du centre d'un torseur"
                << " actuellement la fonction doit avoir uniquement comme parametres des variables globales ";
           cout << "\n fonction nD: "; fnD_Ce->Affiche();this->Affiche();
           Sortie(1);
          };
         break;
        }
    case 3: // cas ou il s'agit d'un noeud
        {switch (temps_noe_Ce)
           {case TEMPS_0:   Ce=noe_Ce->Coord0(); break;
            case TEMPS_t:   Ce=noe_Ce->Coord1(); break;
            case TEMPS_tdt: Ce=noe_Ce->Coord2(); break;
            default:
              break;
           };
         break;
        }
    case 4: // cas d'un centre de gravité
       { // on itère sur les noeuds du tableau
         Ce.Zero(); // init
         int nb_noe = tab_noe_ref_centre.Taille();
         switch (temps_noe_Ce)
           {case TEMPS_0:
             { for (int i=1;i<= nb_noe; i++)
                   Ce += tab_noe_ref_centre(i)->Coord0();
               // on moyenne
               Ce /= nb_noe;
               break;
             }
            case TEMPS_t:
             { for (int i=1;i<= nb_noe; i++)
                   Ce += tab_noe_ref_centre(i)->Coord1();
               // on moyenne
               Ce /= nb_noe;
               break;
             }
            case TEMPS_tdt:
             { for (int i=1;i<= nb_noe; i++)
                   Ce += tab_noe_ref_centre(i)->Coord2();
               // on moyenne
               Ce /= nb_noe;
               break;
             }
            default:
              break;
           };
         break;
       }
    default: break;
   };
  // retour
  return Ce;
 };


// affichage des informations
void PTorseurPonct::Affiche() const
  { cout << "\n TORSEUR_PONCT  Re= " << Re << " Mo= " << Mo;
    if (ParaGlob::NiveauImpression() > 3)
     { cout << "\n";
       if (nom_fnD_Re.length())
         cout << "\n nom_fnD_Re= "<< nom_fnD_Re << " ";
       // idem pour le moment
       if (nom_fnD_Mo.length())
         cout  << " nom_fnD_Mo= " << nom_fnD_Mo;
       switch (type_centre)
         {case 1: cout << " centre_fixe: "; break;
          case 2: {cout << " Fonction_nD_centre_: "
                        << " nom_fnD_Ce= " << nom_fnD_Ce;
                   break;
                  }
          case 3: {cout << " centre_noeud: nom_mail_ref_pour_Ce= "
                        << nom_mail_ref_pour_Ce
                        << " num_noeud= " << num_noeud ;
                   break;
                  }
          case 4: {cout << " centre_de_gravite_d'un_groupe_de_noeuds: "
                        << " nom_mail_ref_pour_Ce= " << nom_mail_ref_pour_Ce
                        << " nom_ref_pour_Ce= " << nom_ref_pour_Ce;
                   break;
                  }
          default: break;
         };
       if (nom_fnD_poids.length())
         cout  << " nom_fnD_poids= " << nom_fnD_poids;
     };
  };

// calcul de l'effort ponctuelle correspondant au torseur
// pour la position passée en paramètres
// M: indique un point dont peut dépendre les éléments du torseur
// tab_P: tableau des points où sont exprimés les forces équivalentes au torseur
// t_force : tableau des forces calculées, équivalentes au torseur
void PTorseurPonct::Force(const Tableau <Coordonnee >& tab_P, Tableau <Coordonnee >& t_force)
 { // on commence par calculer le centre du torseur
   // utile uniquement s'il varie
//--- debug
//cout << "\n debug PTorseurPonct::Force(.."
//     << "\n Re= "<< Re << " Mo= "<< Mo
//     << "\n tab_P= "<< tab_P
//     << flush;
//--- fin debug
   Centre();
//--- debug
//cout << "\n Ce= "<< Ce << flush;
//--- fin debug
   // puis la résultante et le moment qui peuvent dépendre du centre
   Resultante(Ce);
   Moment(Ce);
   // traitement du cas particulier d'un seul point
   int nb_Pi = tab_P.Taille();
   if (nb_Pi==1)
     {// ici on a qu'un seul point
      // -> le centre G = le point
      // par rapport à G, on ne peut pas avoir de moment
      // la résultante ne peut qu'être transférée telle quelle
      // la répartition ne sert à rien
      Coordonnee& G = tab_P(1); // le centre de gravité = le seul point
      Coordonnee CG (G-Ce);
      // on transfert le moment en G
      Coordonnee MG = Mo - Util::ProdVec_coor(CG,Re);
      // il faut que le moment soit nul
      double M_G = MG.Norme();
      if (M_G > ConstMath::petit)
        {cout << "\n *** erreur dans le calcul de la repartition du moment d'un torseur d'action,"
              << " ici il n'y a qu'un point, et le moment en se point n'est pas nul, MG= " << MG
              << " le transfert  n'est pas possible!!  ";
         this->Affiche();
         Sortie(1);
        };
      // calcul des résultantes individuelles correspondant uniquement à Re
      t_force(1) = Re;
     }
   else // la suite concerne le cas avec plusieurs points
    {int dima = ParaGlob::Dimension();
     Coordonnee G(dima);
     t_force.Change_taille(nb_Pi);
     double poids_total = 0.; // init
     if (fnD_poids == NULL)
      // si on n'a pas de fonction de répartition, cela signifie que les poids sont tous = 1
      {for (int i =1; i<= nb_Pi; i++)
         {Coordonnee& tab_P_i = tab_P(i);
          t_force(i) = Re ; // première partie du calcul de force
          G += tab_P_i ;
          poids_total += 1.;
         };
       // d'où
       double alpha = 1./poids_total;
       G *= alpha; // le centre de gravité
//--- debug
//cout << "\n debug PTorseurPonct::Force(.."
//     << "\n Re= "<< Re << " Mo= "<< Mo
//     << "\n centre G= "<< G << flush;
//--- fin debug
       Coordonnee CG (G-Ce);
       // on transfert le moment en G
       Coordonnee MG = Mo - Util::ProdVec_coor(CG,Re);
//--- debug
//cout << "\n moment MG= "<< MG << flush;
//--- fin debug
       // calcul des résultantes individuelles correspondant uniquement à Re
       for (int i =1; i<= nb_Pi; i++)
         { t_force(i) *= alpha;};
       // si le moment n'est pas nul on calcule les moments individuels
       double M_G = MG.Norme();
       t_vec.Change_taille(nb_Pi);
       if (M_G > ConstMath::petit)
        { Coordonnee m = MG/M_G;
          Coordonnee GPi,GPpi; // variables de travail
          double mom_quad = 0.;
          for (int i =1; i<= nb_Pi; i++)
           { Coordonnee& tab_P_i = tab_P(i);
             GPi = tab_P_i - G;
             GPpi = GPi - (GPi * m) * m;
             double GPpi2 = GPpi * GPpi;
             mom_quad += GPpi2 ;
             // si la norme de GPpi est trop petite, la force individuelle
             // ne pourra pas contribuer au moment
             t_vec(i) = Util::ProdVec_coor(GPpi,m);
           };
          // si le moment quadratique est nul on ne peut pas équilibrer le moment
          if (mom_quad < ConstMath::petit)
            {cout << "\n *** erreur dans le calcul de la repartition du moment d'un torseur d'action,"
                  << " vers des forces ponctuelles"
                  << " le moment quadratique est nul, on ne peut pas equilibrer le moment actuel MG= " << MG ;
             this->Affiche();
             Sortie(1);
            };
          double beta = M_G / mom_quad ; // si diff de 0.
          // on calcule la part due au moment, répartie sur les points
          for (int i =1; i<= nb_Pi; i++)
            t_force(i) -= (beta ) * t_vec(i);
        }
      } // fin du cas où il n'y a pas de fonction de poids
     else // cas avec une fonction de répartition de poids
      {int dimPlus1 = 1+ParaGlob::Dimension();
       Tableau <double> tab_d(dimPlus1);
       double& CP_i = tab_d(1); // pour simplifier
       for (int i =1; i<= nb_Pi; i++)
         {Coordonnee& tab_P_i = tab_P(i);
          Coordonnee CPi = tab_P_i - Ce;
          for (int j=1;j<dimPlus1;j++)
             tab_d(j+1) = CPi(j);
          double CP_i_2 = CPi * CPi;
          CP_i = sqrt(CP_i_2);
          Tableau <double> & tava = fnD_poids->Valeur_FnD_tab_scalaire(&tab_d);
                  //Val_FnD_Evoluee(&tab_d,NULL,NULL); // pour simplifier
          double f_opi = t_poids(i)= Dabs(tava(1));
//--- debug
//cout << "\n poids( "<< i << ")= " << f_opi << " r= " << tab_d(1) << flush;
//--- fin debug
          t_force(i) = Re * f_opi; // première partie du calcul de force
          G += tab_P(i) * f_opi;
          poids_total += f_opi;
         };
       // d'où
       double alpha = 1./poids_total;
       G *= alpha; // le centre de gravité
       Coordonnee CG (G-Ce);
       // on transfert le moment en G
       Coordonnee MG = Mo - Util::ProdVec_coor(CG,Re);
       // calcul des résultantes individuelles correspondant uniquement à Re
       for (int i =1; i<= nb_Pi; i++)
         { t_force(i) *= alpha;};
       // si le moment n'est pas nul on calcule les moments individuels
       double M_G = MG.Norme();
       if (M_G > ConstMath::petit)
        { Coordonnee m = MG/M_G;
          Coordonnee GPi,GPpi; // variables de travail
          double mom_quad = 0.;
          for (int i =1; i<= nb_Pi; i++)
           { Coordonnee& tab_P_i = tab_P(i);
             GPi = tab_P_i - G;
             GPpi = GPi - (GPi * m) * m;
             double GPpi2 = GPpi * GPpi;
             mom_quad += GPpi2 * t_poids(i);
             // si la norme de GPpi est trop petite, la force individuelle
             // ne pourra pas contribuer au moment
             t_vec(i) = Util::ProdVec_coor(GPpi,m);
           };
          // si le moment quadratique est nul on ne peut pas équilibrer le moment
          if (mom_quad < ConstMath::petit)
            {cout << "\n *** erreur dans le calcul de la repartition du moment d'un torseur d'action,"
                  << " vers des forces ponctuelles"
                  << " le moment quadratique est nul, on ne peut pas equilibrer le moment actuel MG= " << MG ;
             this->Affiche();
             Sortie(1);
            };
          double beta = M_G / mom_quad ; // si diff de 0.
          // on calcule la part due au moment, répartie sur les points
          for (int i =1; i<= nb_Pi; i++)
            t_force(i) -= (beta * t_poids(i)) * t_vec(i);
        };
      }; // fin du test sur l'existence ou non d'une fonction de poids
    }; // fin du cas où il y a plusieurs points:
  };
  

// affichage et definition interactive des commandes
// plusieurs_maillages : indique s'il y a ou pas
// renvoi : true s'il y a effectivement une écriture
bool  PTorseurPonct::Info_commande_Charges(bool plusieurs_maillages,UtilLecture & entreePrinc)
{  // ---------- définition des différents paramètres de définition du chargement ----------
   ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
   string la_sortie(" TORSEUR_PONCT "); // la chaine de caractères qui sera finalement affichée
   // on passe en revue les différents paramètres qui définissent le torseur
   bool lecture_ok=true;
   //------- lecture de la résultante ----
   string rep(" ");
   int dim = ParaGlob::Dimension();
   // Résultante:  on fait le choix entre valeur ou fonction nD
   int int_choix=0;
   while ((int_choix > 3) || (int_choix < 1))
     {cout << "\n --- definition de la resultante du torseur ---  "
           << "\n (1) (defaut)  valeur fixe: via "<<dim<<" valeurs "
           << "\n (2)  valeur via une fonction nD "
           << "\n (3 ou f )  arret "
           << "\n  ";
      // procédure de lecture avec prise en charge d'un retour chariot
      rep = lect_return_defaut(false,"1");
      Minuscules(rep);
      int_choix = ChangeEntier(rep);
      if ((rep == "f")||(int_choix == 3))
       {lecture_ok = false; break;
       };
      switch (int_choix)
       {case 1:
          {Coordonnee V(dim);
           cout << "\n coordonnee du vecteur ("<< dim << " reels) "<< endl;
           for (int i = 1; i<= dim; i++) cin  >> V(i);
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
           cout << "\n --> coordonnees lues: "; V.Affiche_1(cout);
           Re = V;
           la_sortie += " Re= ";
           for (int i = 1; i<= dim; i++)
             la_sortie += ChangeReelSTring(V(i))+" ";
          }
         break;
        case 2:
          { cout << "\n nom de la fonction nD  ? ";
            nom_fnD_Re = lect_chaine();cout << " nom lu = "<< nom_fnD_Re;
            la_sortie += " Re= Fonction_nD_Re: " + nom_fnD_Re;
          };
          break;
        default:
          {cout << "\n *** mauvais choix, vous devez donner une valeur entre 1 et 2 !"
                << "\n recommencer ";
          };
       };
     };
   // Moment:  on fait le choix entre valeur ou fonction nD
   rep =" ";int_choix=0;
   if (lecture_ok)
    while ((int_choix > 3) || (int_choix < 1))
     {cout << "\n --- definition du moment du torseur ---  "
           << "\n (1) (defaut) valeur fixe: via "<<dim<<" valeurs "
           << "\n (2)  valeur via une fonction nD "
           << "\n (3 ou f )  arret "
           << "\n  ";
      // procédure de lecture avec prise en charge d'un retour chariot
      rep = lect_return_defaut(false,"1");
      Minuscules(rep);
      int_choix = ChangeEntier(rep);
      if ((rep == "f")||(int_choix == 3))
       {lecture_ok = false; break;
       };
      switch (int_choix)
       {case 1:
          {Coordonnee V(dim);
           cout << "\n coordonnee du vecteur ("<< dim << " reels) "<< endl;
           for (int i = 1; i<= dim; i++) cin  >> V(i);
           std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
           cout << "\n --> coordonnees lues: "; V.Affiche_1(cout);
           Mo = V;
           la_sortie += " Mo= ";
           for (int i = 1; i<= dim; i++)
             la_sortie += ChangeReelSTring(V(i))+" ";
          }
         break;
        case 2:
          { cout << "\n nom de la fonction nD  ? ";
            nom_fnD_Mo = lect_chaine();cout << " nom lu = "<< nom_fnD_Mo;
            la_sortie += " Mo= Fonction_nD_Mo: " + nom_fnD_Mo;
          };
          break;
        default:
          {cout << "\n *** mauvais choix, vous devez donner une valeur entre 1 et 2 !"
                << "\n recommencer ";
          };
       };
     };
   // centre:  on fait le choix entre les différentes possibilités
   rep =" ";int_choix=0;
   if (lecture_ok)
    while ((int_choix > 5) || (int_choix < 1))
     {cout << "\n --- definition du centre du torseur ---  "
           << "\n (1) (defaut)  valeur fixe: via "<<dim<<" valeurs "
           << "\n (2)  valeur via une fonction nD "
           << "\n (3)  position d'un noeud "
           << "\n (4)  centre de gravite d'un groupe de noeuds "
           << "\n (5 ou f )  arret "
           << "\n  ";
      // procédure de lecture avec prise en charge d'un retour chariot
      rep = lect_return_defaut(false,"1");
      Minuscules(rep);
      int_choix = ChangeEntier(rep);
      if ((rep == "f")||(int_choix == 5))
       {lecture_ok = false; break;
       };
      switch (int_choix)
       {case 1:
         {Coordonnee V(dim);
          cout << "\n coordonnee du vecteur ("<< dim << " reels) "<< endl;
          for (int i = 1; i<= dim; i++) cin  >> V(i);
          std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// purge de cin
          cout << "\n --> coordonnees lues: "; V.Affiche_1(cout);
          Ce = V;
          type_centre=1;
          la_sortie += " centre_= ";
          for (int i = 1; i<= dim; i++)
             la_sortie += ChangeReelSTring(V(i))+" ";
         }
         break;
       case 2:
         { cout << "\n nom de la fonction nD de charge ? ";
           nom_fnD_Ce=lect_chaine();cout << " nom lu = "<< nom_fnD_Ce;
           la_sortie += " centre_= Fonction_nD_centre_: " + nom_fnD_Ce;
           type_centre = 2;
         }
         break;
       case 3:
         { // cas d'un centre donné par un numero de noeud
           la_sortie += " centre_= centre_noeud_= ";
           nom_mail_ref_pour_Ce = "";
           if (plusieurs_maillages)
             {cout << "\n nom du maillage contenant le noeud ? ";
              nom_mail_ref_pour_Ce = lect_chaine();
              la_sortie += " nom_mail= "+nom_mail_ref_pour_Ce;
             };
           cout << "\n numero du noeud ? ";
           num_noeud = (int) lect_double();
           la_sortie += " "+ChangeEntierSTring(num_noeud)+" ";
           string temps(" ");
           while (!Existe_nom_dure (temps))
            {cout << "\n instant auquel on considere le noeud "
                << "\n TEMPS_0 (ou) TEMPS_t (ou) TEMPS_tdt ? ";
             temps = lect_chaine();
             // on test
             if (Existe_nom_dure (temps))
              {temps_noe_Ce = Id_nom_dure(temps);
              }
             else
              {cout << "\n *** erreur, ce temps n'est pas reconnu, nouvelle valeur ? ";};
            };
           la_sortie += " "+temps+" ";
           type_centre = 3;
         }
         break;
       case 4:
         { // cas d'un centre donné par un centre de gravité d'une ref de noeuds
           la_sortie += " centre_= centre_gravite_ref_= ";
           nom_mail_ref_pour_Ce = "";
           if (plusieurs_maillages)
             {string nom_mail;
              cout << "\n nom du maillage contenant la ref de noeuds ? ";
              nom_mail_ref_pour_Ce = lect_chaine();
              la_sortie += " nom_mail= "+nom_mail_ref_pour_Ce+" ";
             };
           cout << "\n nom de la ref de noeuds ? ";
           nom_ref_pour_Ce=lect_chaine();
           la_sortie += " "+nom_ref_pour_Ce+" ";
           string temps(" ");
           while (!Existe_nom_dure (temps))
            {cout << "\n instant auquel on considere la ref de noeuds "
                << "\n TEMPS_0 (ou) TEMPS_t (ou) TEMPS_tdt ? ";
             temps=lect_chaine();
             // on test
             if (Existe_nom_dure (temps))
              {temps_noe_Ce = Id_nom_dure(temps);
              }
             else
              {cout << "\n *** erreur, ce temps n'est pas reconnu, nouvelle valeur ? ";};
            };
           la_sortie += " "+temps+" ";
           type_centre = 4;
          }
          break;
        default:
          {cout << "\n *** mauvais choix, vous devez donner une valeur entre 1 et 4 !"
                << "\n recommencer ";
          };
        };
      };
   //------- lecture d'une fonction poids éventuelle moment ----
   rep =" ";int_choix=0;nom_fnD_poids="";
   if (lecture_ok)
    while ((int_choix > 3) || (int_choix < 1))
     { cout << "\n --- definition eventuelle d'une fonction poids ---  "
            << "\n (1)  oui "
            << "\n (2) (defaut) non "
            << "\n (3 ou f )  arret "
            << "\n  ";
       // procédure de lecture avec prise en charge d'un retour chariot
       rep = lect_return_defaut(false,"2");
       Minuscules(rep);
       int_choix = ChangeEntier(rep);
       if ((rep == "f")||(int_choix == 5))
        {lecture_ok = false; break;
        };
       switch (int_choix)
        {case 1:
          { cout << "\n nom de la fonction nD  ? ";
            nom_fnD_poids=lect_chaine();cout << " nom lu = "<< nom_fnD_poids;
            la_sortie += " Fonction_nD_Poids: "+nom_fnD_poids+" ";
          };
          break;
         case 2: // on ne fait rien
          break;
         default:
          {cout << "\n *** mauvais choix, vous devez donner une valeur entre 1 et 2 !"
                << "\n recommencer ";
          };
        };
     };
   //------- écriture sur le .info de la grandeur ----
   if (lecture_ok)
     sort << la_sortie;
   return lecture_ok;

};

  
  
  
  
  
  



















