// 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_externe_nD.h"
#include "Sortie.h"
#include "ConstMath.h"
#include "MathUtil.h"
#include "ParaGlob.h"
#include "MotCle.h"
#include "TypeQuelconqueParticulier.h"
#include "CharUtil.h"

// --- fichier pour le tube ------
#ifdef SYSTEM_MAC_OS_CARBON
  #include <types.h>
  #include <stat.h>
#else
  #include <sys/types.h>
  #include <sys/stat.h>
#endif

#include <stdio.h>
#include <fcntl.h> /* Pour O_WRONLY, etc */

#include <unistd.h>    // pour les ordres read write close


int stat(const char *path, struct stat *buf);



    // CONSTRUCTEURS :
Fonction_externe_nD::Fonction_externe_nD(string nom) :
 Fonction_nD(nom,FONCTION_EXTERNE_ND)
 ,passage(0),envoi(nom+"_envoi_Hz.FIFO"),reception(nom+"_reception_Hz.FIFO")
 ,tab_fVal(),tab_ret()

// ,ordre_troncature(2)
  {};
    
    // def de toutes les grandeurs -> donne une fonction utilisable
Fonction_externe_nD::Fonction_externe_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
          ,int nb_double_ret):  // nombre de grandeur en retour de fonction externe
     Fonction_nD(nom_ref,nom_variables_non_globales,enu_variables_globale
                 ,nom_variables_globales_,FONCTION_EXTERNE_ND )
     // ---- la partie spécifiques à la fonction externe
     ,passage(0),envoi(nom_ref+"_envoi_Hz.FIFO"),reception(nom_ref+"_reception_Hz.FIFO")
     ,tab_fVal(),tab_ret(nb_double_ret)
      {// Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
       // --> c'est déjà effectué dans le constructeur de Fonction_nD
      };

    // de copie
Fonction_externe_nD::Fonction_externe_nD(const Fonction_externe_nD& Co) :
 Fonction_nD(Co)
 ,passage(Co.passage),envoi(Co.envoi),reception(Co.reception)
 ,tab_fVal(Co.tab_fVal)
 ,tab_ret(Co.tab_ret)
  { // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
    Fonction_nD::Construction_index_conteneurs_evoluees();
  };
    // de copie à partir d'une instance générale
Fonction_externe_nD::Fonction_externe_nD(const Fonction_nD& Coo) :
 Fonction_nD(Coo)
 ,tab_fVal(),tab_ret()
  { if (Coo.Type_Fonction() != FONCTION_EXTERNE_ND)
      { cout << "\n erreur dans le constructeur de copie pour une  Fonction_externe_nD "
             << " à partir d'une instance générale ";
        cout << "\n Fonction_externe_nD::Fonction_externe_nD(const Fonction_nD& Co) ";
        Sortie(1);
      };
    // définition des données
    Fonction_externe_nD & Co = (Fonction_externe_nD&) Coo;
    tab_fVal=Co.tab_fVal;
    
    // opérations pipe
    passage = Co.passage;
    envoi = Co.envoi; reception = Co.reception;
    
    // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
    Fonction_nD::Construction_index_conteneurs_evoluees();
  };

    // DESTRUCTEUR :
Fonction_externe_nD::~Fonction_externe_nD()
  {};
    
    // METHODES PUBLIQUES :
    
    // --------- virtuelles ---------

// Surcharge de l'operateur = : realise l'egalite de deux fonctions
Fonction_nD& Fonction_externe_nD::operator= (const Fonction_nD& elt)
{ // la suite ne peut fonctionner que s'il s'agit d'une fonction de même type
  if (typeFonction != elt.Type_Fonction())
   {cout << "\n *** erreur d'affectation entre fonction nD "
         << nom_ref  << " et " << elt.NomFonction()
         << "\n Fonction_externe_nD::operator= (..."
         << endl;
    Sortie(1);
   };
  // on commence par appeler la méthode ad hoc pour la fonction Fonction_nD
  Fonction_nD::Transfert_info(elt);
  // puis on s'occupe des variables de la fonction
  const Fonction_externe_nD & Co = ((Fonction_externe_nD &) elt);
  tab_fVal=Co.tab_fVal;
  
  // opérations pipe
  passage = Co.passage;
  envoi = Co.envoi; reception = Co.reception;
  
  // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
  Fonction_nD::Construction_index_conteneurs_evoluees();

  return *this;
};

    // affichage de la courbe
void Fonction_externe_nD::Affiche(int niveau) const
  { cout << " Fonction_externe_nD " << nom_ref  ;
    cout << "  \n arguments= " << 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) << " ";
   
    cout << "\n taille vecteur de retour: "<< this->NbComposante()
         << "\n f(x)= fonction utilisateur externe, dialogue via des pipes nommes"
         << "\n pipe d'envoi:  "<< envoi << " , pipe de reception: "<< reception ;
    // appel de la méthode associée de la classe virtuelle
    Affiche_interne(niveau);
    if (niveau > 0)
     { cout << "\n derniers parametres d'appel: ";
       int nb_var = tab_fVal.Taille();
       for (int j=1;j<=nb_var;j++)
          { cout << " para("<<j<<")= "<< tab_fVal(j);}
       cout << "\n dernieres valeurs de retour de la fonction: ";
       cout << tab_ret ;
     };
    cout << "\n ----- fin fonction Fonction_externe_nD ----- ";
  };

    // vérification que tout est ok, pres à l'emploi
    // ramène true si ok, false sinon
bool Fonction_externe_nD::Complet_Fonction(bool affichage)const
 { bool ret = Complet_var(); // on regarde du coté de la classe mère tout d'abord
   // puis les variables propres
   return ret;
 } ;

    // Lecture des donnees de la classe sur fichier
    // le nom passé en paramètre est le nom de la courbe
    // s'il est vide c-a-d = "", la methode commence par lire le nom sinon
    // ce nom remplace le nom actuel
void Fonction_externe_nD::LectDonnParticulieres_Fonction_nD(const string& nom,UtilLecture * entreePrinc)
  {
     if (nom == "")  { *(entreePrinc->entree) >> nom_ref;}
     else {nom_ref=nom;};
     entreePrinc->NouvelleDonnee();  // lecture d'une nouvelle ligne
     
     // on initialise le tableau de retour qui doit-être redimensionné en lecture
     tab_ret.Change_taille(0);

     // on lit tant que l'on ne rencontre pas la ligne contenant "fin_parametres_fonction_externe_"
     // ou un nouveau mot clé global auquel cas il y a pb !!
     MotCle motCle; // ref aux mots cle
     list < string> list_de_variables; // liste intermédiaire
     list <Enum_GrandeurGlobale >  list_enu_variables_glob; // idem enum glob
     list < string> list_de_variables_nom_globales; // idem string glob
     string titi;
     while (strstr(entreePrinc->tablcar,"fin_parametres_fonction_externe_")==0)
       {
        // 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 le mot cle "
                << " fin_parametres_fonction_externe_ et par contre la ligne courante contient un mot cle global  ";
           entreePrinc->MessageBuffer("** erreur des parametres d'une courbe expression litterale **");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
         };
         
        // lecture d'un mot clé
        *(entreePrinc->entree) >> titi;
        
        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) >>titi;
                 }
        #else
        else  if ((entreePrinc->entree)->eof())
                 // la lecture est bonne mais on a atteind la fin de la ligne
                 { if(titi != "fin_parametres_fonction_externe_")
                     // on lit sans tenir compte des < éventuelles
                     {entreePrinc->NouvelleDonneeSansInf();
                      *(entreePrinc->entree) >> titi;
                     };
                 } 
        #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);     
         };

        // on lit maintenant la ou les variables
        // cas de la lecture d'une variable
        if(titi == "un_argument=")
         {string truc; *(entreePrinc->entree) >> truc;
          // on regarde s'il s'agit d'une variable globale correspondant à un énuméré global
          if (EstUneGrandeurGlobale(truc))
           { list_enu_variables_glob.push_back(Id_nom_GrandeurGlobale (truc));}
          // idem mais sous forme d'un string
          else if (ParaGlob::param->GrandeurGlobal(truc) != NULL)
           { list_de_variables_nom_globales.push_back(truc);}
          else // sinon ce n'est pas une grandeur globale
           {list_de_variables.push_back(truc);};
         }
        else if(titi == "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
           {string truc; *(entreePrinc->entree) >> truc;
            if (truc == "fin_list_var_")
                break;
            // on regarde s'il s'agit d'une variable globale
            if (EstUneGrandeurGlobale(truc))
             { list_enu_variables_glob.push_back(Id_nom_GrandeurGlobale (truc));}
            // idem mais sous forme d'un string
            else if (ParaGlob::param->GrandeurGlobal(truc) != NULL)
             { list_de_variables_nom_globales.push_back(truc);}
            else // sinon ce n'est pas une grandeur globale
             {list_de_variables.push_back(truc);};
            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 courbe expression litterale **");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
           }
          else // sinon la lecture est ok a priori
            ;
         }
        // cas de la lecture du niveau d'impression pour les erreurs
        else if(titi == "permet_affichage_")
         {*(entreePrinc->entree) >> permet_affichage;
         }
        // cas de la lecture du type d'expression du tenseur
        else if(titi == "Tenseur_base_ad_hoc_")
          {*(entreePrinc->entree) >> absolue;
          }
         // cas de la lecture de la taille du vecteur retour
         else if(titi == "nb_double_ret_")
          {int nb_double_ret;  // nombre de grandeur en retour de fonction externe
           *(entreePrinc->entree) >> nb_double_ret;
           if (nb_double_ret < 1)
            {cout << "\n erreur en lecture du nombre de grandeur en retour de fonction externe "
                  << " qui doit etre >= 1,  on a lu : " << nb_double_ret << endl;
             entreePrinc->MessageBuffer("**Fonction_externe_nD::LectureDonneesParticulieres**");
             throw (UtilLecture::ErrNouvelleDonnee(-1));
             Sortie(1);
            }
           else tab_ret.Change_taille(nb_double_ret); // cas ok
          }
        // sinon ce n'est pas un mot clé connu, on le signale
        else if(titi != "fin_parametres_fonction_externe_")
         { cout << "\n erreur en lecture d'un parametre, le mot cle est inconnu "
                << " on a lu : " << titi << endl;
           entreePrinc->MessageBuffer("**Fonction_externe_nD::LectureDonneesParticulieres**");
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);
         };
        
       }; //-- fin du while
     
     // on vérifie que l'on a bien redimensionné le tableau de retour
     if (  tab_ret.Taille() == 0)
      {cout << "\n erreur en definition de la fonction externe, il manque le dimensionnement du vecteur de retour !! "
            << " qui doit etre >= 1 "  << endl;
       entreePrinc->MessageBuffer("**Fonction_externe_nD::LectureDonneesParticulieres**");
       throw (UtilLecture::ErrNouvelleDonnee(-1));
       Sortie(1);
      };

     //  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 parcours les variables globales patentées
     int nb_enu = list_enu_variables_glob.size();
     int ienu=1; enu_variables_globale.Change_taille(nb_enu);
     {list <Enum_GrandeurGlobale >::iterator il,ilfin=list_enu_variables_glob.end();
      for (il=list_enu_variables_glob.begin();il!=ilfin;il++,ienu++)
         enu_variables_globale(ienu) = *il;
     };
     // idem pour les noms de ref
     int nb_nom = list_de_variables_nom_globales.size();
     int i_nom=1; nom_variables_globales.Change_taille(nb_nom);
     {list <string >::iterator il,ilfin=list_de_variables_nom_globales.end();
      for (il=list_de_variables_nom_globales.begin();il!=ilfin;il++,i_nom++)
         nom_variables_globales(i_nom) = *il;
     };
   
     // --- on définie les variables qui ne sont pas globales ---
     // par contre on va changer l'ordre d'apparition des variables
     // en 1) les scalaires, 2) les coordonnées , 3) les tenseurs
     // et .... rajouter
     int taille = list_de_variables.size(); // récup de la taille
     nom_variables.Change_taille(taille); // mise à jour de la taille
     tab_fVal.Change_taille(taille+nb_enu+nb_nom);      // idem mais en tenant compte des var globales
     
     // vérif qui normalement est inutile, mais on ne sait jamais
     if (tab_fVal.Taille() > 115)
      { cout << "\n ** erreur dans la construction de la fonction "
             << nom_ref  ;
        cout << " le nombre de parametres d'appel:" <<  tab_fVal.Taille()
             << " est superieur a 115 = la limite superieur autorisee "
             << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<endl;
         // on génère une interruption ce qui permettra de dépiler les appels
         this->Affiche();ErrCalculFct_nD toto;throw (toto);
         Sortie(1);
      };
 
     // cas des variables non globales
     list < string>::iterator il,ilfin = list_de_variables.end();
     int i= 1;
     for (il = list_de_variables.begin();il != ilfin;il++,i++)
      { nom_variables(i)=(*il); // on récupère le nom
      };

     // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
     Fonction_nD::Construction_index_conteneurs_evoluees();
     // on définit le paramètre depend_M de la classe maître en fonction des nom_variables
     if (permet_affichage > 6)
         cout << "\n == >>> lecture donnees particuliere de la fct:  " << nom_ref << ") "
              << " operations finales: " ;
     Fonction_nD::Definition_depend_M();
     // idem pour le temps
     Fonction_nD::Definition_depend_temps();
     
     // initialisation des pipes
     Fonction_externe_nD::InitialisationPipesNommes();

   };
    
// mise à jour des variables globales: en fonction de l'apparition de nouvelles variables
// globales en cours de calcul
void Fonction_externe_nD::Mise_a_jour_variables_globales()
 { // appel de la fonction interne pour modifier les noms de variables
   Fonction_nD::Mise_a_jour_variables_globales_interne();
 };

// def info fichier de commande
void Fonction_externe_nD::Info_commande_Fonctions_nD(UtilLecture & entreePrinc)
  {  ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
	    cout << "\n cas de la fonction Fonction_externe_nD : "
          << " \ndefinition standart (rep o) ou documentation exhaustive (rep n'importe quoi) ? ";
	    string rep = "_"; rep = lect_return_defaut(false,"o");
     sort << "\n# .......  fonction litterale nD ........";
     // cas particulier
     if ((rep == "o") || (rep == "O" ) || (rep == "0") )
       {sort << "\n# exemple de definition d'une fonction Fonction_externe_nD"
             << " qui renvoi une seule valeur (un reel) "
             << "\n exemple_fonct_ext_nD  FONCTION_EXTERNE_ND "
             << "\n   un_argument= i un_argument= j   "
             << "\n   nb_double_ret_  1 "
             << "\n   fin_parametres_fonction_externe_  "
             << endl;
       }
     else // cas d'une description exhaustive
      { sort << "\n#   Il s'agit d'une fonction utilisateur qui est definie en dehors d'Herezh "
          << "\n#   a chaque appel de la fonction:  "
          << "\n#   1) les variables sont copiees sur le pipe nomme <nom fonction>_envoi_Hz.FIFO "
          << "\n#   2) puis Herezh lit la reponse sur le pipe nomme: <nom fonction>_reception_Hz.FIFO   "
          << "\n#     ==> tant que les informations ne sont pas disponibles sur le pipe de reception "
          << "\n#     l'execution d'Herezh est stoppee "
          << "\n#     "
          << "\n#   L'utilisation de cette fonction impose donc a l'utilisateur, de construire un programme"
          << "\n#   externe qui lit les donnes sur <nom fonction>_envoi_Hz.FIFO, en deduit les valeurs de retour  "
          << "\n#   qui doivent etre ecrite sur <nom fonction>_reception_Hz.FIFO  "
          << "\n#     "
          << "\n#   Format d'echange:   "
          << "\n#    en ecriture, Herezh ecrit sur le pipe d'envoi:  "
          << "\n#     - 2 entiers codes sur 4 octets chacun, qui representent: "
          << "\n#       . le premier n1 = le nombre de variables de la fonction"
          << "\n#       . le second n2 = la taille du vecteur de retour attendu sur le pipe de reception "
          << "\n#     - puis n1 reels, chacun code sur 8 octets "
          << "\n#     "
          << "\n#    en retour, Herezh lit sur le pipe de reception:  "
          << "\n#     - 2 entiers codes sur 4 octets chacun, qui representent: "
          << "\n#       . le premier n1 = le nombre de variables de la fonction"
          << "\n#       . le second n2 = la taille du vecteur de retour attendu sur le pipe de reception "
          << "\n#     - puis n2 reels, chacun code sur 8 octets "
          << "\n#     "
          << "\n#    NB: le nombre maximal possible de reels est actuellement de 115 "
          << "\n#     "
          << "\n#     "
          << "\n#    Par exemple, pour une utilisation via un programme C ou C++, une methode est de definir "
          << "\n#    une structure union. Supposons 4 variables, et un vecteur de 2 composantes en retour "
          << "\n#    cela signifie qu'il faut une taille minimale de tampon de passage de: 2*4+4*8= 40 octets"
          << "\n#    equivalent a 5 reels, 10 entiers d'ou un exemple de declaration: "
          << "\n#     union Tab_car_double_int  "
          << "\n#      {  char    tampon[40]; "
          << "\n#         double  x[5];  "
          << "\n#         int     n[10];  "
          << "\n#      } ;  "
          << "\n#    Ensuite, le programme C lit l'information sur le pipe d'envoi de nom ici: envoi, ex: "
          << "\n#      Tab_car_double_int t_car_x_n; "
          << "\n#      char* tampon =  &(t_car_x_n.tampon[0]); "
          << "\n#      int nb_carac_a_lire = 40 ; "
          << "\n#      int tub = open(envoi.c_str(),O_RDONLY); "
          << "\n#      read (tub,tampon_,nb_carac_a_lire); "
          << "\n#      close (tub);  "
          << "\n#     "
          << "\n#   Les variables sont alors disponible dans le tableau x "
          << "\n#   Puis le programme C calcule les valeurs de retour et les sauvegarde dans x  "
          << "\n#   Reste a ramener les infos a Herezh. Pour cela le programme C doit ecrire dans  "
          << "\n#   le pipe de retour, ici de nom reception, par ex:  "
          << "\n#     "
          << "\n#     int tub = open(reception.c_str(),O_WRONLY); "
          << "\n#     int nb_carac_a_ecrire = 2 * 8 + 2*4 ;  "
          << "\n#     write (tub,t_car_x_n.reception,nb_carac_a_ecrire);  "
          << "\n#     close (tub);     "
          << "\n#     "
          << "\n#   ======= definition d'une fonction externe =====  "
          << "\n#   1) --- on definit la liste de variables   "
          << "\n#      cette liste inclu des variables avec les 2 syntaxes suivantes "
          << "\n#       a) soit une variable par ligne selon la syntaxe: "
          << "\n#          un_argument= nom_argument"
          << "\n#          ou  "
          << "\n#            un_argument= : le mot cle "
          << "\n#            nom_argument : le nom de la variable "
          << "\n#       b) soit une liste de variables (sur une ligne) selon la syntaxe "
          << "\n#            deb_list_var_   nom1 nom2 ... fin_list_var_ "
          << "\n#         ou  "
          << "\n#         deb_list_var_ et fin_list_var_ : balises encadrant la liste"
          << "\n#         nom1 nom2 ... : le nom de chaque variable "
          << "\n#   "
          << "\n#     NB: les variables peuvent etre des grandeurs locales ou globales"
          << "\n#   "
          << "\n#   2) --- on definit la taille du vecteur de retour de la fonction externe   "
          << "\n#         (note n2 dans les explications precedantes) "
          << "\n#      NB: il n'y a pas de definition par defaut "
          << "\n#      la definition s'effectue via le mot cle: nb_double_ret_  "
          << "\n#      suivi de la taille du vecteur de retour, ex:   "
          << "\n#        nb_double_ret_  1 "
          << "\n#   La liste des variables  et la definition de n2 "
          << "\n#   doit se terminer par le mot cle   (sur une ligne seule ): "
          << "\n#      fin_parametres_fonction_externe_ "
          << "\n#   "
          << "\n#............................................"
          << "\n# exemple de definition d'une fonction Fonction_externe_nD"
          << "     qui renvoi une seule valeur (un reel) "
          << "\n   exemple_fonct_ext_nD  FONCTION_EXTERNE_ND "
          << "\n     un_argument= i un_argument= j   "
          << "\n     nb_double_ret_  1 "
          << "\n   fin_parametres_fonction_externe_  "
          << "\n#       "
          << "\n#  type d'expression des tenseurs:      "
          << "\n#  Tenseur_base_ad_hoc_ suivi de  "
          << "\n#     0 si dans la  base ad hoc   "
          << "\n#     1 si  dans une base globale     "
          << "\n#   NB: les deux sont en orthonorme    "
          << "\n#       par defaut, c'est dans une base ad hoc"
          << "\n#   ex:  Tenseur_base_ad_hoc_ 0   "
          << "\n#       "
          << "\n#  niveau d'impression: dans certain cas il peut-etre utile d'afficher    "
          << "\n#   les resultats intermediaires des calculs et egalement des erreurs intermediaires    "
          << "\n#   pour mettre en route ce fonctionnement il faut indiquer sur une ligne seule le mot cle     "
          << "\n#   permet_affichage_ suivi d'un chiffre donnant le niveau d'impression (entre 0 et 10)    "
          << "\n# ex: permet_affichage_ 5  "
          << "\n#   Remarques: 1) ceci ne fonctionne qu'avec la version non fast    "
          << "\n#      cependant, la lecture reste correcte avec le mot cle permet_affichage_ "
          << "\n#     mais la presence du mot cle n'entraine aucune action en fast  "
          << "\n#   2) le mot cle doit etre indique avant le dernier mot cle :     "
          << "\n#   fin_parametres_fonction_externe_  "
          << endl;
      };
   };

// calcul  des valeurs de la fonction, retour d'un tableau de scalaires
Tableau <double> & Fonction_externe_nD::Valeur_FnD_interne(Tableau <double >* xi)
 {
 
   int i_in_xi=1; // indice pour se déplacer dans xi
   int i_fval=1; // indice pour se déplacer dans fval_int
   int taille_xi=0; // init par défaut
   if (xi != NULL)
     taille_xi=xi->Taille();

   try
     {
     
      int nb_var_int = nom_variables.Taille();
      int tail_enu = enu_variables_globale.Taille(); // les variables globales
      int tail_nom = nom_variables_globales.Taille(); // idem avec des noms
      #ifdef MISE_AU_POINT
      if (tab_fVal.Taille() != (taille_xi+tail_enu+tail_nom))
  	     { cout << "\n *** pb de dimensions d'argument non coherentes !! "
               << " taille_xi "<<taille_xi
               << ", tab_fVal.Taille()= "<<tab_fVal.Taille()
               << " enu_variables_globale.Taille()= "<<enu_variables_globale
  	            << "\n Fonction_externe_nD::Valeur_FnD(..."<<endl;
          this->Affiche();
          // on génère une interruption ce qui permettra de dépiler les appels
          ErrCalculFct_nD toto;
          throw (toto);
  	       Sortie(1);
  	     };

      #endif
      
      // on remplit le tableau de passage pour la fonction maître
      // 1) tout d'abord pour les variables patentées
      for (int ii = 1;ii<= nb_var_int;ii++,i_fval++)
       {
        // on se déplace d'abord dans xi
        if (i_in_xi <= taille_xi)
         {tab_fVal(i_fval) = xi->operator()(i_in_xi);i_in_xi++;}
        else
         { cout << "\n *** pb de nombre d'argument non coherentes !! "
                << " on n'a pas assez d'arguments pour l'appel de la fonction globale: ";
           this->Affiche();
           cout << "\n revoir la mise en donnees "
                << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<endl;
           // on génère une interruption ce qui permettra de dépiler les appels
           ErrCalculFct_nD toto;
           throw (toto);
           Sortie(1);
         };
       };
      
      // 2) puis les valeurs globales éventuelles typées énuméré
/*      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 Fonction_externe_nD " << nom_ref << " !! "
                        << " la variable globale  "<< Nom_GrandeurGlobale(enu_variables_globale(i))
                        << ", n'est pas disponible, on ne peut pas continuer  "
                        << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<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(...)
         { cout << "\n ** erreur dans l'appel de la fonction "
                << nom_ref  ;
           cout << " verifier la presence des grandeurs globales voulues "
                << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<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 = enu_variables_globale.Taille();
        for (int i=1;i<= taille;i++,i_fval++)
         {// 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
                      tab_fVal(i_fval) = *(gr.ConteneurEntier());
                      break;
                     }
                   case PARTICULIER_SCALAIRE_DOUBLE:
                     {Grandeur_scalaire_double& gr
                           = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = *(gr.ConteneurDouble());
                      break;
                     }
                   case PARTICULIER_DDL_ETENDU:
                     {Grandeur_Ddl_etendu& gr
                           = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (gr.GrandeurNumOrdre(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_externe_nD::Valeur_FnD_interne(..."
                            <<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_externe_nD::Valeur_FnD_interne(..."
                      <<endl;
                 // on génère une interruption ce qui permettra de dépiler les appels
                 this->Affiche();ErrCalculFct_nD toto;throw (toto);
                 Sortie(1);
               };
           };
         };
       };
      // 3) idem pour les globaux en nom c-a-d  typées sous forme de string
      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_externe_nD " << nom_ref << " !! "
                        << " la variable globale  "<< nom_variables_globales(i)
                        << ", n'est pas disponible, on ne peut pas continuer  "
                        << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<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(...)
         { cout << "\n ** erreur dans l'appel de la fonction "
                << nom_ref  ;
           cout << " verifier la presence des grandeurs globales voulues "
                << "\n Fonction_externe_nD::Valeur_FnD_interne(..."<<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++,i_fval++)
         {// 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
                      tab_fVal(i_fval) = *(gr.ConteneurEntier());
                      break;
                     }
                   case PARTICULIER_SCALAIRE_DOUBLE:
                     {Grandeur_scalaire_double& gr
                           = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = *(gr.ConteneurDouble());
                      break;
                     }
                   case PARTICULIER_DDL_ETENDU:
                     {Grandeur_Ddl_etendu& gr
                           = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (gr.GrandeurNumOrdre(1));
                      break;
                     }
                   case PARTICULIER_VECTEUR_NOMMER:
                     {Grandeur_Vecteur_Nommer& gr
                           = *((Grandeur_Vecteur_Nommer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (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_externe_nD::Valeur_FnD_interne(..."
                                <<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_externe_nD::Valeur_FnD_interne(..."
                            <<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
                      tab_fVal(i_fval) = (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_externe_nD::Valeur_FnD_interne(..."
                                <<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_externe_nD::Valeur_FnD_interne(..."
                            <<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_externe_nD::Valeur_FnD_interne(..."
                      <<endl;
                 // on génère une interruption ce qui permettra de dépiler les appels
                 this->Affiche();ErrCalculFct_nD toto;throw (toto);
                 Sortie(1);
               };
           };
         };
       };
*/
      // on récupère les grandeurs globales
      Fonction_nD::Recup_Grandeurs_globales();
      // on affecte les grandeurs
      int taille = x_glob.Taille();
      for (int i=1;i<= taille;i++,i_fval++)
         tab_fVal(i_fval) = x_glob(i);

      // maintenant on appelle la fonction et on récupère les grandeurs
      // 1) écriture des données sur le pipe
      EcritureDonneesPipe();
      // 2) lecture des données sur le pipe
      LectureResultatsPipe();

      #ifdef MISE_AU_POINT
      // vérification d'une norme infinie
//      if (permet_affichage > 0)
        {int nNum = tab_ret.Taille();
         double absret_Fi= 0.;
         for (int i=0; i<nNum; ++i)
           absret_Fi += Dabs(tab_ret(i+1));
         if ((!isfinite(absret_Fi)) || (isnan(absret_Fi)) )
           { cout << "\n probleme dans le calcul de la fonction  "
                  << " on obtient en norme euclidienne: " << absret_Fi
                  << "\n Fonction_externe_nD::Valeur_FnD_interne(...";
             cout << "\n parametres d'appel: ";
             int nb_var = tab_fVal.Taille();
             for (int j=1;j<=nb_var;j++)
              { cout << " para("<<j<<")= "<< tab_fVal(j);}
             cout <<"\n >>> arbre d'appel : fonction this : ";
             this->Affiche(5);
             cout << endl;
             // on génère une interruption ce qui permettra de dépiler les appels
             ErrCalculFct_nD toto;throw (toto);Sortie(1);
           };
      };
     #endif
     }
    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 non determinee dans l'appel de la fonction "
            << nom_ref  << " d'expression "
            << " \n xi= "<<xi ;
       this->Affiche();
       cout << "\n Fonction_externe_nD::Valeur_FnD_interne(...";
       // on génère une interruption ce qui permettra de dépiler les appels
       ErrCalculFct_nD toto;throw (toto);
       Sortie(1);
     };
    return tab_ret;
  };
 
 
// calcul des valeurs de la fonction, dans le cas où les variables
// sont toutes des grandeurs globales: pour l'instant que pour des variables scalaires
Tableau <double> & Fonction_externe_nD::Valeur_pour_variables_globales_interne()
  {
  
/*    // en debug on vérifie que les grandeurs globales sont présentent
    #ifdef MISE_AU_POINT
    try
     { // on vérifie tout d'abord que toutes les variables sont globales
       if (nom_variables.Taille() != 0)
        { cout << "\n ** erreur dans l'appel de la fonction "
               << nom_ref  ;
          cout << " toutes les variables ne sont pas globales !!  "
               << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(..."<<endl;
          this->Affiche();
          // on génère une interruption ce qui permettra de dépiler les appels
          ErrCalculFct_nD toto;throw (toto);
          Sortie(1);
        };
       // maintenant on vérifie la présence des variables globales
       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 Fonction_externe_nD " << nom_ref << " !! "
                    << " la variable globale  "<< Nom_GrandeurGlobale(enu_variables_globale(i))
                    << ", n'est pas disponible, on ne peut pas continuer  "
                    << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(..."<<endl;
               this->Affiche();
               // on génère une interruption ce qui permettra de dépiler les appels
               ErrCalculFct_nD toto;throw (toto);
               Sortie(1);
             };
          };
     }
    catch(...)
     { cout << "\n ** erreur dans l'appel de la fonction "
            << nom_ref  ;
       cout << " verifier la presence des grandeurs globales voulues "
            << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(..."<<endl;
       this->Affiche();
       // on génère une interruption ce qui permettra de dépiler les appels
       ErrCalculFct_nD toto;throw (toto);
       Sortie(1);
     };
    #endif
    // idem pour les grandeurs indicées avec des string
    #ifdef MISE_AU_POINT
    try
     { int tail_nom = nom_variables_globales.Taille();
       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_externe_nD " << nom_ref << " !! "
                    << " la variable globale  "<< nom_variables_globales(i)
                    << ", n'est pas disponible, on ne peut pas continuer  "
                    << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(..."<<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(...)
     { cout << "\n ** erreur dans l'appel de la fonction "
            << nom_ref  ;
       cout << " verifier la presence des grandeurs globales voulues "
            << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(..."<<endl;
       this->Affiche();
       // on génère une interruption ce qui permettra de dépiler les appels
       ErrCalculFct_nD toto;throw (toto);
       Sortie(1);
     };
    #endif
*/
    // arrivée ici toutes les grandeurs existent
    try
     {
/*      // on parcours les variables globales
      int i_fval=1; // indice pour se déplacer dans plusieurs boucles
      int taille = enu_variables_globale.Taille();
      for (int i=1;i<= taille;i++,i_fval++)
       {// 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
                    tab_fVal(i_fval) = *(gr.ConteneurEntier());
                    break;
                   }
                 case PARTICULIER_SCALAIRE_DOUBLE:
                   {Grandeur_scalaire_double& gr
                         = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                    tab_fVal(i_fval) = *(gr.ConteneurDouble());
                    break;
                   }
                 case PARTICULIER_DDL_ETENDU:
                     {Grandeur_Ddl_etendu& gr
                           = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (gr.GrandeurNumOrdre(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_externe_nD::Valeur_pour_variables_globales_interne(..."
                          <<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_externe_nD::Valeur_pour_variables_globales_interne(..."
                    <<endl;
               // on génère une interruption ce qui permettra de dépiler les appels
               this->Affiche();ErrCalculFct_nD toto;throw (toto);
               Sortie(1);
             };
         };
       };
      // idem mais typées sous forme de string
      {// on parcours les variables globales
       int taille = nom_variables_globales.Taille();
       for (int i=1;i<= taille;i++,i_fval++)
        {// 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
                      tab_fVal(i_fval) = *(gr.ConteneurEntier());
                      break;
                     }
                   case PARTICULIER_SCALAIRE_DOUBLE:
                     {Grandeur_scalaire_double& gr
                           = *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = *(gr.ConteneurDouble());
                      break;
                     }
                   case PARTICULIER_DDL_ETENDU:
                     {Grandeur_Ddl_etendu& gr
                           = *((Grandeur_Ddl_etendu*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (gr.GrandeurNumOrdre(1));
                      break;
                     }
                   case PARTICULIER_VECTEUR_NOMMER:
                     {Grandeur_Vecteur_Nommer& gr
                           = *((Grandeur_Vecteur_Nommer*) gr_quelc->Grandeur_pointee()); // pour simplifier
                      tab_fVal(i_fval) = (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_externe_nD::Valeur_pour_variables_globales_interne(..."
                                <<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_externe_nD::Valeur_pour_variables_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
                      tab_fVal(i_fval) = (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_externe_nD::Valeur_pour_variables_globales_interne(..."
                                <<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_externe_nD::Valeur_pour_variables_globales_interne(..."
                            <<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_externe_nD::Valeur_pour_variables_globales_interne(..."
                      <<endl;
                 // on génère une interruption ce qui permettra de dépiler les appels
                 this->Affiche();ErrCalculFct_nD toto;throw (toto);
                 Sortie(1);
               };
          };
        };
      };
*/
      // on récupère les grandeurs globales
      Fonction_nD::Recup_Grandeurs_globales();
      // on affecte les grandeurs
      int taille_x_glob = x_glob.Taille();
      for (int i=1;i<= taille_x_glob;i++)
         tab_fVal(i) = x_glob(i);

      // maintenant on appelle la fonction et on récupère les grandeurs
      // 1) écriture des données sur le pipe
      EcritureDonneesPipe();
      // 2) lecture des données sur le pipe
      LectureResultatsPipe();

      #ifdef MISE_AU_POINT
      // vérification d'une norme infinie
//      if (permet_affichage > 0)
        {int nNum = tab_ret.Taille();
         double absret_Fi= 0.;
         for (int i=0; i<nNum; ++i)
           absret_Fi += Dabs(tab_ret(i+1));
         if ((!isfinite(absret_Fi)) || (isnan(absret_Fi)) )
           { cout << "\n probleme dans le calcul de la fonction  "
                  << " on obtient en norme euclidienne: " << absret_Fi
                  << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(...";
             cout << "\n parametres d'appel: ";
             int nb_var = tab_fVal.Taille();
             for (int j=1;j<=nb_var;j++)
              { cout << " para("<<j<<")= "<< tab_fVal(j);}
             cout <<"\n >>> arbre d'appel : fonction this : ";
             this->Affiche(5);
             cout << endl;
             // on génère une interruption ce qui permettra de dépiler les appels
             this->Affiche(5);ErrCalculFct_nD toto;throw (toto);Sortie(1);
           };
      };
     #endif
     }
    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 non determinee dans l'appel de la fonction "
            << nom_ref
            << "\n Fonction_externe_nD::Valeur_pour_variables_globales_interne(...";
//       // on génère une interruption ce qui permettra de dépiler les appels
       this->Affiche();ErrCalculFct_nD toto;throw (toto);
       Sortie(1);
     };
    return tab_ret;
  };

	//----- lecture écriture de restart -----
	// 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_externe_nD::Lecture_base_info(ifstream& ent,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { string nom;
        // lecture et vérification de l'entête
        ent >> nom;
        if (nom != "Fonction_externe_nD")
         { cout << "\n erreur dans la vérification du type de courbe lue ";    
           cout << "\n Fonction_externe_nD::Lecture_base_info(... ";
           Sortie(1); 
           } 
        // lecture des infos
       
        // les arguments gérés par la classe mère
        Fonction_nD::Lect_base_info(ent,cas);
        
        // retour des valeurs
        string toto;
        ent >> toto ;
        if (toto != "taille_vecteur_de_retour:")
           {cout << "\n erreur en lecture sur base info du nombre de grandeur en retour de fonction externe "
                 << " on a lu : " << toto
                 << " alors que l'on attendait: taille_vecteur_de_retour:"
                 << "\n Fonction_externe_nD::Lecture_base_info(..."
                 << endl;
            Sortie(1);
           };
        // cas où c'est ok
        int nb_double_ret;
        ent >> nb_double_ret;
        tab_ret.Change_taille(nb_double_ret);

        // on définit le paramètre depend_M de la classe maître en fonction des nom_variables
        Fonction_nD::Definition_depend_M();
        // idem pour le temps
        Fonction_nD::Definition_depend_temps();
        // idem pour la cohérence avec les enu
//        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();
        // initialisation des pipes au cas où
        Fonction_externe_nD::InitialisationPipesNommes();
       }
   };

    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
void Fonction_externe_nD::Ecriture_base_info(ofstream& sort,const int cas)
  { // on n'a que des grandeurs constantes
    if (cas == 1)
      { sort << "\n <FONCTION_EXTERNE_ND>  ";
        sort << " Fonction_externe_nD ";
        // les arguments gérés par la classe mère
        Fonction_nD::Ecrit_base_info(sort,cas);
        // retour des valeurs
        sort << "\n taille_vecteur_de_retour: "<< this->NbComposante()
             << " ";
        sort << "\n </FONCTION_EXTERNE_ND> \n";
      };
   };
         
// sortie du schemaXML: en fonction de enu 
void Fonction_externe_nD::SchemaXML_Fonctions_nD(ofstream& ,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;
		}
	};		
  };
     

// initialisation des pipes
void Fonction_externe_nD::InitialisationPipesNommes()
 {
  try
    { // pipe de sortie
      // on test l'existence du pipe
      struct stat buf;
      int tub=0; // init
      int etat = stat(envoi.c_str(), &buf);
      
      int tube_a_cree = 0;
      if (etat == -1) // cela veut dire que la fonction stat n'a pas fonctionné
        // on part sur le principe que les tubes n'existent pas
        {tube_a_cree=1;}
      else if (!S_ISFIFO(buf.st_mode))
        {tube_a_cree=1;};
      if (tube_a_cree ) // cas où le tube n'existe pas
       {tub = mkfifo (envoi.c_str(), S_IRWXU);
        if (tub == -1 ) // gestion d'erreur éventuelle
         {cout << "\n *** erreur en creation du tube nomme: " << envoi << ", de sortie d'herezh pour la "
               << " fonction externe "<< nom_ref
               << "\n Fonction_externe_nD::InitialisationPipesNommes() "<<flush;
          Sortie(1);
         }
        else if ((ParaGlob::NiveauImpression() > 3) || (permet_affichage > 0 ))
         { cout << "\n creation du pipe nomme: "<< envoi << " pour la "
                << " fonction externe "<< nom_ref << flush;
           // partie affichage du nom des variables
           if (permet_affichage > 5)
             {  cout << "\n ---- Fonction_externe_nD " << nom_ref  ;
                cout << "  \n arguments= " << 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) << " ";
             };
         } ;
        close (tub); // fermeture du tampon
       }
     else if ((ParaGlob::NiveauImpression() > 3) || (permet_affichage > 0 ))
       { cout << "\n utilisation du pipe nomme: "<< reception << " pour la "
              << " fonction externe "<< nom_ref << flush;
         // partie affichage du nom des variables
         if (permet_affichage > 5)
           {  cout << "\n ---- Fonction_externe_nD " << nom_ref  ;
              cout << "  \n arguments= " << 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) << " ";
           };
       } ;
     tub = 0;         // réinit
     tube_a_cree = 0; // réinit
    
     // ouverture du tube nommé en lecture
     etat = stat(reception.c_str(), &buf);
     if (etat == -1) // cela veut dire que la fonction stat n'a pas fonctionné
       // on part sur le principe que les tubes n'existent pas
       {tube_a_cree=1;}
     else if (!S_ISFIFO(buf.st_mode))
       {tube_a_cree=1;};
     if (tube_a_cree ) // cas où le tube n'existe pas
      {tub = mkfifo (reception.c_str(), S_IRWXU);
       if (tub == -1 ) // gestion d'erreur éventuelle
        {cout << "\n *** erreur en creation du tobe nomme: " << reception << ", de lecture d'herezh pour la "
              << " fonction externe "<< nom_ref
              << "\n Fonction_externe_nD::InitialisationPipesNommes() "<<flush;
         Sortie(1);
        }
      else if ((ParaGlob::NiveauImpression() > 3) || (permet_affichage > 0 ))
       { cout << "\n creation du pipe nomme: "<< reception << " pour la "
              << " fonction externe "<< nom_ref << flush;
       } ;
      close (tub); // fermeture du tampon
     }
     else if ((ParaGlob::NiveauImpression() > 3) || (permet_affichage > 0 ))
      { cout << "\n utilisation du pipe nomme: "<< reception << " pour la "
             << " fonction externe "<< nom_ref << flush;
      } ;

    
    }
   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 inconnue lors de l'initialisation des pipes I/O pour la "
          << " fonction externe "<< nom_ref
          << "\n Fonction_externe_nD::InitialisationPipesNommes() "<<flush;
     Sortie(1);
    };
 
 };


// lecture des données
void Fonction_externe_nD::LectureResultatsPipe()
{
 try
  {//  Creation d'un processus de reception des données
   // en fait l'objectif est de réceptionner que les variables d'entrées ou
   // d'entrée sortie
   if (permet_affichage > 5)
        cout << "\n hzpp:  ouverture du tube en lecture, lecture sur le tube: "
             << reception << endl;


  //      union Tab_car_double_int_1
  //      {  char    tampon[928];
  //         double  x[116];
  //         int     n[232];
  //      } ;
  //      Tab_car_double_int_1 t_car_x_n; // tableau de caractères, réels et entiers
  //      Tableau <double> tab_fVal; // les variables internes dont le nombre doit être
  //        // égal à celui du tableau nom_variables + les enum globaux + les noms globaux
  //      Tableau <double> tab_ret; // le tableau de retour

    // le premier élément est le nombre de grandeurs à écrire (et donc à lire du coté externe)
    // le second élément est le nombre de grandeurs que l'on attend en retour
    t_car_x_n.n[1] = tab_ret.Taille();

    char* tampon =  &(t_car_x_n.tampon[0]);
    int nb_carac_a_lire = t_car_x_n.n[1] * 8 + 2*4 ;
    
    int tub = open(reception.c_str(),O_RDONLY);
    read (tub,tampon,nb_carac_a_lire);
    close (tub); // fermeture du tampon
    
    // on récupère les informations du tampon
    int nb_doublePlusUn = tab_ret.Taille() +1;
    for (int i=1;i<nb_doublePlusUn;i++)
//        tab_fVal(i) = tab_ret(i) = t_car_x_n.x[i] ;
        tab_ret(i) = t_car_x_n.x[i] ;
    if (permet_affichage >2 )
       {cout << "\n lecture de " << t_car_x_n.n[1] << " reels ";
        if (permet_affichage > 3)
         {for (int i=1;i <= t_car_x_n.n[1]; i++)
           cout << "\n resultat "<< i<< "= " << t_car_x_n.x[i];
         };
       
        cout << "\n HZpp: fermeture du tube en lecture: "
             << reception << endl;
       };
  }
 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 en lecture des resultats de la fonction externe "
        << nom_ref ;
   Affiche(permet_affichage);
   cout << flush;
   Sortie(1);
  };
 // à chaque lecture on incrémente un compteur
 passage++; // pour des comptes éventuelles
};

// écriture des variables de passage
void Fonction_externe_nD::EcritureDonneesPipe()
{try
  {//   Creation d'un processus d'ecriture des variables
   // en fait l'objectif est d'ecrire que les variables qui évoluent
   if (permet_affichage > 5)
        cout << "\n hzpp: ouverture du tube en ecriture, ecriture  sur le tube:  "
             << envoi << endl;

 //      union Tab_car_double_int_1
 //      {  char    tampon[928];
 //         double  x[116];
 //         int     n[232];
 //      } ;
 //      Tab_car_double_int_1 t_car_x_n; // tableau de caractères, réels et entiers
 //      Tableau <double> tab_fVal; // les variables internes dont le nombre doit être
 //        // égal à celui du tableau nom_variables + les enum globaux + les noms globaux
 //      Tableau <double> tab_ret; // le tableau de retour

   // le premier élément est le nombre de réel à écrire (et donc à lire du coté externe)
   t_car_x_n.n[0]=tab_fVal.Taille();
   int nb_doublePlusUn = t_car_x_n.n[0]+1;
   // le second élément est le nombre de grandeurs que l'on attend en retour
   t_car_x_n.n[1] = tab_ret.Taille();
   // après on transfert dans le tampon
   for (int i=1;i<nb_doublePlusUn;i++)
     t_car_x_n.x[i] = tab_fVal(i);
   // ouverture du tube nomme en ecriture
   int tub = open(envoi.c_str(),O_WRONLY);
   int nb_carac_a_ecrire = t_car_x_n.n[0] * 8 + 2*4 ;
   write (tub,t_car_x_n.tampon,nb_carac_a_ecrire);
   close (tub); // fermeture du tampon

   if (permet_affichage > 2)
        {cout << "\n ecriture de " << t_car_x_n.n[0] << " reels ";
         if (permet_affichage > 3)
          {for (int i=1;i <= t_car_x_n.n[0]; i++)
            cout << "\n variable "<< i<< "= " << t_car_x_n.x[i];
          };
         if (permet_affichage > 7)
            cout << "\n HZpp: fermeture du tube en ecriture: "
                 << envoi << endl;
    };
   }
  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 en ecriture des parametre de la fonction externe "
         << nom_ref ;
    Affiche(permet_affichage);
    cout << flush;
    Sortie(1);
   };
 };

