// 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-2021 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 "Fonction_nD.h"
#include <stdarg.h>     /* va_list, va_start, va_copy, va_arg, va_end */
#include "Enum_ddl.h"
#include "NevezTenseur.h"
#include "TypeQuelconqueParticulier.h"

// les différentes fonctions existantes
#include "F_nD_courbe1D.h"
#include "Fonc_scal_combinees_nD.h"
#include "Fonction_expression_litterale_nD.h"
#include "Fonction_externe_nD.h"
#include "MotCle.h"

// CONSTRUCTEURS :
// par défaut
Fonction_nD::Fonction_nD(string nom, EnumFonction_nD typ)
      : nom_variables(),t_inter_double()
      ,enu_variables_globale(),nom_ref(nom),typeFonction(typ)
      ,nom_variables_globales()
      ,tab_enu_etendu(),tab_enu_quelconque()
      ,equivalence_nom_enu_etendu_et_enu_quelconque(false)
      ,index_enu_etendu(),index_enu_quelconque()
      ,x_x_i(),x_glob(),xinter(NULL)
      ,depend_M(0),depend_Mt(0),depend_M0(0),depend_temps(0),permet_affichage(0)
      //------ grandeurs évoluées -------
      ,type_des_variables(),val_ddl_enum(),li_enu_etendu_scalaire()
      ,coor_ddl_enum(),num_dans_coor(),premier_famille_Coord()
      ,tens_ddl_enum(),ind_tens(),premier_famille_tenseur(),absolue(false)
      ,li_equi_Quel_evolue(),tab_equi_Coor(),tab_equi_tens()
      ,posi_ddl_enum(),tailles_tab()
      { // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
// non car au début il n'y a rien comme variable !!
//        Fonction_nD::Construction_index_conteneurs_evoluees();
      };

// constructeur avec plus d'info
// dans le cas ou les variables sont associées à des types quelconques, par défaut on considère qu'il
// s'agit de conteneur d'un scalaire simple. Dans le cas contraire il faut utiliser
// Preparation_Grandeur_quelconque( pour spécifier les tailles réelles
Fonction_nD::Fonction_nD(const Tableau <string >& var, string nom, EnumFonction_nD typ )
      : nom_variables(var),t_inter_double(var.Taille())
      ,enu_variables_globale(),nom_ref(nom),typeFonction(typ)
      ,nom_variables_globales()
      ,tab_enu_etendu(),tab_enu_quelconque()
      ,equivalence_nom_enu_etendu_et_enu_quelconque(false)
      ,index_enu_etendu(),index_enu_quelconque()
      ,x_x_i(),x_glob(),xinter(NULL)
      ,depend_M(0),depend_Mt(0),depend_M0(0),depend_temps(0),permet_affichage(0)
      //------ grandeurs évoluées -------
      ,type_des_variables(),val_ddl_enum(),li_enu_etendu_scalaire()
      ,coor_ddl_enum(),num_dans_coor(),premier_famille_Coord()
      ,tens_ddl_enum(),ind_tens(),premier_famille_tenseur(),absolue(false)
      ,li_equi_Quel_evolue(),tab_equi_Coor(),tab_equi_tens()
      ,posi_ddl_enum(),tailles_tab()
      {// comme on a le tableau de variables, on tente une équivalence éventuelle
//       Fonction_nD::Construction_enu_etendu_et_quelconque();
       // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
       Fonction_nD::Construction_index_conteneurs_evoluees();
      };

// def de tous les paramètres: utile pour être appelé par les classes dérivées
Fonction_nD::Fonction_nD
          ( string nom_ref_  // nom de ref de la fonction
           ,Tableau <string >& nom_variables_non_globales // les variables non globales
           ,Tableau <Enum_GrandeurGlobale >& enu_variables_globale_ // enu globaux
           ,Tableau <string >& nom_variables_globales_ // idem sous forme de strings
           ,EnumFonction_nD typ ) // le type de fonction
      : nom_variables(nom_variables_non_globales),t_inter_double(nom_variables_non_globales.Taille())
      ,enu_variables_globale(enu_variables_globale_),nom_ref(nom_ref_),typeFonction(typ)
      ,nom_variables_globales(nom_variables_globales_)
      ,tab_enu_etendu(),tab_enu_quelconque()
      ,equivalence_nom_enu_etendu_et_enu_quelconque(false)
      ,index_enu_etendu(),index_enu_quelconque()
      ,x_x_i(),x_glob(),xinter(NULL)
      ,depend_M(0),depend_Mt(0),depend_M0(0),depend_temps(0),permet_affichage(0)
      //------ grandeurs évoluées -------
      ,type_des_variables(),val_ddl_enum(),li_enu_etendu_scalaire()
      ,coor_ddl_enum(),num_dans_coor(),premier_famille_Coord()
      ,tens_ddl_enum(),ind_tens(),premier_famille_tenseur(),absolue(false)
      ,li_equi_Quel_evolue(),tab_equi_Coor(),tab_equi_tens()
      ,posi_ddl_enum(),tailles_tab()
      {// comme on a le tableau de variables, on tente une équivalence éventuelle
//       Fonction_nD::Construction_enu_etendu_et_quelconque();
       // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
       Fonction_nD::Construction_index_conteneurs_evoluees();
      };


// de copie
Fonction_nD::Fonction_nD(const Fonction_nD& Co) :
   nom_variables(Co.nom_variables),t_inter_double(Co.t_inter_double)
   ,enu_variables_globale(Co.enu_variables_globale)
   ,nom_variables_globales(Co.nom_variables_globales)
   ,nom_ref(Co.nom_ref),typeFonction(Co.typeFonction)
   ,tab_enu_etendu(Co.tab_enu_etendu),tab_enu_quelconque(Co.tab_enu_quelconque)
   ,equivalence_nom_enu_etendu_et_enu_quelconque(Co.equivalence_nom_enu_etendu_et_enu_quelconque)
   ,index_enu_etendu(Co.index_enu_etendu),index_enu_quelconque(Co.index_enu_quelconque)
   ,x_x_i(Co.x_x_i),x_glob(Co.x_glob),xinter(NULL)
   ,depend_M(Co.depend_M),depend_Mt(Co.depend_Mt),depend_M0(Co.depend_M0)
   ,depend_temps(Co.depend_temps)
   //------ grandeurs évoluées -------
   ,type_des_variables(Co.type_des_variables),val_ddl_enum(Co.val_ddl_enum)
   ,li_enu_etendu_scalaire() // reconstruit avec les index
   ,coor_ddl_enum(Co.coor_ddl_enum),num_dans_coor(Co.num_dans_coor)
   ,premier_famille_Coord(Co.premier_famille_Coord)
   ,tens_ddl_enum(Co.tens_ddl_enum),ind_tens(Co.ind_tens)
   ,premier_famille_tenseur(Co.premier_famille_tenseur)
   ,absolue(Co.absolue)
   ,li_equi_Quel_evolue(),tab_equi_Coor(),tab_equi_tens() // est reconstruit ensuite
   ,posi_ddl_enum(Co.posi_ddl_enum),tailles_tab(Co.tailles_tab)
   ,permet_affichage(Co.permet_affichage)
     {if (Co.xinter != NULL)
       xinter = new Tableau <double >(*(Co.xinter));
      // comme on a le tableau de variables, on tente une équivalence éventuelle
//      Fonction_nD::Construction_enu_etendu_et_quelconque();
      // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
      Fonction_nD::Construction_index_conteneurs_evoluees();
     };



 // DESTRUCTEUR :
 Fonction_nD::~Fonction_nD()
   {if (xinter != NULL)
      delete xinter;
    if (tens_ddl_enum.Taille() != 0)
     {int taille = tens_ddl_enum.Taille();
      for (int i=1; i<= taille; i++)
       if (tens_ddl_enum(i) != NULL)
        delete tens_ddl_enum(i);
     };
   };


    // METHODES PUBLIQUES :
    
    // ---------- non virtuelle ---------
 
 
//// complète les tableaux internes en fonction de la taille des conteneurs
//// associés aux types quelconques éventuelles
//// *** doit -être appelée s'il y a des grandeurs quelconque dont les conteneurs
//// sont associés à plusieurs scalaires
//void Fonction_nD::Preparation_Grandeur_quelconque(const Tableau <TypeQuelconque >& tqi)
// {// on parcourt la liste des enumérés de grandeurs quelconque
//  int tail = tab_enu_quelconque.Taille();
//  if (tqi.Taille() != tail)
//   { cout << "\n *** pb dans Fonction_nD::Preparation_Grandeur_quelconque( "
//          << " le tableau en parametre " << tqi.Taille()
//          << " n'a pas la meme taille que le nombre de grandeur quelconque  enregistrees "
//          << tail
//          << " on ne peut pas continuer  " <<endl;
//         Sortie(1);
//   };
//  // --- l'objectif est de dimensionner correctement le tableau de passage de réelles
//  //   x_x_i
//  int nb_scalaire_type_quelconque = 0; // init
//  for (int i=1;i<= tail; i++)
//   {nb_scalaire_type_quelconque += tqi(i).NbMaxiNumeroOrdre();
//    #ifdef MISE_AU_POINT
//    if ((tqi)(i).EnuTypeQuelconque() != tab_enu_quelconque(i))
//      { cout << "\n *** pb dans la preparation de l'utilisation de type quelconque "
//             << "  au niveau des parametres d'appel "
//             << "  la grandeur quelconque "<< i<< "correspondante a "
//             << NomTypeQuelconque((tqi)(i).EnuTypeQuelconque())
//             << " est differente de celle deja enregistree "
//             << NomTypeQuelconque(tab_enu_quelconque(i))
//             << " ce n'est pas normal !! ,  on arrete le calcul   "
//             << "\n Fonction_nD::Preparation_Grandeur_quelconque(..."<<endl;
//        Sortie(1);
//      };
//    #endif
//   };
//  // on dimensionne le tableau de passage
//  // chaque ddl est associé à un seul scalaire
//  x_x_i.Change_taille(nb_scalaire_type_quelconque+tab_enu_etendu.Taille());
// };



// calcul équivalent, mais pour des paramètres de type ddl enum étendu et/ou type quelconque
// pour que l'appel à cette méthode soit correcte, il faut que la dimension de t_enu + celle de tqi
// soit identique à celle du tableau Nom_variables() : en fait t_enu et tqi doivent représenter les variables
Tableau <double> & Fonction_nD::Valeur_FnD(Tableau <Ddl_etendu> * t_enu,Tableau <const TypeQuelconque * > * t_qi
                                           ,Tableau <int> * t_num_ordre)
  {// on se sert des tableaux d'adressage indirect pour remplir le tableau de passage
      // tab_enu_etendu(i) correspond à nom_variables(index_enu_etendu(i))
    // tab_enu_quelconque(i) correspond à nom_variables(index_enu_quelconque(i))
    // un tableau intermédiaire qui sert pour Valeur(Tableau <Ddl_etendu> ...
//    Tableau <double > x_x_i;
   #ifdef MISE_AU_POINT
   // on vérifie qu'il y a bien équivalence entre les variables
   if (!equivalence_nom_enu_etendu_et_enu_quelconque)
     { cout << "\n *** pb dans les parametres de passage pour l'appel de la fonction nD  "
            << "  les variables de passage ne sont pas tous des ddl etendue ou des grandeurs "
            << "  quelconque scalaire "
            << " ce n'est pas normal !! ,  on arrete le calcul   "
            << "\n Fonction_nD::Valeur(Tableau <Ddl_etendu>..."<<endl;
       Sortie(1);
     };
   
   #endif
 try
  {int tail_tab_enu_etendu = tab_enu_etendu.Taille();
   if (t_enu != NULL)
    {Tableau <Ddl_etendu>& tenu = *t_enu; // pour simplifier l'appel
     for (int i= 1; i<= tail_tab_enu_etendu;i++)
      {x_x_i(index_enu_etendu(i)) = tenu(i).Valeur();
     
      };
    };

   int tail_tab_enu_quelc = tab_enu_quelconque.Taille();
   if (t_qi != NULL)
    {Tableau <const TypeQuelconque * >& tqi = *t_qi; // pour simplifier l'appel
     for (int i= 1; i<= tail_tab_enu_quelc;i++)
      { x_x_i(index_enu_quelconque(i)) = tqi(i)->GrandeurNumOrdre(1);
        #ifdef MISE_AU_POINT
        int nb_scalaire_type_quelconque = tqi(i)->NbMaxiNumeroOrdre();
        if (nb_scalaire_type_quelconque != 1)
          { cout << "\n *** pb dans le nombre de parametre de passage pour l'appel de la fonction nD  "
                 << "  au niveau des parametres d'appel "
                 << "  la grandeur quelconque "<< i<< "correspondante a "
                 << (tqi)(i)->EnuTypeQuelconque().NomPlein()
                 << " n'est pas une grandeur scalaire "
                 << " ce n'est pas normal !! ,  on arrete le calcul   "
                 << "\n Fonction_nD::Valeur(Tableau <Ddl_etendu>..."<<endl;
            Sortie(1);
          };
        #endif
      };
    };
   // on peut maintenant appeler la fonction de base
   // avec que des scalaires
   #ifdef MISE_AU_POINT
   if (permet_affichage > 4)
    {cout << "\n retour fonction: "<<nom_ref<<" : ";
     Tableau <double> & inter = Valeur_FnD_interne(&x_x_i);
     int nb_val = inter.Taille();
     for (int i=1;i<=nb_val;i++)
       cout << " val("<<i<<")= "<<inter(i);
     if (permet_affichage > 5)
      {cout << "\n parametres d'appel: ";
       int nb_var = x_x_i.Taille();
       for (int j=1;j<=nb_var;j++)
         { cout << " para("<<j<<")= "<< x_x_i(j);}
      };
     return inter;
    }
   else
   #endif
   return Valeur_FnD_interne(&x_x_i);
  }
 catch (ErrSortieFinale)
      // cas d'une direction voulue vers la sortie
      // on relance l'interuption pour le niveau supérieur
    { ErrSortieFinale toto;
      throw (toto);
    }
 catch(...)
  { cout << "\n ** erreur \n Valeur_FnD(..."<<endl;
    this->Affiche();Sortie(1);
  };
 };

// ramène un pointeur sur la fonction correspondant au type de fonction passé en paramètre
Fonction_nD* Fonction_nD::New_Fonction_nD(string& nom,EnumFonction_nD typeFonction)
  {	// définition du pointeur de retour
    Fonction_nD* fonction;
    // choix en fonction du typeCourbe
    switch (typeFonction)
     {
      case FONCTION_EXPRESSION_LITTERALE_nD :
           fonction= new Fonction_expression_litterale_nD(nom); break;
      case FONCTION_COURBE1D : fonction= new F_nD_courbe1D(nom); break;
      case FONC_SCAL_COMBINEES_ND : fonction= new Fonc_scal_combinees_nD(nom); break;
      case FONCTION_EXTERNE_ND : fonction= new Fonction_externe_nD(nom); break;
      default :
          {  cout << "\nErreur : valeur incorrecte du type de Fonction_nD : "
            << typeFonction << "\n";
       cout << "\n New_Fonction_nD(EnumFonction_nD typeFonction) \n";
       Sortie(1);
        }
     };
	   return fonction;
  };
    
// ramène un pointeur sur une courbe copie de celle passée en paramètre
// IMPORTANT : il y a création d'une courbe (utilisation d'un new)
Fonction_nD* Fonction_nD::New_Fonction_nD(const Fonction_nD& Co)
  {	// définition du pointeur de retour
    Fonction_nD* fonction;
    // choix en fonction du typeFonction
    switch (Co.Type_Fonction())
      {
       case FONCTION_EXPRESSION_LITTERALE_nD : fonction= new Fonction_expression_litterale_nD( Co); break;
       case FONCTION_COURBE1D : fonction= new F_nD_courbe1D(Co); break;
       case FONC_SCAL_COMBINEES_ND : fonction= new Fonc_scal_combinees_nD(Co); break;
       case FONCTION_EXTERNE_ND : fonction= new Fonction_externe_nD(Co); break;
       default :
           {  cout << "\nErreur : valeur incorrecte du type de Fonction_nD : "
                   << Co.Type_Fonction() << "\n";
              cout << "\n New_Fonction_nD(const Fonction_nD& Co) \n";
              Sortie(1);
		         }
	     };
	   return fonction;
  };
    
// ramène la liste des identificateurs de courbes actuellement disponibles
list <EnumFonction_nD> Fonction_nD::Liste_Fonction_disponible()
  {	// définition de la liste de retour
    list <EnumFonction_nD> list_ret;
    // remplissage de la liste 
    list_ret.push_back(FONCTION_EXPRESSION_LITTERALE_nD);
    list_ret.push_back(FONCTION_COURBE1D);
    list_ret.push_back(FONC_SCAL_COMBINEES_ND);
    list_ret.push_back(FONCTION_EXTERNE_ND);
    // retour de la liste
	   return list_ret;
  };

 
// mise à jour des variables globales: en fonction de l'apparition de nouvelles variables
// globales en cours de calcul
// méthode interne: qui est utilisé par les fonctions dérivées pour la méthode:
// Mise_a_jour_variables_globales
// retourne false si rien n'a changé
bool Fonction_nD::Mise_a_jour_variables_globales_interne()
{// on passe en revue les variables normales et on regarde s'il s'agit de nouvelles variables globales
 int taille = nom_variables.Taille();
 list <string> li_variable; // liste de travail
 list <string> li_globale;  //   ""
 bool a_changer = false; // a priori rien ne change
 // maintenant on parcours les variables
 for (int i=1;i<=taille;i++)
  {if (ParaGlob::param->GrandeurGlobal(nom_variables(i)) != NULL)
    // il s'agit d'une variable globale
    {// on n'ajoute que si elle n'est pas déjà présente
     std::list <string>::iterator it
         = find (li_globale.begin(), li_globale.end(),nom_variables(i));
     if (it == li_globale.end())
       {li_globale.push_back(nom_variables(i));
       };
     // quelque soit le cas il faut valider
     a_changer=true;
    }
   else // sinon c'est toujours une variable
    li_variable.push_back(nom_variables(i));
  };
 // on met à jour les tableaux
 if (a_changer)
   {// on ajoute maintenant les variables globales déjà existantes
    int taille_globale = nom_variables_globales.Taille();  // Init_from_list
    for (int j=1;j<= taille_globale;j++)
      {// on n'ajoute que si elle n'est pas déjà présente
       list <string>::iterator it
         = find (li_globale.begin(), li_globale.end(),nom_variables_globales(j));
       if (it == li_globale.end())
          {li_globale.push_back(nom_variables_globales(j));}
      };
    // on met à jour les tableaux
    nom_variables.Init_from_list(li_variable);
    t_inter_double.Change_taille(nom_variables.Taille());
    // pour les variables globales on considère les points suivants:
    // leur nombre ne peut pas décroitre
    // l'ordre n'a pas vraiment d'importance
//    int taille_ajout = li_globale.size();
    int taille_finale = li_globale.size();
    if (taille_finale < nom_variables_globales.Taille())
     {cout << "\n erreur changement de taille des variables globales "
           << "\n Fonction_nD::Mise_a_jour_variables_globales_interne() "
           << endl;
      Sortie(1);
     };
    
    nom_variables_globales.Init_from_list(li_globale);

//    int taille_ini = nom_variables_globales.Taille();
//    nom_variables_globales.Change_taille(taille_ini+taille_ajout);
//    nom_variables_globales.Change_taille(taille_finale);
//    list <string>::iterator il,ilfin=li_globale.end();
//    int ip = 1; //taille_ini+1;
//    for (il = li_globale.begin();il != ilfin; il++,ip++)
//      nom_variables_globales(ip) = (*il);
//    nom_variables_globales.Init_from_list(li_globale);
   };
 // on met à jour le tableau d'échange interne : x_glob
 int nb_tot_glob = enu_variables_globale.Taille() + nom_variables_globales.Taille();
 x_glob.Change_taille(nb_tot_glob);
 
 // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
 Fonction_nD::Construction_index_conteneurs_evoluees();
 return a_changer;
};
//    Tableau <string > nom_variables; //variables de la fonction, vu de l'extérieur
// 
//    Tableau <Enum_GrandeurGlobale > enu_variables_globale; //tableau des énumérés
//      // de variables globales
//      // éventuellement vide s'il ne sert pas
//    Tableau <string > nom_variables_globales; //tableau des énumérés


// 2) retourne une liste de nom correspondant aux noms de courbes dont dépend *this
list <string>& Fonction_nD::ListDependanceCourbes(list <string>& lico) const
   { // par défaut, ne dépend pas de fonctions, donc on ramène une liste vide
     // ce sera surchargé dans les classes qui elles éventuellement dépendent de quelque chose
     if (lico.size() != 0)
        lico.clear();
     return lico; 
   };

// 3) retourne une liste de nom correspondant aux noms de fonctions dont dépend *this
list <string>& Fonction_nD::ListDependanceFonctions(list <string>& lico) const
   { // par défaut, ne dépend pas de fonctions, donc on ramène une liste vide
     // ce sera surchargé dans les classes qui elles éventuellement dépendent de quelque chose
     if (lico.size() != 0)
        lico.clear();
     return lico; 
   };

    // ---------- METHODES PROTEGEES :-------------------
    
// ramène true si les variables de la classe mère sont complèté
bool Fonction_nD::Complet_var() const
  { bool ret = true;
    if (typeFonction == AUCUNE_FONCTION_nD) ret = false;
    if (nom_ref == "") ret = false;
    return ret;
   };
 
// définit le paramètre depend_M en fonction des nom_variables
// 3 indicateurs permettant de connaître rapidement si
// la fonction dépend de la position d'un point M à tdt, t et t=0
// 0 : la fonction ne dépend pas de la position d'un point M
//  non nul : la fonction dépend de la position d'un point M
// dans ce cas, une au moins un des nom_variables
// a un nom de la même famille que le ddl X1
// et depend_M =  nombre de composantes demandés (ne sert pas vraiment)
// si = -1 : cela signifie que la fonction dépend "que" de M
void Fonction_nD::Definition_depend_M()
 {// on parcours les noms des variables
  int taille = nom_variables.Taille();
  depend_M=0; // init a priori
  depend_Mt=0; // idem à t
  depend_M0 = 0; // idem à 0
  Ddl_enum_etendu d_X1_t = Ddl_enum_etendu(X1,"X1_t");
  Ddl_enum_etendu d_X1_t0 = Ddl_enum_etendu(X1,"X1_t0");
  if (permet_affichage > 6)
    cout << "\n == >>> Fonction_nD::Definition_depend_M ( fct= " << nom_ref << ") ";
  
  list<string> var_X_deja_enreg; // une liste de travail
  list<string> var_independante; // une liste de travail

  for (int i=1; i<= taille; i++)
   {// on ne traite que si la variable n'a pas déjà été traité
    if (find(var_independante.begin(),var_independante.end(),nom_variables(i)) == var_independante.end())
     {var_independante.push_back(nom_variables(i));
      if (ExisteEnum_ddl(nom_variables(i))) // on regarde s'il s'agit d'un ddl patenté
       {if (permet_affichage > 7)
          cout << "\n cas d'un ddl de base: nom_variables("<<i<<") = "<<nom_variables(i);
        if ( Meme_famille(Id_nom_ddl(nom_variables(i)),X1))
         // si c'est de la famille d'X1 c'est ok, on regarde s'il ne s'agit pas d'une variable
         // déjà consultée, car nom_variables peut contenir plusieurs fois la même variable
         {if (find(var_X_deja_enreg.begin(),var_X_deja_enreg.end(),nom_variables(i)) == var_X_deja_enreg.end())
            {depend_M += 1; // ok et la variable n'a pas été encore enregistrée
             if (permet_affichage > 7)
                cout << " depend_M += 1 ";
             var_X_deja_enreg.push_back(nom_variables(i));
            };
         };
       }
      // sinon on regarde s'il s'agit d'un ddl étendu relatif à t = 0 ou t
      else if (Ddl_enum_etendu::VerifExistence(nom_variables(i)))
       { if (permet_affichage > 7)
            cout << "\n cas d'un ddl etendu relatif a t=0 ou t : nom_variables("<<i<<") = "<<nom_variables(i);
         // on a un ddl enum
         Ddl_enum_etendu dd_et = Ddl_enum_etendu::RecupDdl_enum_etendu(nom_variables(i));
         if ( Ddl_enum_etendu::PremierDdlEnumEtenduFamille(dd_et) == d_X1_t)
             // si c'est de la famille d'X1_t c'est ok, on regarde s'il ne s'agit pas d'une variable
             // déjà consultée, car nom_variables peut contenir plusieurs fois la même variable
             {if (find(var_X_deja_enreg.begin(),var_X_deja_enreg.end(),nom_variables(i)) == var_X_deja_enreg.end())
                {depend_Mt += 1;
                 if (permet_affichage > 7)
                    cout << " depend_Mt += 1 ";
                 var_X_deja_enreg.push_back(nom_variables(i)); // on peut utiliser la même liste de travail
                }
             };
         if ( Ddl_enum_etendu::PremierDdlEnumEtenduFamille(dd_et) == d_X1_t0)
             // si c'est de la famille d'X1_t0 c'est ok, on regarde s'il ne s'agit pas d'une variable
             // déjà consultée, car nom_variables peut contenir plusieurs fois la même variable
             {if (find(var_X_deja_enreg.begin(),var_X_deja_enreg.end(),nom_variables(i)) == var_X_deja_enreg.end())
                {depend_M0 += 1;
                 if (permet_affichage > 7)
                    cout << " depend_M0 += 1 ";
                 var_X_deja_enreg.push_back(nom_variables(i)); // on peut utiliser la même liste de travail
                }
             };
       };
     }
   };
  // le nombre de variables indépendantes, car nom_variables peut contenir plusieurs fois la même variable
  int nb_var_inde = var_independante.size();
  if (permet_affichage > 6)
    cout << "\n nb de variables independantes : "<< nb_var_inde << " ";
  
  // maintenant si depend_M est > à la dimension => il n'y a pas qu'une dépendance à M
//  if ((depend_M <= ParaGlob::Dimension()) && (depend_M > 0))
  if ((depend_M <= taille) && (depend_M > 0))
    {// on vérifie que l'on n'a pas utilisé plus de composantes que la dimension
     if (depend_M <= ParaGlob::Dimension())
      {if (depend_M == nb_var_inde)
        depend_M = -1; // cas d'une dépendance stricte à M
      }
     else
      { cout << "\n **** erreur le nombre de composante de dependance a M_tdt "<<taille
              << " est plus grand que la dimension " << ParaGlob::Dimension()
              << " de l'espace !! "
              << "\n Fonction_nD::Definition_depend_M() "
              << endl;
         Sortie(1);
      };
    };
  if ((depend_Mt <= taille) && (depend_Mt > 0))
    {// on vérifie que l'on n'a pas utilisé plus de composantes que la dimension
     if (depend_Mt <= ParaGlob::Dimension())
      {if (depend_Mt == nb_var_inde)
         depend_Mt = -1;// cas d'une dépendance stricte à Mt
      }
     else
      { cout << "\n **** erreur le nombre de composante de dependance a M_t"<<taille
              << " est plus grand que la dimension " << ParaGlob::Dimension()
              << " de l'espace !! "
              << "\n Fonction_nD::Definition_depend_M() "
              << endl;
         Sortie(1);
      };
    };
  if ((depend_M0 <= taille) && (depend_M0 > 0))
    {// on vérifie que l'on n'a pas utilisé plus de composantes que la dimension
     if (depend_M0 <= ParaGlob::Dimension())
      {if (depend_M0 == nb_var_inde)
         depend_M0 = -1; // cas d'une dépendance stricte à M0
      }
     else
      { cout << "\n **** erreur le nombre de composante de dependance a M_t=0 : "<<taille
             << " est plus grand que la dimension " << ParaGlob::Dimension()
             << " de l'espace !! "
             << "\n Fonction_nD::Definition_depend_M() "
             << endl;
        Sortie(1);
      };
    };
  if (permet_affichage > 6)
   {cout << "\n == >>> Fonction_nD::Definition_depend_M : valeur des indicateurs finaux "
         << "\n pour memoire: = 0 -> la fct ne depend pas de la position "
         << " = -1 : la fct depend que de la position "
         << " > 0 : la fct depend de la position mais pas seulement "
         << "\n depend_M = " << depend_M << ",depend_Mt = " << depend_Mt
         << ", depend_M0 = " << depend_M0 << " ";
   };

 };

// définit le paramètre depend_temps en fonction des nom_variables
void Fonction_nD::Definition_depend_temps()
 {// on parcours les identifiants globaux
  int taille = enu_variables_globale.Taille();
  depend_temps=false; // init a priori
  // le temps est une grandeurs globales
  for (int i=1; i<= taille; i++)
   if (enu_variables_globale(i) == TEMPS_COURANT) // on regarde s'il s'agit d'un ddl patenté
    {depend_temps = true;
     break;
    };
 };

 
//// construction à partir des noms de variables, des tableaux tab_enu_etendu et
//// tab_enu_quelconque
//void Fonction_nD::Construction_enu_etendu_et_quelconque()
// {// on parcours les noms des variables
//  int taille = nom_variables.Taille();
//  // a priori on considère qu'il y a  équivalence
//  equivalence_nom_enu_etendu_et_enu_quelconque = true;
//  list <Ddl_enum_etendu> li_inter_enu; // une liste intermédiaire de travail
//  list <int> li_index_enu;
//  list <EnumTypeQuelconque> li_inter_tyQ; // idem
//  list <int> li_index_quelc;
//
//  // un conteneur de service: un réel par ddl
//  Ddl_enum_etendu ddl_de_service;
//  // par contre pour les grandeurs quelconques, on peut avoir plusieurs
//  // réels par grandeur quelconque
//
//
//  for (int i=1; i<= taille; i++)
//   {if (ddl_de_service.VerifExistence(nom_variables(i)))
//     {li_inter_enu.push_back(Ddl_enum_etendu(nom_variables(i)));
//      li_index_enu.push_back(i);
//     }
//    else if (Existe_typeQuelconque(nom_variables(i)))
//     {li_inter_tyQ.push_back(Id_nomTypeQuelconque(nom_variables(i)));
//      li_index_quelc.push_back(i);
//     }
//    else equivalence_nom_enu_etendu_et_enu_quelconque = false  ;
//   };
//  // maintenant on peut définir les tableaux
//  int tail_enu_ddl = li_inter_enu.size();
//  { tab_enu_etendu.Change_taille(tail_enu_ddl);
//    index_enu_etendu.Change_taille(tail_enu_ddl);
//    int i_enu=1; // un compteur pour le tableau
//    list <Ddl_enum_etendu>::iterator il,ilfin=li_inter_enu.end();
//    list <int>::iterator i_int=li_index_enu.begin();
//    for (il=li_inter_enu.begin();il!=ilfin;il++,i_enu++,i_int++)
//      {tab_enu_etendu(i_enu)=(*il);
//       index_enu_etendu(i_enu)=(*i_int);
//      };
//  };
//  int tail_enuquel = li_inter_tyQ.size();
//    { tab_enu_quelconque.Change_taille(tail_enuquel);
//    index_enu_quelconque.Change_taille(tail_enuquel);
//    int i_enu=1; // un compteur pour le tableau
//    list <EnumTypeQuelconque>::iterator il,ilfin=li_inter_tyQ.end();
//    list <int>::iterator i_int=li_index_quelc.begin();
//    for (il=li_inter_tyQ.begin();il!=ilfin;il++,i_enu++,i_int++)
//      {tab_enu_quelconque(i_enu)=(*il);
//       index_enu_quelconque(i_enu) = (*i_int);
//       #ifdef MISE_AU_POINT
//       EnumTypeQuelconque inter = (*il);
//       if (NombreElementFoncDim(Type_de_grandeur_associee(inter)) != 1)
//        { cout << "\n *** pb de dimensions d'argument non coherentes !! "
//               << " la grandeur quelconque "<< NomTypeQuelconque(inter)
//               << ", n'est pas un scalaire simple "
//               << "\n Fonction_nD::Construction_enu_etendu_et_quelconque(..."<<endl;
//          Sortie(1);
//        };
//       #endif
//      };
//  };
//  // on met à jour le tableau de transfert
//  // ici par défaut chaque type quelconque est associé à un conteneur scalaire
//  // si ce n'est pas le cas, on considère que l'utilisateur utilisera la méthode
//  // Preparation_Grandeur_quelconque( pour mettre les bonnes dimensions
//  x_x_i.Change_taille(tail_enu_ddl+tail_enuquel);
// };

// Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
void Fonction_nD::Construction_index_conteneurs_evoluees()
 {// on parcours les noms des variables
  int taille = nom_variables.Taille();
  t_inter_double.Change_taille(taille);
  // on dimensionne le tableau des types de variables
  type_des_variables.Change_taille(taille);
  // on nettoie les listes
  li_enu_etendu_scalaire.clear();
  // on part avec l'idée que toutes les grandeurs seront reconnues localement
  equivalence_nom_enu_etendu_et_enu_quelconque = true;
  
  // def de listes intermédiaires
  list <int> li_inter_posi_ddl_enum; // liste des positions
  // --- cas des tenseurs
  list <TenseurBB* > li_inter_tens_ddl_enum; // pour les tenseurs
 // list <Deuxentiers_enu > li_ind_tens; // pour les indices dans les tenseurs
  List_io <Ddl_enum_etendu> li_premier_famille_tenseur; // pour savoir si c'est déjà enregistré
  // --- cas des coordonnées
  list <Coordonnee > li_coor_ddl_enum;
 // list <int > li_num_dans_coor;
  List_io <Ddl_enum_etendu> li_premier_famille_Coord; // pour savoir si c'est déjà enregistré
  // --- init de la liste équivalente de grandeurs quelconques évoluées
  li_equi_Quel_evolue.clear(); // on remet à 0
  // on défini des conteneurs ad hoc
  int dim = ParaGlob::Dimension(); // la dimension globale
  //  ... cas des Coordonnees
  Coordonnee v_rep(dim); // un vecteur de travail
  Grandeur_coordonnee grand5(v_rep); // def d'une grandeur courante coordonnée
  //  ... cas des tenseurs
  TenseurBB* tens = NevezTenseurBB(dim);  // un tenseur typique
  //   maintenant on définit une grandeur typique de type tenseurBB
  Grandeur_TenseurBB gtBB(*tens);

  
  list < int > li_position; // liste de la position des variables dans les tableaux

  // on parcours les noms de variables
  list <Ddl_enum_etendu> li_inter_enu; // une liste intermédiaire de travail
  list <int> li_index_enu;
  list <EnumTypeQuelconque> li_inter_tyQ; // idem
  list <int> li_index_quelc;
  
  // un conteneur de service: un réel par ddl
  Ddl_enum_etendu ddl_de_service;
  list <double> list_inter_val_ddl_enum; // inter qui donnera ensuite: val_ddl_enum
  // par contre pour les grandeurs quelconques, on peut avoir plusieurs
  // réels par grandeur quelconque
  int indice_enu_ddl = 0; // init
  int indice_t_quelconque = 0; // init
  for (int i=1; i<= taille; i++) // on balaie les noms de variable
    {// on sépare tout d'abord entre ddl_enum_etendu et type quelconque
     if (ddl_de_service.VerifExistence(nom_variables(i)))
     {ddl_de_service = Ddl_enum_etendu(nom_variables(i));
      li_inter_enu.push_back(ddl_de_service);
      li_index_enu.push_back(i);
      // def de la position du ddl dans le tableau final des ddl (créé à la fin)
      indice_enu_ddl++;li_inter_posi_ddl_enum.push_back(indice_enu_ddl);
      // récup du type de grandeur auquel apartient l'énumération
      // l'idée est de passer en revue le type de grandeur
      EnumTypeGrandeur enu_type_grandeur = ddl_de_service.TypeDeGrandeur();

      switch (enu_type_grandeur)
       {case SCALAIRE : case SCALAIRE_ENTIER : case SCALAIRE_DOUBLE :
         {// dans le cas d'un scalaire on a directement une équivalence à Ddl_enum_etendu
          // quelque soit le scalaire, on le stocke en double
          list_inter_val_ddl_enum.push_back(0.); // on ajoute une valeur 0. arbitraire
          li_enu_etendu_scalaire.push_back(ddl_de_service);
          type_des_variables(i)=1;
          break;
         }
        case TENSEUR : case TENSEUR_NON_SYM : case TENSEURBB : case TENSEURHH :
        case TENSEURBH : case TENSEURHB : case TENSEUR_NON_SYM_BB :
        case TENSEUR_NON_SYM_HH :
         { // on considère que c'est toujours un tenseur en absolu et par défaut c'est un tenseur BB
           type_des_variables(i)=3;
           // maintenant il faut savoir si on a déjà enregistré un tenseur qui contiend la composante
           if (!(Ddl_enum_etendu::Existe_dans_la_liste(li_premier_famille_tenseur,Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddl_de_service))))
             // s'il n'existe pas on rajoute le premier de la famille
            { TenseurBB * pt_tens= NevezTenseurBB(dim);
              li_inter_tens_ddl_enum.push_back(pt_tens);
              li_premier_famille_tenseur.push_back
                (Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddl_de_service));
              // on s'occupe de la grandeur quelconque équivalente
              EnumTypeQuelconque enuQ = Ddl_enum_etendu::Equivalent_en_grandeur_quelconque(ddl_de_service);
              TypeQuelconque typQ6(enuQ,ddl_de_service.Enum(),gtBB);
              li_equi_Quel_evolue.push_back(typQ6);
            };
//           // maintenant il faut récupérer la position = l'indice, de l'enu dans le tenseur
//           Deuxentiers_enu deux = IJind(ddl_de_service.Enum(),dim);
//           li_ind_tens.push_back(deux);
           break;
         }
        case COORDONNEE : case COORDONNEEB : case COORDONNEEH :
         {// on considère que c'est toujours un type coordonnée en absolu et par défaut c'est un Coordonnee
           type_des_variables(i)=2;
           // maintenant il faut savoir si on a déjà enregistré un Coordonnee  qui contiend la composante
           if (!(Ddl_enum_etendu::Existe_dans_la_liste(li_premier_famille_Coord,Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddl_de_service))))
             // s'il n'existe pas on rajoute le premier de la famille
            { Coordonnee  pt_coor(dim);
              li_coor_ddl_enum.push_back(pt_coor);
              li_premier_famille_Coord.push_back(Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddl_de_service));
              // on s'occupe de la grandeur quelconque équivalente
              EnumTypeQuelconque enuQ = Ddl_enum_etendu::Equivalent_en_grandeur_quelconque(ddl_de_service);
              TypeQuelconque typQ6(enuQ,ddl_de_service.Enum(),grand5);
              li_equi_Quel_evolue.push_back(typQ6);
            };
//           // maintenant il faut récupérer la position = l'indice, de l'enu dans Coordonnee
//           int indice_coor  = Indice_coor(ddl_de_service.Enum(),dim);
//           li_num_dans_coor.push_back(indice_coor);
          break;
         }
        default : // pour l'instant les autres cas, par exemple Vecteur, ne sont pas pris en compte
         cout << "\nErreur : la grandeur " << nom_variables(i)
              << " n'est pas pris en compte pour les fonctions nD  !\n";
         cout << "\n Fonction_nD::Construction_index_conteneurs_evoluees(.. \n";
         Sortie(1);
       }; // fin du switch
     } // fin du cas où c'est un ddl_enum_etendu
    else if (Existe_typeQuelconque(nom_variables(i)))
     {li_inter_tyQ.push_back(Id_nomTypeQuelconque(nom_variables(i)));
      li_index_quelc.push_back(i);
      type_des_variables(i)=4;
     }
    else
      {// il y a des variables qui ne rentrent pas dans le cadre dd enu étendu et grandeur quelconque
       // on ne pourra pas utiliser l'appel via des grandeurs évoluées: on le sauvegarde
       // pour signaler des erreurs mais  cela peut changer ensuite
       // par exemple via la transformation de variables locales en variables globales qui sont
       // dynamiquement créés, du coup on laisse l'algo
       equivalence_nom_enu_etendu_et_enu_quelconque = false  ;
       type_des_variables(i)=0;
      };
    
   };
  // on poursuit même s'il n'y a pas équivalence parfaite
  // de manière a remplacer la méthode :  Construction_enu_etendu_et_quelconque()
  // cependant s'il y a une équivalence parfaite
  //  on ne pourra pas utiliser l'appel évolué
  // donc certains indexes ne seront pas utilisables
//  if (equivalence_nom_enu_etendu_et_enu_quelconque)
    {// maintenant on va construire les tableaux qui sont équivalent aux listes
     tailles_tab.Change_taille(4);
     tailles_tab(1)=list_inter_val_ddl_enum.size();
     tailles_tab(2)=li_coor_ddl_enum.size();
     tailles_tab(3)=li_inter_tens_ddl_enum.size();
     tailles_tab(4)=li_inter_tyQ.size();
     // .... pour les ddl étendue
     // le tableau global de ddl étendu
     tab_enu_etendu.Init_from_list(li_inter_enu);
     posi_ddl_enum.Init_from_list(li_inter_posi_ddl_enum);
     
     val_ddl_enum.Init_from_list(list_inter_val_ddl_enum);
     
     coor_ddl_enum.Init_from_list(li_coor_ddl_enum);
     premier_famille_Coord.Init_from_list(li_premier_famille_Coord);
//     num_dans_coor.Init_from_list(li_num_dans_coor);
     num_dans_coor.Change_taille(tab_enu_etendu.Taille());
     
     tens_ddl_enum.Init_from_list(li_inter_tens_ddl_enum);
     premier_famille_tenseur.Init_from_list(li_premier_famille_tenseur);
//     ind_tens.Init_from_list(li_ind_tens);
     ind_tens.Change_taille(tab_enu_etendu.Taille());
     
     index_enu_etendu.Init_from_list(li_index_enu);
  
     // .... pour les grandeurs quelconques
     // le tableau global de grandeurs quelconque
     tab_enu_quelconque.Init_from_list(li_inter_tyQ);
     index_enu_quelconque.Init_from_list(li_index_quelc);
  
     // il faut maintenant revoir le tableau posi_ddl_enum dans le cas
     // ou un tenseur et/ou un Coordonnee contient plusieurs Ddl_enum_etendu
     // on fait systématiquement le test
//     if (tab_enu_etendu.Taille() > (tailles_tab(1)+tailles_tab(2)+tailles_tab(3)))
      {// on utilise les premiers de famille dont l'indice est le même que les
       // tableau de tenseur et de Coordonnee
      
       int nb_enu = tab_enu_etendu.Taille();
       for (int i=1;i<=nb_enu;i++)
        {// récup du type de grandeur auquel apartient l'énumération
         // l'idée est de passer en revue le type de grandeur
         Ddl_enum_etendu & ddenumetendu = tab_enu_etendu(i); // pour simplifier
         EnumTypeGrandeur enu_type_grandeur = ddenumetendu.TypeDeGrandeur();
         //TypeGrandeur(ddenumetendu.Enum());
         switch (enu_type_grandeur)
          {case TENSEUR : case TENSEUR_NON_SYM : case TENSEURBB : case TENSEURHH :
           case TENSEURBH : case TENSEURHB : case TENSEUR_NON_SYM_BB :
           case TENSEUR_NON_SYM_HH :
            { // on récupère la position dans le tableau de tenseur
              int position = premier_famille_tenseur.Contient
              (Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddenumetendu));
              posi_ddl_enum(i)=position;
              // maintenant il faut récupérer la position = l'indice, de l'enu dans le tenseur
              Deuxentiers_enu deux = IJind(ddl_de_service.Enum(),dim);
              ind_tens(i) = deux;
              break;
            }
           case COORDONNEE : case COORDONNEEB : case COORDONNEEH :
            { // on récupère la position dans le tableau de Coordonnee
              int position = premier_famille_Coord.Contient
              (Ddl_enum_etendu::PremierDdlEnumEtenduFamille(ddenumetendu));
              posi_ddl_enum(i)=position;
              // maintenant il faut récupérer la position = l'indice, de l'enu dans Coordonnee
              int indice_coor  = Indice_coor(ddenumetendu.Enum(),dim);
              num_dans_coor(i) = indice_coor;
              break;
            }
           default : break;// sinon c'est des scalaires
          }; // fin du switch
        };
      }; // fin du if (tab_enu_etendu.Taille() > (tailles_tab(1)+tailles_tab(2)+tailles_tab(3)))
////------- debug
//cout << "\n\n debug Fonction_nD::Construction_index_conteneurs_evoluees() : FCT= " << nom_ref
//     << "\n les variables: "<< nom_variables
//     << "\n li_equi_Quel_evolue= " << li_equi_Quel_evolue
//     << " num_dans_coor= "<<num_dans_coor;
////------- fin debug

     // .... pour les grandeurs quelconques équivalentes aux grandeurs
     //       évoluées non scalaires

     // l'ordre d'apparition dans la liste est le même que celui dans les tableaux
     // donc on parcours deux fois la liste des grandeurs, une fois pour les coordonnées et
     // une fois pour les tenseurs
     int nb_etendu = tab_enu_etendu.Taille();

     int nb_coor = coor_ddl_enum.Taille();
     tab_equi_Coor.Change_taille(nb_coor);
     int nb_tenseur = tens_ddl_enum.Taille();
     tab_equi_tens.Change_taille(nb_tenseur);
     
     List_io <TypeQuelconque >::iterator iqc,iqc_fin=li_equi_Quel_evolue.end();
     
//     cout << "\n posi_ddl_enum= " << posi_ddl_enum << endl;
  
     for (int i=1;i<=nb_etendu;i++)
       if ((type_des_variables(index_enu_etendu(i)) == 2)
         || (type_des_variables(index_enu_etendu(i)) == 3))
           {EnumTypeQuelconque enuQ =
                      Ddl_enum_etendu::Equivalent_en_grandeur_quelconque(tab_enu_etendu(i));
            TypeQuelconque tq(enuQ);
            // on cherche dans la liste enregistrée
            List_io <TypeQuelconque >::iterator result1 =
               std::find(li_equi_Quel_evolue.begin(),li_equi_Quel_evolue.end(), tq);
            if (result1 == li_equi_Quel_evolue.end())
             {cout << "\n *** erreur d'adressage dans "
                  << "Fonction_nD::Construction_index_conteneurs_evoluees()";
              this->Affiche();
              Sortie(1);
             };

            if (type_des_variables(index_enu_etendu(i)) == 2) // cas de coordonnées
                 tab_equi_Coor(posi_ddl_enum(i))=result1;
            else if (type_des_variables(index_enu_etendu(i)) == 3) // cas des tenseurs
                 tab_equi_tens(posi_ddl_enum(i))=result1;
           };
  
     delete tens; // car on n'en a plus besoin

    // on met à jour le tableau de transfert
    // ici par défaut chaque type quelconque est associé à un conteneur scalaire
    // si ce n'est pas le cas, on considère que l'utilisateur utilisera la méthode
    // Preparation_Grandeur_quelconque( pour mettre les bonnes dimensions
    x_x_i.Change_taille(tab_enu_etendu.Taille()+tab_enu_quelconque.Taille());
   }; // fin du cas où il y a une équivalence parfaite
 };


// Passage des infos variables évoluées en tableau de réels
// I/O : di
Tableau <double > & Fonction_nD::Vers_tab_double(Tableau <double > & di
                                 ,const Tableau <double >* val_ddl_enum
                                 ,const Tableau <Coordonnee> * coor_ddl_enum
                                 ,const Tableau <TenseurBB* >* tens_ddl_enum
                                 ,const Tableau <const TypeQuelconque *  >* tqi
                                 ,const Tableau <int> * t_num_ordre)
 {
    #ifdef MISE_AU_POINT
    if (di.Taille() != (tab_enu_etendu.Taille() + tab_enu_quelconque.Taille()))
      { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
             << "  tab_enu_etendu.Taille()= " << tab_enu_etendu.Taille()
             << "  tab_enu_quelconque.Taille()= "<< tab_enu_quelconque.Taille()
             << " ce n'est pas normal !! ,  on arrete le calcul   "
             << "\n Fonction_nD::Vers_tab_double(..."<<endl;
        Sortie(1);
      };
    if (tailles_tab(1) != 0) // cas où il existe des scalaires
      {if (val_ddl_enum == NULL)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  val_ddl_enum pointe sur NULL "
               << "  et il est prevu d'avoir des scalaires purs !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        }
       else
        {if (val_ddl_enum->Taille() != tailles_tab(1))
          { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
                 << "  taille val_ddl_enum  = " << val_ddl_enum->Taille()
                 << "  est different du nombre prevu !" << tailles_tab(1)
                 << " ce n'est pas normal !! ,  on arrete le calcul   "
                 << "\n Fonction_nD::Vers_tab_double(..."<<endl;
            Sortie(1);
          };
        };
      };
    if (tailles_tab(2) != 0)
      {if (coor_ddl_enum == NULL)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  coor_ddl_enum pointe sur NULL "
               << "  et il est prevu d'avoir des coordonnees !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
      };
    if (tailles_tab(3) != 0)
      {if (tens_ddl_enum == NULL)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  tens_ddl_enum pointe sur NULL "
               << "  et il est prevu d'avoir des tenseurs !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
      };
    if (tailles_tab(4) != 0)
      {if (tqi == NULL)
        { cout << "\n *** pb dans le transfert des grandeurs quelconques vers scalaires "
               << "  tqi pointe sur NULL "
               << "  et il est prevu d'avoir des grandeurs quelconques !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        }
       else if (t_num_ordre != NULL)
        {if (t_num_ordre->Taille() != tqi->Taille())
          { cout << "\n *** pb dans le transfert des grandeurs quelconques vers scalaires "
                 << "  taille tqi  = " << tqi->Taille()
                 << "  est different du nombre de numero d'ordre prevu !" << t_num_ordre->Taille()
                 << " ce n'est pas normal !! ,  on arrete le calcul   "
                 << "\n Fonction_nD::Vers_tab_double(..."<<endl;
            Sortie(1);
          };
       };
     };
    #endif
    // on va boucler sur les arguments:
    // on utilise les index, pour un adressage indirect, pour le tableau de retour "et"
    // la grandeur, normalement, cela devrait être ok
    // 1) sur les enum
    int nb_enu = index_enu_etendu.Taille();
    for (int ienu=1;ienu <= nb_enu; ienu++)
      {int num_variable = index_enu_etendu(ienu); // le numéro de nom_variable
       switch (type_des_variables(num_variable))
        { case 1: // scalaire
            {di(num_variable) = val_ddl_enum->operator()(posi_ddl_enum(ienu));
             break;}
          case 2: // Coordonnee
            {int j = posi_ddl_enum(ienu);
             di(num_variable) = (*coor_ddl_enum)(j)(num_dans_coor(ienu));
             break;}
          case 3: // tenseur
            {int j = posi_ddl_enum(ienu);
             int k = ind_tens(ienu).i; int l = ind_tens(ienu).j;
             di(num_variable) = (*(*tens_ddl_enum)(j))(k,l);
             break;}
          default:
            break;
       };
      }; // fin de la boucle sur les enum
    // 2) sur les grandeurs quelconques
    int nb_quelc = index_enu_quelconque.Taille();
    for (int ieq = 1; ieq <= nb_quelc; ieq++)
     { int num_variable = index_enu_quelconque(ieq);
       int nb_ordre = 1; // init par défaut
       if (t_num_ordre != NULL)
         nb_ordre = (*t_num_ordre)(ieq);
       di(num_variable) = (*tqi)(ieq)->GrandeurNumOrdre(nb_ordre);
     }; // fin de la boucle sur les enu quelconques
     
   // retour
   return di;
 };

// idem, mais via les listes
// val_ddl_enum(k) correspond à li_evolue_scalaire de rang i
Tableau <double > & Fonction_nD::Vers_tab_double(Tableau <double > & di
                                 ,const Tableau <double >* val_ddl_enum
                                 ,List_io <Ddl_enum_etendu>* li_evolue_scalaire
                                 ,List_io <TypeQuelconque >* li_evoluee_non_scalaire
                                 ,const Tableau <const TypeQuelconque *  >* tqi
                                 ,const Tableau <int> * t_num_ordre)
 {
    #ifdef MISE_AU_POINT
    // on vérifie qu'il s'agit bien des mêmes listes
    if ((&li_enu_etendu_scalaire) !=  li_evolue_scalaire)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  la liste des enum etendu scalaires n'est pas celle fournie par la fonction"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
    if ((&li_equi_Quel_evolue) !=  li_evoluee_non_scalaire)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  la liste des grandeurs evoluees non scalaire n'est pas celle fournie par la fonction"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
  
    if (li_enu_etendu_scalaire.size() != 0)
     {if (val_ddl_enum==NULL)
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  val_ddl_enum pointe sur NULL "
               << "  et il est prevu d'avoir "<< li_enu_etendu_scalaire.size() << " grandeurs scalaires !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
      if (val_ddl_enum->Taille() != li_enu_etendu_scalaire.size())
        { cout << "\n *** pb dans le transfert des grandeurs evoluees vers scalaires "
               << "  val_ddl_enum est de taille " << val_ddl_enum->Taille()
               << "  alors qu'il est prevu d'avoir "<< li_enu_etendu_scalaire.size() << " grandeurs scalaires !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        };
     };

    if (tailles_tab(4) != 0)
      {if (tqi == NULL)
        { cout << "\n *** pb dans le transfert des grandeurs quelconques vers scalaires "
               << "  tqi pointe sur NULL "
               << "  et il est prevu d'avoir des grandeurs quelconques !"
               << " ce n'est pas normal !! ,  on arrete le calcul   "
               << "\n Fonction_nD::Vers_tab_double(..."<<endl;
          Sortie(1);
        }
       else if (t_num_ordre != NULL)
        {if (t_num_ordre->Taille() != tqi->Taille())
          { cout << "\n *** pb dans le transfert des grandeurs quelconques vers scalaires "
                 << "  taille tqi  = " << tqi->Taille()
                 << "  est different du nombre de numero d'ordre prevu !" << t_num_ordre->Taille()
                 << " ce n'est pas normal !! ,  on arrete le calcul   "
                 << "\n Fonction_nD::Vers_tab_double(..."<<endl;
            Sortie(1);
          };
       };
     };
    #endif
    
    // on va boucler sur les arguments:
    List_io <Ddl_enum_etendu>::iterator i_scal = li_enu_etendu_scalaire.begin();
    List_io <TypeQuelconque >::iterator i_evol = li_equi_Quel_evolue.begin();
    int indice_scal=1; // init : indice dans le tableau val_ddl_enum
  
////------- debug
//cout << "\n\n debug Fonction_nD::Vers_tab_double( : FCT= " << nom_ref
//     << "\n les variables: "<< nom_variables
//     << "\n li_equi_Quel_evolue= " << li_equi_Quel_evolue
//     << " num_dans_coor= "<<num_dans_coor;
////------- fin debug
    // 1) sur les enum
    int nb_enu = index_enu_etendu.Taille();
    // qui a la même taille que tab_enu_etendu, et dans le même ordre
    for (int ienu=1;ienu <= nb_enu; ienu++)
      {int num_variable = index_enu_etendu(ienu); // le numéro de nom_variable
       switch (type_des_variables(num_variable))
        { case 1: // scalaire
            {di(num_variable) = (*val_ddl_enum)(posi_ddl_enum(ienu));
             break;}
          case 2: // Coordonnee
            {int j = posi_ddl_enum(ienu);
             // pour simplifier l'écriture
             List_io<TypeQuelconque >::iterator& il = tab_equi_Coor(j);
             Grandeur_coordonnee& coo = *((Grandeur_coordonnee*) (*il).Grandeur_pointee());
             Coordonnee& coord = *(coo.ConteneurCoordonnee());
             di(num_variable) = coord(num_dans_coor(ienu));
////------- debug
//cout << "\n num_variable= "<<num_variable
//     << " di (num_variable)= "<<di(num_variable)
//     << " num_dans_coor("<<ienu<<")= "<<num_dans_coor(ienu)
//     << "\n coord= "<<coord ;
////------- fin debug
             i_evol++;
             break;}
          case 3: // tenseur
            {int j = posi_ddl_enum(ienu);
             int k = ind_tens(ienu).i; int l = ind_tens(ienu).j;
             // pour simplifier l'écriture
             List_io<TypeQuelconque >::iterator& il = tab_equi_tens(j);
             Grandeur_TenseurBB& ten = *((Grandeur_TenseurBB*) (*il).Grandeur_pointee());
             TenseurBB& tensBB = ten.RefConteneurTenseur();
             di(num_variable) = tensBB(k,l);
             i_evol++;
             break;}
          default:
            break;
       };
      }; // fin de la boucle sur les enum
  
    // 2) sur les grandeurs quelconques
    int nb_quelc = index_enu_quelconque.Taille();
    for (int ieq = 1; ieq <= nb_quelc; ieq++)
     { int num_variable = index_enu_quelconque(ieq);
       int nb_ordre = 1; // init par défaut
       if (t_num_ordre != NULL)
         nb_ordre = (*t_num_ordre)(ieq);
       di(num_variable) = (*tqi)(ieq)->GrandeurNumOrdre(nb_ordre);
     }; // fin de la boucle sur les enu quelconques
  
////------ debug
//cout << "\n  debug  Fonction_nD::Vers_tab_double( ";
//cout << di << endl;
//
////------ fin debug

   // retour
   return di;
 };

// appel de la fonction sous forme d'une méthode avec un nombre non limité
// de paramètres: en fait utilise Valeur
// c'est une méthode avec retour uniquement en scalaire, sinon -> erreur
// calcul  des valeurs de la fonction
double Fonction_nD::Val_avec_nbArgVariable(double x,...)
  {
    // un certain nombre de variables utilisée pour gérer
    // http://www.cplusplus.com/reference/cstdarg/va_copy/
    // cf. variadic function
   
    int count = 0;
    double val = x;
    va_list vl,vl_count;
    va_start(vl,x);
   
    // on va remplir le tableau xinter, pour faire un appel classique
    int nb_var = this->NbVariable();
    if (xinter == NULL)
      xinter = new Tableau <double >(nb_var);
    if (nb_var != 0)
     {(*xinter)(count+1)=val;
      /* count number of arguments: */
      va_copy(vl_count,vl);
      while (val != 0)
       {if (count < nb_var) // cas normal
         {val=va_arg(vl_count,double);
          ++count;
          (*xinter)(count+1)=val;
         }
        else // sinon il y a plus d'argument que prévu, on génère une erreur
         { cout << "\n *** erreur dans l'appel de la fonction " << nom_ref
                << " le nombre d'argument est superieur a "<< nb_var
                << " ce qui n'est pas prevu dans la definition de la fonction "
                << "\n Fonction_nD::Val_avec_nbArgVariable( ";
           if (ParaGlob::NiveauImpression() > 1)
             this->Affiche();
           cout << endl;
           Sortie(1);
         };
       };
      va_end(vl_count);
     };
    // maintenant on peut utiliser la méthode classique
    Tableau <double> & ret = this->Valeur_FnD_interne(xinter);
    return ret(1);
  
  };

// méthode utilisée par les classes dérivées, pour transférer les infos qui sont
// gérées au niveau de Fonction_nD
Fonction_nD& Fonction_nD::Transfert_info(const Fonction_nD& elt)
{ // on reprend toutes les données gérées par Fonction_nD
  typeFonction = elt.typeFonction;
  nom_ref = elt.nom_ref;
  nom_variables = elt.nom_variables;
  t_inter_double = elt.t_inter_double;
  enu_variables_globale = elt.enu_variables_globale;
  nom_variables_globales = elt.nom_variables_globales;
  tab_enu_etendu = elt.tab_enu_etendu;
  type_des_variables = elt.type_des_variables;
  val_ddl_enum = elt.val_ddl_enum;
  li_enu_etendu_scalaire = elt.li_enu_etendu_scalaire;
  coor_ddl_enum = elt.coor_ddl_enum;
  num_dans_coor = elt.num_dans_coor;
  tens_ddl_enum = elt.tens_ddl_enum;
  premier_famille_tenseur = elt.premier_famille_tenseur;
  ind_tens = elt.ind_tens;
  posi_ddl_enum = elt.posi_ddl_enum;
  tailles_tab = elt.tailles_tab;
  tab_enu_quelconque = elt.tab_enu_quelconque;
  equivalence_nom_enu_etendu_et_enu_quelconque = elt.equivalence_nom_enu_etendu_et_enu_quelconque;
  index_enu_etendu = elt.index_enu_etendu;
  index_enu_quelconque = elt.index_enu_quelconque;
  // les listes pour les appels via les listes
  li_enu_etendu_scalaire = elt.li_enu_etendu_scalaire;
  li_equi_Quel_evolue = elt.li_equi_Quel_evolue;
  tab_equi_Coor = elt.tab_equi_Coor;
  tab_equi_tens = elt.tab_equi_tens;
 
  x_x_i = elt.x_x_i;
  x_glob = elt.x_glob;
  depend_M = elt.depend_M;
  depend_Mt = elt.depend_Mt;
  depend_M0 = elt.depend_M0;
  depend_temps = elt.depend_temps;
};


// affichage des données internes, utilisée par les fonctions dérivées
// niveau donne le degré d'affichage
void Fonction_nD::Affiche_interne(int niveau) const
 { if (niveau > 0)
    { cout << "\n type_de_fonction: "<< Nom_Fonction_nD(typeFonction)
           << "  nom_ref= " << nom_ref
           << "\n les_variables_lues: " << nom_variables ;
      if (niveau > 1)
       { // les énumérés globaux éventuels
         int taille_enu_variables_globale= enu_variables_globale.Taille();
         if (taille_enu_variables_globale != 0)
          { cout << "\n enumeres_globaux:_taille " << enu_variables_globale.Taille();
            for (int i=1;i<= taille_enu_variables_globale;i++)
              cout << " " << Nom_GrandeurGlobale(enu_variables_globale(i));
          };
         // les noms de variables globales éventuelles
         int taille_nom_variables_globales= nom_variables_globales.Taille();
         if (taille_nom_variables_globales != 0)
          { cout << "\n noms_variables_globales:_taille " << nom_variables_globales.Taille();
            for (int i=1;i<= taille_nom_variables_globales;i++)
              cout << " " << nom_variables_globales(i);
          };
         // enu étendu équivalent aux variables non globales
         int taille_tab_enu_etendu= tab_enu_etendu.Taille();
         if (taille_tab_enu_etendu != 0)
          { cout << "\n enum_etendu_locaux:_taille " << tab_enu_etendu.Taille();
            for (int i=1;i<= taille_tab_enu_etendu;i++)
              {cout << " " << tab_enu_etendu(i).Nom_plein();
               int j = posi_ddl_enum(i);
               switch (type_des_variables(i))
                {case 1: cout << " type scalaire: valeur actuelle= "
                              << val_ddl_enum(j) ;
                        break;
                 case 2: cout << " type coordonnees: valeur actuelle= "
                              << coor_ddl_enum(j)(num_dans_coor(j));
                        break;
                 case 3: cout << " type tenseur: valeur actuelle= "
                              << (*tens_ddl_enum(j))(ind_tens(j).i,ind_tens(j).j) ;
                 break;
                 default: cout << "\n type non reconnue= " << type_des_variables(i)
                               << "\n Fonction_nD::Affiche_interne( ";
                          Sortie(1);
                };
              };
            // bilan des variables évoluées
            cout << "\n il y a: "
                 << tailles_tab(1) << " scalaire(s) "
                 << tailles_tab(2) << " coordonnee(s) "
                 << tailles_tab(3) << " composante(s) de tenseur "
                 << endl;
          };
         // grandeurs quelconques équivalentes aux variables non globales
         int taille_tab_enu_quelconque= tab_enu_quelconque.Taille();
         if (taille_tab_enu_quelconque != 0)
          { cout << "\n enum_quelconque:_taille " << tab_enu_quelconque.Taille()
                 << "\n liste: ";
            for (int i=1;i<= taille_tab_enu_quelconque;i++)
              cout << NomTypeQuelconque(tab_enu_quelconque(i)) << ", ";
          };
       };
      // autres infos
      cout << "\n il y a " << this->NbComposante() << " valeur(s) en retour de la fonction ";
      if (depend_temps || depend_M || depend_Mt ||depend_M0 )
        { cout << "\n ";
          if (depend_temps)
            cout << " la fonction depend du temps,  ";
          if (depend_M || depend_Mt ||depend_M0 )
             cout << " la fonction depend du point M : ";
          if (depend_M)
            cout << " courant, ";
          if (depend_Mt)
            cout << " a t, ";
          if (depend_M0)
            cout << " a 0, ";
        };
    };
 };


//------ méthodes appelée par les classes dérivées ----
//  relatives aux données gérées par Fonction_nD
// cas donne le niveau de la récupération
// = 1 : on récupère tout
// = 2 : on récupère uniquement les données variables (supposées comme telles)
void Fonction_nD::Lect_base_info(ifstream& ent,const int cas)
{
 if (cas == 1)
    { string toto; string nom;
      // lecture des arguments
      ent >> nom >> nom_variables;
      t_inter_double.Change_taille(nom_variables.Taille());
      // les énumérés des variables globales
      ent >> nom;
      int nb_enu=0;
      ent >> nom >> nb_enu;
      enu_variables_globale.Change_taille(nb_enu);
      for (int i=1;i<= nb_enu;i++)
       { ent >> nom;
         enu_variables_globale(i) = Id_nom_GrandeurGlobale(nom);
       };
     
      // les nom des variables globales indicées en string
      ent >> nom;
      int nb_nom=0;
      ent >> nom >> nb_nom;
      nom_variables_globales.Change_taille(nb_nom);
      for (int i=1;i<= nb_nom;i++)
       { ent >> nom;
         nom_variables_globales(i) = nom;
       };
     
      // enu étendu équivalent aux variables non globales
      ent >> nom >> tab_enu_etendu;

      // grandeurs quelconques équivalentes aux variables non globales
      int taille_tab_enu_quelconque; // init
      ent >> nom >> taille_tab_enu_quelconque >> toto;
      tab_enu_quelconque.Change_taille(taille_tab_enu_quelconque);
      for (int i=1;i<= taille_tab_enu_quelconque;i++)
       {ent >> nom;
        tab_enu_quelconque(i) = Id_nomTypeQuelconque(nom);
       };
     
      // bilan des variables évoluées (on lit pour passer les infos
      // dans le .BI, mais cela va être recalculé au moment de la fabrication
      // des index
      tailles_tab.Change_taille(4);
      ent >> nom
          >> tailles_tab(1) >> nom
          >> tailles_tab(2) >> nom
          >> tailles_tab(3) >> nom
          >> tailles_tab(4) >> nom;
      ent >> nom >> permet_affichage ;

      // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
      Fonction_nD::Construction_index_conteneurs_evoluees();
    };
 };

// cas donne le niveau de sauvegarde
// = 1 : on sauvegarde tout
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Fonction_nD::Ecrit_base_info(ofstream& sort,const int cas)
{
 if (cas == 1)
    { // les variables
      sort << " \n arguments= " << nom_variables
           << " \n variables_globales_en_enumere= " ;
      int nb_enu = enu_variables_globale.Taille();
      sort << "taille " << nb_enu << "  ";
      for (int i=1;i<= nb_enu;i++)
        sort << Nom_GrandeurGlobale(enu_variables_globale(i)) << " ";
   
      sort  << " \n variables_globales_en_string= " ;
      int nb_str = nom_variables_globales.Taille();
      sort << "taille " << nb_str << "  ";
      for (int i=1;i<= nb_str;i++)
        sort << nom_variables_globales(i) << " ";

      // enu étendu équivalent aux variables non globales
      int taille_tab_enu_etendu= tab_enu_etendu.Taille();
      sort << "\n enum_etendu_locaux: " << tab_enu_etendu;

      // grandeurs quelconques équivalentes aux variables non globales
      int taille_tab_enu_quelconque= tab_enu_quelconque.Taille();
      sort << "\n enum_quelconque:_taille " << tab_enu_quelconque.Taille()
           << "\n liste: ";
      for (int i=1;i<= taille_tab_enu_quelconque;i++)
           sort << NomTypeQuelconque(tab_enu_quelconque(i)) << " ";

      // bilan des variables évoluées
      sort << "\n bilan_var_evolue_il_y_a: "
           << tailles_tab(1) << " scalaire(s) "
           << tailles_tab(2) << " coordonnee(s) "
           << tailles_tab(3) << " composante(s)_de_tenseur "
           << tailles_tab(4) << " grandeur_quelconque "
           ;
      sort << "\n permet_affichage_ "<<permet_affichage << " ";

    };
 };

// sortie du schemaXML: en fonction de enu
void Fonction_nD::SchemXML_Fonctions_nD(ofstream& sort,const Enum_IO_XML enu)
  {
 switch (enu)
 { case XML_TYPE_GLOBAUX :
  {
   break;
  }
  case XML_IO_POINT_INFO :
  {
   break;
  }
  case XML_IO_POINT_BI :
  {
   break;
  }
  case XML_IO_ELEMENT_FINI :
  {
   break;
  }
 };
  };

// lecture d'une ou plusieurs variables
// peut-être appelée plusieurs fois,
// stockage des infos dans Fonction_nD
void Fonction_nD::Lecture_variables(string& nom_lu,UtilLecture * entreePrinc)
 {
  // on lit tant que l'on ne rencontre pas une ligne contenant
  // une info ne correspondant pas à des variables    // ou un nouveau mot clé global auquel cas il y a pb !!
  MotCle motCle; // ref aux mots cle
  // on utilise des listes pour éviter les doublons
  list <Enum_GrandeurGlobale >  list_enu_variables_glob; // enum glob
  // on transvase le tableau dans la liste
  enu_variables_globale.Init_list(list_enu_variables_glob);
  // idem pour les noms globaux
  list < string> list_de_variables_nom_globales; //  string glob
  nom_variables_globales.Init_list(list_de_variables_nom_globales);
  // puis les variables qui ne sont pas globales
  list < string> list_de_variables; // liste
  nom_variables.Init_list(list_de_variables);
  
  bool lecture_effective = false; // init
  while ((   (strstr(entreePrinc->tablcar,"un_argument=")==0)
          && (strstr(entreePrinc->tablcar,"deb_list_var_")==0)
         )
        || (nom_lu == "un_argument=")
        || (nom_lu == "deb_list_var_")
       )
    {
     // si on a  un mot clé global dans la ligne courante c-a-d dans tablcar --> erreur
     if ( motCle.SimotCle(entreePrinc->tablcar))
      { cout << "\n erreur de lecture des parametre de definition d'une courbe avec expression litterale : on n'a pas trouve de mot cle relatif a une variable"
             << " et par contre la ligne courante contient un mot cle global  "
             << " *** a priori il y a une erreur de mise en donnees ! " ;
        entreePrinc->MessageBuffer("** erreur des parametres d'une fonction nD **");
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
      };
      
     // lecture d'un mot clé éventuellement
    if ((    (nom_lu != "un_argument=")
         && (nom_lu != "deb_list_var_")
        )
        || lecture_effective
       )
     *(entreePrinc->entree) >> nom_lu;
    // sinon cela veut dire que nom_lu a déjà été lu et repéré
    // relatif à une variable
    // ou que l'on vient de terminer une lecture de variabl
     
     if ((entreePrinc->entree)->rdstate() == 0)
       {} // lecture normale
     #ifdef ENLINUX
     else  if ((entreePrinc->entree)->fail())
               // on a atteind la fin de la ligne et on appelle un nouvel enregistrement
              {   // on lit sans tenir compte des < éventuelles
                  entreePrinc->NouvelleDonneeSansInf();
                  *(entreePrinc->entree) >>nom_lu;
              }
     #else
     else  if ((entreePrinc->entree)->eof())
              // la lecture est bonne mais on a atteind la fin de la ligne
              { if(nom_lu != "fin_parametres_fonction_expression_litterale_")
                  // on lit sans tenir compte des < éventuelles
                  {entreePrinc->NouvelleDonneeSansInf();
                   *(entreePrinc->entree) >> nom_lu;
                  };
              }
     #endif
     else // cas d'une erreur de lecture
      { cout << "\n erreur de lecture inconnue  ";
        entreePrinc->MessageBuffer("** erreur2 des parametres d'une courbe expression litterale**");
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
      };

 
     // cas de la lecture d'une variable
     if(nom_lu == "un_argument=")
      {*(entreePrinc->entree) >> nom_lu;
       // on regarde s'il s'agit d'une variable globale correspondant à un énuméré global
       if (EstUneGrandeurGlobale(nom_lu))
        { list_enu_variables_glob.push_back(Id_nom_GrandeurGlobale (nom_lu));}
       // idem mais sous forme d'un string
       else if (ParaGlob::param->GrandeurGlobal(nom_lu) != NULL)
        { list_de_variables_nom_globales.push_back(nom_lu);}
       else // sinon ce n'est pas une grandeur globale
        {list_de_variables.push_back(nom_lu);};
       // on signale que la lecture a été effective
       lecture_effective = true;
      }
     else if(nom_lu == "deb_list_var_") // lecture d'une liste d'argument
      {// on va lire juqu'au mot clé fin_list_var_
       int nb_boucle = 0; // indicateur pour éviter une boucle infinie
       do
        {*(entreePrinc->entree) >> nom_lu;
         if (nom_lu == "fin_list_var_")
             break;
         // on regarde s'il s'agit d'une variable globale
         if (EstUneGrandeurGlobale(nom_lu))
          { list_enu_variables_glob.push_back(Id_nom_GrandeurGlobale (nom_lu));}
         // idem mais sous forme d'un string
         else if (ParaGlob::param->GrandeurGlobal(nom_lu) != NULL)
          { list_de_variables_nom_globales.push_back(nom_lu);}
         else // sinon ce n'est pas une grandeur globale
          {list_de_variables.push_back(nom_lu);};
         nb_boucle++;
        } while (nb_boucle < 200);
       if (nb_boucle > 199)
        { cout << "\n erreur de lecture au niveau d'une liste de variable  "
               << " deb_list_var_ nom1 nom2 ... fin_list_var_";
          entreePrinc->MessageBuffer("** erreur lecture parametre d'une d'une fonction nD ** **");
          throw (UtilLecture::ErrNouvelleDonnee(-1));
          Sortie(1);
        }
       else // sinon c'est ok
        // on signale que la lecture a été effective
        lecture_effective = true;
     }
     ; // sinon rien, ce n'est plus une variable, on va donc sortir
       // du while à la suite
   }; // fin du while
  // nom_lu contient la dernière information lue qui ne correspond pas à une variable
  
  //--- maintenant on va gérer les variables lues
  
  //  on supprime les doublons dans les variables globales
  list_enu_variables_glob.sort();
  list_enu_variables_glob.unique();
  list_de_variables_nom_globales.sort();
  list_de_variables_nom_globales.unique();
  
  // on remet à jour le tableau des énumérés globaux
  enu_variables_globale.Init_from_list(list_enu_variables_glob);
  // idem pour les noms de reférence globaux
  nom_variables_globales.Init_from_list(list_de_variables_nom_globales);
  // puis pour les variables qui ne sont pas globales
  nom_variables.Init_from_list(list_de_variables);
  
  // on met à jour les tableaux internes de passage de valeurs
  x_x_i.Change_taille(nom_variables.Taille());
  x_glob.Change_taille(enu_variables_globale.Taille()+nom_variables_globales.Taille());

};


// affichage des variables de la fonction, dépend du niveau d'impression
void Fonction_nD::Affichage_variables() const
 {
  if (permet_affichage > 5)
    {  cout << "\n ---- Fonction_nD " << nom_ref  ;
       cout << "  \n arguments_specifiques= " << nom_variables
            << "  \n variables_globales_en_enumere= " ;
       int nb_enu = enu_variables_globale.Taille();
       cout << "taille " << nb_enu << "  ";
       for (int i=1;i<= nb_enu;i++)
         cout << Nom_GrandeurGlobale(enu_variables_globale(i)) << " ";
      
       cout  << "  \n variables_globales_en_string= " ;
       int nb_str = nom_variables_globales.Taille();
       cout << "taille " << nb_str << "  ";
       for (int i=1;i<= nb_str;i++)
         cout << nom_variables_globales(i) << " ";
    };

  };


// récupération des valeurs des variables globales et stockage dans le tableau
// interne x_glob
void Fonction_nD::Recup_Grandeurs_globales()
 { // --- on parcours les variables globales:
   // 1) les énumérés
   int index_glob=1;
   int tail_enu = enu_variables_globale.Taille();
   if (tail_enu>0)
    {
     // en debug on vérifie que les grandeurs globales sont présentent
     #ifdef MISE_AU_POINT
     try
      { int taille = enu_variables_globale.Taille();
        for (int i=1;i<= taille;i++)
           {// on récupère le pointeur correspondant à la grandeur
            const void* pointe =  (ParaGlob::param->GrandeurGlobal(enu_variables_globale(i)));
            if (pointe == NULL)
              { cout << "\n *** pb dans l'appel de la fonction " << nom_ref << " !! "
                     << " la variable globale  "<< Nom_GrandeurGlobale(enu_variables_globale(i))
                     << ", n'est pas disponible, on ne peut pas continuer  "
                     << "\n Fonction_nD::Recup_Grandeurs_globales(..."<<endl;
                // on génère une interruption ce qui permettra de dépiler les appels
                this->Affiche();ErrCalculFct_nD toto;throw (toto);
                Sortie(1);
              };
           };
      }
     catch (ErrSortieFinale)
          // cas d'une direction voulue vers la sortie
          // on relance l'interuption pour le niveau supérieur
        { ErrSortieFinale toto;
          throw (toto);
        }
     catch(...)
      { cout << "\n ** erreur dans l'appel de la fonction "
             << nom_ref  ;
        cout << " verifier la presence des grandeurs globales voulues "
             << "\n Fonction_nD::Recup_Grandeurs_globales(..."<<endl;
        // on génère une interruption ce qui permettra de dépiler les appels
        this->Affiche();ErrCalculFct_nD toto;throw (toto);
        Sortie(1);
      };
     #endif
     for (int i=1;i<= tail_enu;i++,index_glob++)
      {// on récupère le pointeur correspondant à la grandeur
       const void* pointe =  (ParaGlob::param->GrandeurGlobal(enu_variables_globale(i)));
       TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
       switch(gr_quelc->Grandeur_pointee()->Type_structure_grandeurAssocie())
        { case  TYPE_SIMPLE:
            { switch(gr_quelc->Grandeur_pointee()->Type_enumGrandeurParticuliere())
               {case PARTICULIER_SCALAIRE_ENTIER:
                  {Grandeur_scalaire_entier& gr
                        = *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurEntier());
                   break;
                  }
                case PARTICULIER_SCALAIRE_DOUBLE:
                  {Grandeur_scalaire_double& gr
                        = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurDouble());
                   break;
                  }
                case PARTICULIER_DDL_ETENDU:
                  {Grandeur_Ddl_etendu& gr
                        = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = (gr.GrandeurNumOrdre(1));
                   break;
                  }
                case PARTICULIER_SCALAIRE_DOUBLE_NOMMER_INDICER:
                  {Grandeur_Double_Nommer_indicer& gr
                        = *((Grandeur_Double_Nommer_indicer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurDouble());
                   break;
                  }
                default:
                  { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                         << " la variable globale  "<< Nom_GrandeurGlobale(enu_variables_globale(i))
                         << ", n'est pas prise en compte actuellement , on ne peut pas continuer  "
                         << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                         <<endl;
                    // on génère une interruption ce qui permettra de dépiler les appels
                    this->Affiche();ErrCalculFct_nD toto;throw (toto);
                    Sortie(1);
                  };
               }
            
             break;
            }
          default:
            { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                   << " la variable globale  "<< Nom_GrandeurGlobale(enu_variables_globale(i))
                   << ", n'est pas prise en compte actuellement , on ne peut pas continuer  "
                   << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                   <<endl;
              // on génère une interruption ce qui permettra de dépiler les appels
              this->Affiche();ErrCalculFct_nD toto;throw (toto);
              Sortie(1);
            };
        };
       if (permet_affichage > 5)
        {cout << "\n " << Nom_GrandeurGlobale(enu_variables_globale(i))
              << " " << x_glob(index_glob);
        };
      };
    };
   // 2) idem pour les globaux en nom c-a-d  typées sous forme de string
   int tail_nom = nom_variables_globales.Taille();
   if (tail_nom>0)
    {
     // en debug on vérifie que les grandeurs globales sont présentent
     #ifdef MISE_AU_POINT
     try
      { for (int i=1;i<= tail_nom;i++)
           {// on récupère le pointeur correspondant à la grandeur
            const void* pointe =  (ParaGlob::param->GrandeurGlobal(nom_variables_globales(i)));
            if (pointe == NULL)
              { cout << "\n *** pb dans Fonction_expression_litterale_nD " << nom_ref << " !! "
                     << " la variable globale  "<< nom_variables_globales(i)
                     << ", n'est pas disponible, on ne peut pas continuer  "
                     << "\n Fonction_nD::Recup_Grandeurs_globales(..."<<endl;
                // on génère une interruption ce qui permettra de dépiler les appels
                this->Affiche();ErrCalculFct_nD toto;throw (toto);
                Sortie(1);
              };
           };
      }
     catch (ErrSortieFinale)
          // cas d'une direction voulue vers la sortie
          // on relance l'interuption pour le niveau supérieur
        { ErrSortieFinale toto;
          throw (toto);
        }
     catch(...)
      { cout << "\n ** erreur dans l'appel de la fonction "
             << nom_ref  ;
        cout << " verifier la presence des grandeurs globales voulues "
             << "\n Fonction_nD::Recup_Grandeurs_globales(..."<<endl;
        // on génère une interruption ce qui permettra de dépiler les appels
        this->Affiche();ErrCalculFct_nD toto;throw (toto);
        Sortie(1);
      };
     #endif
     // on parcours les variables globales
     int taille = nom_variables_globales.Taille();
     for (int i=1;i<= taille;i++,index_glob++)
      {// on récupère le pointeur correspondant à la grandeur
       const void* pointe =  (ParaGlob::param->GrandeurGlobal(nom_variables_globales(i)));
       TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
       switch(gr_quelc->Grandeur_pointee()->Type_structure_grandeurAssocie())
        { case  TYPE_SIMPLE:
            { switch(gr_quelc->Grandeur_pointee()->Type_enumGrandeurParticuliere())
               {case PARTICULIER_SCALAIRE_ENTIER:
                  {Grandeur_scalaire_entier& gr
                        = *((Grandeur_scalaire_entier*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurEntier());
                   break;
                  }
                case PARTICULIER_SCALAIRE_DOUBLE:
                  {Grandeur_scalaire_double& gr
                        = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurDouble());
                   break;
                  }
                case PARTICULIER_DDL_ETENDU:
                  {Grandeur_Ddl_etendu& gr
                        = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = (gr.GrandeurNumOrdre(1));
                   break;
                  }
                case PARTICULIER_SCALAIRE_DOUBLE_NOMMER_INDICER:
                  {Grandeur_Double_Nommer_indicer& gr
                        = *((Grandeur_Double_Nommer_indicer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = *(gr.ConteneurDouble());
                   break;
                  }
                case PARTICULIER_VECTEUR_NOMMER:
                  {Grandeur_Vecteur_Nommer& gr
                        = *((Grandeur_Vecteur_Nommer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = (gr.GrandeurNumOrdre(1));
                   #ifdef MISE_AU_POINT
                   // on vérifie qu'une seule grandeur est stockée
                   if (gr.NbMaxiNumeroOrdre() > 1)
                      { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                             << " la variable globale  "<< nom_variables_globales(i)
                             << ", correspond a un vecteur a plusieur composantes, ce n'est pas pris en "
                             << " compte pour l'intant, on ne peut pas continuer  "
                             << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                             <<endl;
                        // on génère une interruption ce qui permettra de dépiler les appels
                        this->Affiche();ErrCalculFct_nD toto;throw (toto);
                        Sortie(1);
                      };
                   #endif
                   break;
                  }
                default:
                  { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                         << " la variable globale  "<< nom_variables_globales(i)
                         << ", n'est pas prise en compte actuellement , on ne peut pas continuer  "
                         << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                         <<endl;
                    // on génère une interruption ce qui permettra de dépiler les appels
                    this->Affiche();ErrCalculFct_nD toto;throw (toto);
                    Sortie(1);
                  };
               }
            
             break;
            }
          case TABLEAU_T: // valable uniquement pour les vecteur nommer
           // dans ce cas on n'utilise pour l'instant que la première valeur
            { switch(gr_quelc->Grandeur_pointee()->Type_enumGrandeurParticuliere())
               { case PARTICULIER_VECTEUR_NOMMER:
                  {Grandeur_Vecteur_Nommer& gr
                        = *((Grandeur_Vecteur_Nommer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                   x_glob(index_glob) = (gr.GrandeurNumOrdre(1));
                   #ifdef MISE_AU_POINT
                   // on vérifie qu'une seule grandeur est stockée
                   if (gr.NbMaxiNumeroOrdre() > 1)
                      { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                             << " la variable globale  "<< nom_variables_globales(i)
                             << ", correspond a un vecteur a plusieur composantes, ce n'est pas pris en "
                             << " compte pour l'intant, on ne peut pas continuer  "
                             << "\n grandeur= "<<gr<< " NbMaxiNumeroOrdre()= "<< gr.NbMaxiNumeroOrdre()
                             << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                             <<endl;
                        // on génère une interruption ce qui permettra de dépiler les appels
                        this->Affiche();ErrCalculFct_nD toto;throw (toto);
                        Sortie(1);
                      };
                   #endif
                   break;
                  }
                default:
                  { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                         << " la variable globale  "<< nom_variables_globales(i)
                         << ", n'est pas prise en compte actuellement , on ne peut pas continuer  "
                         << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                         <<endl;
                    // on génère une interruption ce qui permettra de dépiler les appels
                   this->Affiche();ErrCalculFct_nD toto;throw (toto);
                   Sortie(1);
                  };
               }
            
             break;
            }
          default:
            { cout << "\n *** pb dans dans l'appel de la fonction "<< nom_ref
                   << " la variable globale  "<< nom_variables_globales(i)
                   << ", n'est pas prise en compte actuellement , on ne peut pas continuer  "
                   << "\n Fonction_nD::Recup_Grandeurs_globales(..."
                   <<endl;
              // on génère une interruption ce qui permettra de dépiler les appels
              this->Affiche();ErrCalculFct_nD toto;throw (toto);
              Sortie(1);
            };
        };
       if (permet_affichage > 5)
        {cout << "\n " << nom_variables_globales(i)
              << " " << x_glob(index_glob);
        };
      };
    };
 
 };
































