// 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/>.

// fichier : Fonction_nD.h
// classe  : Fonction_nD


/************************************************************************
 *     DATE:        01/06/2016                                           *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:    Classe virtuelle permettant le calcul d'une fonction nD  *
 *     ainsi qu'éventuellement un certain nombre d'information supplé-  *
 *     mentaires telles que dérivées.                                   *
 *     si le nom de la Fonction = "_" il s'agit d'une Fonction interne  *
 *     à un objet, c'est-à-dire gérée seulement par l'entité qui la     *
 *     contient, donc pas besoin de nom (elle n'est pas utilisée autre  *
 *     part). Si le nom est différent de "_" c'est une Fonction qui est *
 *     gérée et référencée dans LesFonctions, donc à partir de son nom, *
 *     on peut la retrouver.                                            *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
 
#ifndef FONCTION_N_D_H
#define FONCTION_N_D_H

#include "UtilLecture.h"
#include "EnumFonction_nD.h"
#include "Enum_IO_XML.h"
#include "Tableau_T.h"
#include "Enum_GrandeurGlobale.h"
#include "Courbe1D.h"
#include "Coordonnee.h"
#include "Ddl_etendu.h"
#include "TypeQuelconque.h"
#include "Tenseur.h"
/** @defgroup Les_fonctions_nD Les_fonctions_nD
*
* \author    Gérard Rio
* \version   1.0
* \date      01/06/2016
* \brief       Def des fonctions nD
*
*/


/// @addtogroup Les_fonctions_nD
///  @{
///

/// gestion d'exception pour des erreurs d'appel de fonction nD
class ErrCalculFct_nD
   { public :
       ErrCalculFct_nD () {} ;  // CONSTRUCTEURS
       ~ErrCalculFct_nD () {};// DESTRUCTEUR :
   };
/// @}  // end of group

/// @addtogroup Les_fonctions_nD
///  @{
///

/**
*
*     BUT:    Classe virtuelle d'interface permettant le calcul d'une fonction nD
*     ainsi qu'éventuellement un certain nombre d'informations supplé-
*     mentaires telles que dérivées.
*     si le nom de la Fonction = "_" il s'agit d'une Fonction interne
*     à un objet, c'est-à-dire gérée seulement par l'entité qui la
*     contient, donc pas besoin de nom (elle n'est pas utilisée autre
*     part). Si le nom est différent de "_" c'est une Fonction qui est
*     gérée et référencée dans LesFonctions, donc à partir de son nom,
*     on peut la retrouver.
*
*
* \author    Gérard Rio
* \version   1.0
* \date      01/06/2016
* \brief       Classe virtuelle d'interface permettant le calcul d'une fonction nD ainsi qu'éventuellement un certain nombre d'informations supplémentaires telles que dérivées.
*
*/

class Fonction_nD
{
  public :

    // CONSTRUCTEURS :
    // par défaut
    Fonction_nD(string nom = "", EnumFonction_nD typ = AUCUNE_FONCTION_nD);
    // constructeur avec plus d'info
    // dans le cas ou les variables sont associées à des types quelconques, il
    // s'agit que de conteneur d'un scalaire simple. Dans le cas contraire il y a erreur !
    Fonction_nD(const Tableau <string >& var, string nom = "", EnumFonction_nD typ = AUCUNE_FONCTION_nD);
    
    // def de tous les paramètres: utile pour être appelé par les classes dérivées
    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

    // de copie
    Fonction_nD(const Fonction_nD& Co);
    // DESTRUCTEUR :
    virtual ~Fonction_nD();
    
    // METHODES PUBLIQUES :
// 
//    // 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
//    // la fonction nD ne doit pas pouvoir fonctionner s'il y a des types complexes
//    // et que cette méthode n'a pas été appelé
//    void Preparation_Grandeur_quelconque(const Tableau <TypeQuelconque >& tqi);
 
    // --------- virtuelles ---------
 
    // Surcharge de l'operateur = : realise l'egalite de deux fonctions
    virtual Fonction_nD& operator= (const Fonction_nD& elt)  = 0;
 
    // affichage de la Fonction
    // = 0, 1 ou 2 (le plus précis)
	   virtual void Affiche(int niveau = 0) const  = 0;
	   // ramène le nom de la Fonction
	   const string& NomFonction() const {return nom_ref;};
    // vérification que tout est ok, pres à l'emploi
    // ramène true si ok, false sinon
    virtual bool Complet_Fonction(bool affichage = true)const =0 ;
 
    // ramène le nombre total de variables de la fonction
    // c-a-dire locale et globales
    virtual int NbVariable()const
      {return nom_variables.Taille()+enu_variables_globale.Taille()
              + nom_variables_globales.Taille();
      };
 
    // ramène le nombre de variables locales
    // c-a-dire à l'exclusion des variables globales
    virtual int NbVariable_locale()const
      {return nom_variables.Taille();
      };
 
    // ramène le nombre de variables globales
    // c-a-dire à l'exclusion des variables locales
    virtual int NbVariable_globale()const
      {return (enu_variables_globale.Taille()+nom_variables_globales.Taille());
      };

    // ramène le noms des variables, indépendamment des variables globales
    const Tableau <string >& Nom_variables() const {return nom_variables;};
 
    // ramène les énumérés des variables globales éventuelles
    const Tableau <Enum_GrandeurGlobale >& Enu_variables_globales() const {return enu_variables_globale;};
    // ramène les noms string des variables globales éventuelles
    const Tableau <string >& Nom_variables_globales() const {return nom_variables_globales;};
 
    // ramène l'équivalent des nom_variables sous forme de Ddl_enum_etendu et
    // d'EnumTypeQuelconque
    // permet ensuite d'appeler la méthode Valeur(.. mais à la condition
    // que l'ensemble des Nom_variables() sont représenté soit par des Ddl_enum_etendu
    // et ou soit par des EnumTypeQuelconque
    const Tableau <Ddl_enum_etendu>& Tab_enu_etendu()const {return tab_enu_etendu;};
    const Tableau <EnumTypeQuelconque>& Tab_enu_quelconque() const {return tab_enu_quelconque;};
    // un booléen pour noter l'équivalence parfaite ou non
    bool Equivalence_nom_enu_etendu_et_enu_quelconque() const {return equivalence_nom_enu_etendu_et_enu_quelconque;};

    // tab_enu_etendu(i) correspond à nom_variables(index_enu_etendu(i))
    const Tableau <int>& Iindex_enu_etendu() const {return index_enu_etendu;};
    // tab_enu_quelconque(i) correspond à nom_variables(index_enu_quelconque(i))
    const Tableau <int>& Iindex_enu_quelconque() const {return index_enu_quelconque;};
 
    // .. chaque type_des_variables tab_enu_etendu(i) est associé à :
          // si type_des_variables(i) = 1 -> un scalaire
          // si type_des_variables(i) = 2 -> des coordonnées de dim absolue
          // si type_des_variables(i) = 3 -> un tenseur de dim absolue
          // si type_des_variables(i) = 4 -> une grandeur quelconque
    // retour du tableau des indicateurs
    const Tableau <int>& Type_des_variables_locales() const {return type_des_variables;};
 
    // retour du tableau posi_ddl_enum, qui est nécessaire pour l'appel de la fonction
    //  Val_FnD_Evoluee(Tableau <double >* xi_,Tableau <Coordonnee> * tab_coor_,Tableau <TenseurBB* >* tab_tensBB_
    //                  Tableau <TypeQuelconque >* t_quelc_ )
    // -> Pour le Ddl_enum_etendu (i)  dont on récupère la liste via Tab_enu_etendu()
    // si (i) est un scalaire alors: posi_ddl_enum(i) représente la position que doit
    //    avoir de Ddl_enum_etendu(i) dans xi_
    // si (i) est de type  Coordonnee -> position du ddl_enum_etendu(i) dans tab_coor_
    // si (i) un tenseur -> position du ddl_enum_etendu(i) dans tab_tensBB_
    // si (i) une grandeur quelconque -> position du ddl_enum_etendu(i) dans t_quelc_
    const Tableau <int>& Index_dans_tableau() const {return posi_ddl_enum;};
 
 
    // retour des tailles qu'ont les différents tableaux associés au ddl_enum
         // tailles_tab(1) -> nb de scalaires
         //   (2) -> nb de Coordonnee
         //   (3) -> nb de tenseur
         //   (4) -> nb de grandeurs quelconques
    const Tableau <int>& Tailles_tab() const {return  tailles_tab;};

 
    // ramène le nombre de composantes de la fonction
    virtual int NbComposante() const =0;

    // Lecture des donnees de la classe sur fichier
    // le nom passé en paramètre est le nom de la Fonction
    // s'il est vide c-a-d = "", la methode commence par lire le nom sinon
    // ce nom remplace le nom actuel
    virtual void LectDonnParticulieres_Fonction_nD(const string& nom, UtilLecture * ) = 0;
 
    // mise à jour des variables globales: en fonction de l'apparition de nouvelles variables
    // globales en cours de calcul
    virtual void Mise_a_jour_variables_globales() = 0;
    
    // établir le lien entre la Fonction et des Fonctions déjà existantes dont
    // on connait que le nom
    // permet ainsi de complèter la Fonction
    // 1) renseigne si la Fonction dépend d'autre Fonction ou non
    virtual bool DependAutreFoncCourbes() const {return false;}; // par défaut non
    // 2) retourne une liste de nom correspondant aux noms de courbes dont dépend *this
    virtual list <string>& ListDependanceCourbes(list <string>& lico) const;
    // 3) retourne une liste de nom correspondant aux noms de Fonction dont dépend *this
    virtual list <string>& ListDependanceFonctions(list <string>& lico) const;
    // 4) établit la connection entre la demande de *this et les Fonctions passées en paramètres
    virtual void Lien_entre_fonc_courbe(list <Fonction_nD *>&  liptfonc,list <Courbe1D *>&  liptco) {};
    
    // def info fichier de commande
    virtual void Info_commande_Fonctions_nD(UtilLecture & entreePrinc) = 0;
    
 
    // calcul  des valeurs de la fonction, avec comme argument: uniquement des grandeurs
    // scalaires simples
    // retour d'un tableau de scalaires
    Tableau <double> & Valeur_FnD_tab_scalaire(Tableau <double >* val_double)
      {try
         {
//           #ifdef MISE_AU_POINT
           if (permet_affichage > 4)
            {
             cout << "\n fonction: "<<nom_ref<<" : ";
             if (permet_affichage > 5)
              {cout << "\n parametres d'appel: ";
               int nb_var = val_double->Taille();
               for (int j=1;j<=nb_var;j++)
                 { cout << " para("<<j<<")= "<< (*val_double)(j);}
              };
             Tableau <double> & inter = Valeur_FnD_interne(val_double);
             cout << "\n retour fonction: ";
             int nb_val = inter.Taille();
             for (int i=1;i<=nb_val;i++)
               cout << " val("<<i<<")= "<<inter(i);
             return inter;
            }
           else
//           #endif
             return Valeur_FnD_interne(val_double);
         }
       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_tab_scalaire(..."<<endl;
           this->Affiche();
           ErrCalculFct_nD toto;throw (toto);
           Sortie(1);
         };
        // on ne doit jamais arriver ici !
        return Valeur_FnD_interne(val_double); // pour taire le compilo
      };
 
    // calcul  des valeurs de la fonction, à l'aide de paramètres =  grandeurs évoluées
    // retour d'un tableau de scalaires
    // les différents tableaux doivent contenir toutes les informations nécessaires pour l'appel
    // NB: il peut y avoir plus d'info que nécessaire
    // l'ordre des paramètres doit respecter celui donné par les fonctions Index_dans_tableau()
    // il peut y avoir éventuellement des grandeurs quelconques et éventuellement des types non scalaire
    // dans ce dernier cas il faut renseigner le tableau de numéro d'ordre t_num_ordre
    Tableau <double> & Val_FnD_Evoluee(Tableau <double >* val_ddl_enum
                                       ,Tableau <Coordonnee> * coor_ddl_enum
                                       ,Tableau <TenseurBB* >* tens_ddl_enum
                                       ,Tableau <const TypeQuelconque *  >* tqi = NULL
                                       ,Tableau <int> * t_num_ordre = NULL
                                      )
      { if (equivalence_nom_enu_etendu_et_enu_quelconque)
         {try
            { Vers_tab_double(t_inter_double,val_ddl_enum,coor_ddl_enum,tens_ddl_enum
                        ,tqi,t_num_ordre);
//              #ifdef MISE_AU_POINT
              if (permet_affichage > 4)
               {cout << "\n fonction: "<<nom_ref<<" : ";
                if (permet_affichage > 5)
                 {cout << "\n parametres d'appel: ";
                  int nb_var = t_inter_double.Taille();
                  for (int j=1;j<=nb_var;j++)
                    { cout << " para("<<j<<")= "<< t_inter_double(j);}
                 };
                Tableau <double> & inter = Valeur_FnD_interne(&t_inter_double);
                cout << "\n retour fonction: ";
                int nb_val = inter.Taille();
                for (int i=1;i<=nb_val;i++)
                  cout << " val("<<i<<")= "<<inter(i);
                return inter;
               }
              else
//              #endif
                return Valeur_FnD_interne(&t_inter_double);
            }
           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_Evoluee(..."<<endl;
               ErrCalculFct_nD toto;throw (toto);
               this->Affiche();Sortie(1);
             };
         }
        else {cout << "\n erreur appel Val_FnD_Evoluee(, variables non definies ! ";
              this->Affiche();
              ErrCalculFct_nD toto;throw (toto);Sortie(1);
              return Valeur_FnD_interne(&t_inter_double); // pour taire le compilateur
             };
        // on ne doit jamais arriver ici !
        return Valeur_FnD_interne(&t_inter_double); // pour taire le compilo
      };
 
    //  mise à disposition des conteneurs pour l'appel de Valeur_FnD sans paramètres
    // il n'est pas autorisé de changer la taille du conteneur, c'est seulement les valeurs qui doivent
    // être modifiées sinon il y aura des pb
    // l'ordre des paramètres doit respecter celui donné par les fonctions Index_dans_tableau()
    Tableau <double >& Val_ddl_enum() {return val_ddl_enum;} // valeur associé à l'enu_etendu(i) si scalaire
    Tableau <Coordonnee >& Coor_ddl_enum() {return coor_ddl_enum;}; // idem  si Coordonnées (en orthonormée)
    // retourne le tableau de l'ensemble des grandeurs de type Coordonnee qui sont nécessaire pour l'appel
    // chaque type est repéré par premier_famille_Coord(j) ce qui correspond à coor_ddl_enum(j)
    Tableau <Ddl_enum_etendu>& Premier_famille_Coor() {return premier_famille_Coord;}

    Tableau <TenseurBB* >& Tens_ddl_enum() {return tens_ddl_enum;}; // idem si Tenseur (en orthonormée !)
    int Absolue() const {return absolue;} // indique si les tenseurs sont en absolue ou non

    Tableau <Ddl_enum_etendu>& Premier_famille_tenseur() {return premier_famille_tenseur;}
 
    // -- retourne une liste de grandeurs quelconques équivalentes aux types évoluées non scalaires
    // li_equi_Quel_evolue : est l'équivalent des grandeurs évoluées: coor_ddl_enum et tens_ddl_enum
    // permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs évoluées
    // non scalaires
    // l'ordre l'apparition dans la liste est telle que l'on a:
    // 1) tous les Coordonnees 2) puis tous les tenseurs
    // dans le même ordre que pour les tableaux: coor_ddl_enum puis tens_ddl_enum
    // =>=>=> important: il est permis "que" de changer les valeurs dans les conteneurs
    List_io <TypeQuelconque >&  Li_equi_Quel_evolue() {return li_equi_Quel_evolue;};

    // -- retourne une liste des grandeurs évoluées uniquement scalaire
    // permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs scalaires
    // est équivalent à val_ddl_enum, l'ordre d'apparition est celui de val_ddl_enum
    // =>=>=> important: il est permis "que" de changer les valeurs dans les conteneurs
    List_io <Ddl_enum_etendu>& Li_enu_etendu_scalaire() {return li_enu_etendu_scalaire;}
 
    // calcul équivalent, cf. les paramètres de passage
    // pour que l'appel à cette méthode soit correcte, il faut que les listes correspondent
    // à celles de Li_equi_Quel_evolue(), et Li_enu_etendu_scalaire(),
    // =>=>=> il faut donc utiliser ces listes en les récupérants auparavant !!
    // Si t_num_ordre est Null cela signifie que tous les tqi sont de grandeurs scalaire
    // dans le cas contraire t_num_ordre(i) donne le numéro d'ordre du scalaire dans tqi qui correspond à Nom_variable(i)
    // =>=>=> important: il est permis "que" de changer les valeurs dans les conteneurs
    Tableau <double> & Valeur_FnD_Evoluee(Tableau <double >* val_ddl_enum
                                          ,List_io <Ddl_enum_etendu>* li_evolue_scalaire
                                          ,List_io <TypeQuelconque >* li_evoluee_non_scalaire
                                          ,Tableau <const TypeQuelconque *  >* tqi
                                          ,Tableau <int> * t_num_ordre)
      { if (equivalence_nom_enu_etendu_et_enu_quelconque)
         { try
            {Vers_tab_double(t_inter_double,val_ddl_enum,li_evolue_scalaire,li_evoluee_non_scalaire,tqi,t_num_ordre);
//             #ifdef MISE_AU_POINT
             if (permet_affichage > 4)
              {cout << "\n fonction: "<<nom_ref<<" : ";
               if (permet_affichage > 5)
                {cout << "\n parametres d'appel: ";
                 int nb_var = t_inter_double.Taille();
                 for (int j=1;j<=nb_var;j++)
                   { cout << " para("<<j<<")= "<< t_inter_double(j);}
                };
               Tableau <double> & inter = Valeur_FnD_interne(&t_inter_double);
               cout << "\n retour fonction: ";
               int nb_val = inter.Taille();
               for (int i=1;i<=nb_val;i++)
                 cout << " val("<<i<<")= "<<inter(i);
               return inter;
              }
             else
//             #endif
              return Valeur_FnD_interne(&t_inter_double);
            }
           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_Evoluee(..."<<endl;
               this->Affiche();
               ErrCalculFct_nD toto;throw (toto);
               Sortie(1);
             };
         }
        else {cout << "\n erreur appel Val_FnD_Evoluee(, variables non definies ! ";
              // on génère une interruption ce qui permettra de dépiler les appels
              this->Affiche();
              ErrCalculFct_nD toto;throw (toto);
              Sortie(1);
              return Valeur_FnD_interne(&t_inter_double); // pour taire le compilateur
             };
        // on ne doit jamais arriver ici !
        return Valeur_FnD_interne(&t_inter_double); // pour taire le compilo
      };

    // 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
    // Si t_num_ordre est Null cela signifie que tous les tqi sont de grandeurs scalaire
    // dans le cas contraire t_num_ordre(i) donne le numéro d'ordre du scalaire dans tqi qui correspond à Nom_variable(i)
    Tableau <double> & Valeur_FnD(Tableau <Ddl_etendu> * t_enu,Tableau <const TypeQuelconque * > * tqi
                                           ,Tableau <int> * t_num_ordre);
 
    // indicateur permettant de connaître rapidement si
    // la fonction dépend de la position d'un point M: ici au temps tdt
    // 0 : la fonction ne dépend pas de la position d'un point M
    // =i non nul : la fonction dépend de la position d'un point M
    // et  =  le nombre de composantes demandés (ne sert pas vraiment)
    // dans ce cas, une au moins des nom_variables a un nom de la même famille que le ddl X1
    // si = -1 : cela signifie que la fonction dépend "que" de M
    int Depend_M() const {return depend_M;}; // cas d'une position courante
    int Depend_Mt() const {return depend_Mt;}; // cas de la position spécifiquement a t
    int Depend_M0() const {return depend_M0;}; // cas de la position initiale

    // calcul des valeurs de la fonction, dans le cas où les variables
    // sont "tous" des grandeurs globales
    Tableau <double> & Valeur_pour_variables_globales()
      { try
            {
//             #ifdef MISE_AU_POINT
             if (permet_affichage > 4)
              {cout << "\n fonction: "<<nom_ref<<" : ";
               Tableau <double> & inter = Valeur_pour_variables_globales_interne();
               cout << "\n retour fonction: ";
               int nb_val = inter.Taille();
               for (int i=1;i<=nb_val;i++)
                 cout << " val("<<i<<")= "<<inter(i);
               return inter;
              }
             else
//             #endif
               return Valeur_pour_variables_globales_interne();
            }
        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  Valeur_pour_variables_globales(..."<<endl;
            ErrCalculFct_nD toto;throw (toto);
            this->Affiche();Sortie(1);
          };
        // on ne doit jamais arriver ici !
        return Valeur_pour_variables_globales_interne(); // pour taire le compilo
      };
 
//  ---- fonctions internes qui ne "doivent pas !!!" être utilisée directement ---
    // elles sont mises en public, pour pouvoir être appelées par les classes dérivées
    // sans avoir à déclarer en friend les classes dérivées, sinon cela fait une boucle
    // sans fin, d'où la solution choisit pour éviter ce pb
 
    // calcul  des valeurs de la fonction, retour d'un tableau de scalaires
    virtual Tableau <double> & Valeur_FnD_interne(Tableau <double >* val_ddl_enum) = 0;

    // calcul des valeurs de la fonction, dans le cas où les variables
    // sont "tous" des grandeurs globales
    virtual Tableau <double> & Valeur_pour_variables_globales_interne() = 0;

	//----- 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)
	   virtual void Lecture_base_info(ifstream& ent,const int cas) = 0;
    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
	   virtual void Ecriture_base_info(ofstream& sort,const int cas) = 0;
    // sortie du schemaXML: en fonction de enu 
    virtual void SchemaXML_Fonctions_nD(ofstream& sort,const Enum_IO_XML enu) = 0;
     
    // ---------- static ---------
    
    // ramène un pointeur sur la Fonction correspondant au type de Fonction passé en paramètre
    // IMPORTANT : il y a création d'une Fonction (utilisation d'un new)
    static Fonction_nD* New_Fonction_nD(string& nom,EnumFonction_nD typeFonction);
    // ramène un pointeur sur une Fonction copie de celle passée en paramètre
    // IMPORTANT : il y a création d'une Fonction (utilisation d'un new)
    static Fonction_nD* New_Fonction_nD(const Fonction_nD& Co);
    
    // ramène la liste des identificateurs de Fonctions actuellement disponibles
    static list <EnumFonction_nD> Liste_Fonction_disponible();
    
    // ---------- non virtuelle ---------
    
    // ramène le type de la Fonction
    EnumFonction_nD Type_Fonction() const { return typeFonction;};

     
  protected :
    
    // VARIABLES PROTEGEES :
    EnumFonction_nD typeFonction; // type de la fonction
    string nom_ref; // nom de référence de la Fonction
 
    Tableau <string > nom_variables; //variables de la fonction, vu de l'extérieur
    Tableau <double > t_inter_double; // tableau de même dimension que nom_variable
                  // sert pour passer les infos à la méthode Valeur_FnD_interne(..
 
    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 noms en string
      // de variables globales
      // éventuellement vide s'il ne sert pas
 
    // *** important: les tableaux nom_variables, enu_variables_globales et
    // nom_variables_globales  s'ajoutent
    // ils ne sont pas liés entre eux: le nombre total de variables est
    // la somme des trois tableaux. En général c'est soit l'un , soit l'autre
    // ou le dernier mais on peut avoir un mixte
 
    // ---- tableaux de grandeurs équivalentes aux nom_variables (locales) -----
    // un tableau tab_enu_etendu et un tableau tab_enu_quelconque:
    // tab_enu_etendu.Taille()+tab_enu_quelconque.Taille() == nom_variables.Taille() -> grandeurs locales
    Tableau <Ddl_enum_etendu> tab_enu_etendu;
 
    // tab_enu_etendu peut se décomposer de deux manières équivalentes :
    // 1) tableaux: val_ddl_enum (scalaires) , coor_ddl_enum (Coordonnees) , tens_ddl_enum (tenseur)
    //   permet aux utilisateurs d'obtenir un stockage et un appel avec des grandeurs évoluées, distinctes
    // 2) list: li_enu_etendu_scalaire (scalaires) , li_equi_Quel_evolue (Coordonnees "et" tenseurs)
    // permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs scalaires
    // et permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs évoluées
    // excluant les scalaire, et appels associés
    // li_equi_Quel_evolue correspond à des grandeurs quelconques contenant Coordonnees et tenseur,
    // est indépendant de tab_enu_quelconque, qui lui est complètement quelconque, on ne sait pas a priori
    // ce qu'il y a dedans
 
    // .. chaque grandeur quelconque doit être associé, lors de l'appel de la fonction, à un numéro d'ordre
    // du coup, pour l'instant on n'utilise qu'un scalaire par grandeur quelconque, mais le conteneur
    // peut en contenir plusieurs
    Tableau <EnumTypeQuelconque> tab_enu_quelconque;

    //  ----- grandeurs évoluées y compris les grandeurs quelconques -------
    // .. chaque nom_variables(j) est associé à :
    Tableau <int> type_des_variables; // si type_des_variables(j) = 1 -> un scalaire
                                // si type_des_variables(j) = 2 -> des coordonnées de dim absolue
                                // si type_des_variables(j) = 3 -> un tenseur de dim absolue
                                // si type_des_variables(j) = 4 -> une grandeur quelconque
                                // si type_des_variables(j) = 0 -> une grandeur qui n'est pas reconnue en local
 
    // .... dans le cas d'un Ddl_enum_etendu : donc c'est relatif au tableau: tab_enu_etendu
    Tableau <double > val_ddl_enum; // valeur associé au ddl tab_enu_etendu(i) si scalaire
                      // tab_enu_etendu(i) <=> val_ddl_enum(posi_ddl_enum(i))
    List_io <Ddl_enum_etendu> li_enu_etendu_scalaire; // est équivalent à val_ddl_enum,
    // permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs scalaires
 
    Tableau <Ddl_enum_etendu> premier_famille_Coord; // les ddl du premier de famille
        //coor_ddl_enum(j) est associé avec premier_famille_Coord(j)
    Tableau <Coordonnee > coor_ddl_enum; // le vecteur Coordonnée associé au ddl tab_enu_etendu(i) si Coordonnées
    Tableau <int > num_dans_coor; // le numéro dans le vecteur associé au ddl tab_enu_etendu(i)
                // avec j = posi_ddl_enum(i)
                // tab_enu_etendu(i) <=> coor_ddl_enum(j)(num_dans_coor(i))
    // bien noter qu'un objet Coordonnee peut contenir plusieurs Ddl_enum_etendu

    Tableau <Ddl_enum_etendu> premier_famille_tenseur; // les ddl du premier de famille
                         // (*tens_ddl_enum)(j) est associé avec premier_famille_tenseur(j)
    Tableau <TenseurBB* > tens_ddl_enum; // tenseur associé au ddl tab_enu_etendu(i) si Tenseur
    int absolue; // indique si les tenseurs sont en absolue ou non
    Tableau <Deuxentiers_enu > ind_tens; // indice dans le tenseur de la grandeur
                // avec j = posi_ddl_enum(i)
                // avec k = ind_tens(i).i et l = ind_tens(i).j
                // tab_enu_etendu(i) <=> (*tens_ddl_enum)(j)(k,l)
    // bien noter qu'un objet Tenseur peut contenir plusieurs Ddl_enum_etendu

    // li_equi_Quel_evolue : est l'équivalent des grandeurs évoluées: coor_ddl_enum et tens_ddl_enum
    // permet aux utilisateurs d'accèder à un stockage transitoire contenant "que" les grandeurs évoluées
    List_io <TypeQuelconque > li_equi_Quel_evolue;  // non scalaires
 
    // tab_equi_Coor(j) contient un Coordonnee équivalent à coor_ddl_enum(j)
    Tableau <List_io<TypeQuelconque >::iterator > tab_equi_Coor;
    //tab_equi_tens(j) contient un tenseur équivalent à tens_ddl_enum(j)
    Tableau <List_io<TypeQuelconque >::iterator > tab_equi_tens;


    // un système d'adressage indirect pour le passage : tab_enu_etendu(i) <-> grandeur évoluée
    Tableau <int> posi_ddl_enum; // posi_ddl_enum(i) donne la position de tab_enu_etendu(i)
    // dans le tableau :
    // si scalaire    : dans le tableau val_ddl_enum ->val_ddl_enum(posi_ddl_enum(i))
    // si Coordonnées : dans le tableau coor_ddl_enum -> coor_ddl_enum(posi_ddl_enum(i))
    //                 ici il s'agira de tous les ddl de la même famille,
    //                 et c'est num_dans_coor qui permet de trouver la position
    // si Tenseur     : dans le tableau tens_ddl_enum -> tens_ddl_enum(posi_ddl_enum(i))
    //                 et c'est ind_tens qui permettra de trouver les indices

    // un système d'adressage indirect pour le passage : nom_variables(j) <-> grandeur évoluée
    // tab_enu_etendu(i) correspond à nom_variables(index_enu_etendu(i))
    Tableau <int> index_enu_etendu;

    // .... dans le cas d'une grandeur quelconque
    // pour les grandeurs quelconques, l'utilisateur doit transmettre le numéro d'ordre correspondant à l'équivalence
    // du ddl_etendu, du coup on ne s'occupe pas de gérer les numéros d'ordre pour les grandeurs quelconques

    // un système d'adressage indirect pour le passage : nom_variables(j) <-> grandeur quelconque
    // tab_enu_quelconque(i) correspond à nom_variables(index_enu_quelconque(i))
    Tableau <int> index_enu_quelconque;

 
    // stockage des tailles qu'ont les différents tableaux associés
    Tableau <int> tailles_tab; // tailles_tab(1) -> nb de scalaires
                               //   (2) -> nb de Coordonnee
                               //   (3) -> nb de tenseur
                               //   (4) -> nb de grandeurs quelconques
    //  ----- fin grandeurs évoluées  y compris les grandeurs quelconques-------
 
    // ces deux tableaux permettent d'appeler la méthode Valeur(..
    // un booléen pour noter l'équivalence parfaite ou non
    bool equivalence_nom_enu_etendu_et_enu_quelconque;
 
    // un tableau intermédiaire qui sert pour Valeur(Tableau <Ddl_etendu> ...
    // c-a-d pour les variables non globales
    Tableau <double > x_x_i;
    // un tableau intermédiaire qui sert pour toutes les variables globales
    Tableau <double > x_glob;
 
    int depend_M; // indicateur permettant de connaître rapidement si
        // la fonction dépend de la position courante d'un point M 
        // 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
    int depend_Mt; // idem pour le temps t
    int depend_M0; // idem pour le temps 0
 
    bool depend_temps; // indicateur permettant de connaître rapidement si
        // la fonction dépend du temps ou non
 
    // ----- controle de la sortie des informations: utilisé par les classes dérivées
    int permet_affichage; // pour permettre un affichage spécifique dans les méthodes, pour les erreurs et warning
 
    //-------------------------------------------------------------------------------

    // METHODES PROTEGEES :
    // ramène true si les variables de la classe mère sont complèté
    bool Complet_var() const;
 
    // définit le paramètre depend_M en fonction des nom_variables
    void Definition_depend_M();
 
    // définit le paramètre depend_temps en fonction des nom_variables
    void Definition_depend_temps();
 
    // construction à partir des noms de variables, des tableaux tab_enu_etendu et
    // tab_enu_quelconque
//    void Construction_enu_etendu_et_quelconque();
 
    // Contruction des index pour les grandeurs évoluées, ainsi que les conteneurs
    void Construction_index_conteneurs_evoluees();
 
    // Passage des infos variables évoluées en tableau de réels
    // I/O : d
    Tableau <double > & 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 = NULL
                                 ,const Tableau <int> * t_num_ordre = NULL);
    // idem, mais via les listes
    // val_ddl_enum(k) correspond à li_evolue_scalaire de rang i
    Tableau <double > & 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 = NULL
                                 ,const Tableau <int> * t_num_ordre = NULL);

    // 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 Mise_a_jour_variables_globales_interne();

    // 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
    // ****** fonction a priori dangereuse, à éviter , pour l'instant ne sert pas !! ****
    double Val_avec_nbArgVariable(double x,...);
 
    // 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& Transfert_info(const Fonction_nD& elt);
 
    // affichage des données internes, utilisée par les fonctions dérivées
    // niveau donne le degré d'affichage
    void Affiche_interne(int niveau) const;
 
    //------ 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 Lect_base_info(ifstream& ent,const int cas);
    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
    void Ecrit_base_info(ofstream& sort,const int cas);
    // sortie du schemaXML: en fonction de enu
    void SchemXML_Fonctions_nD(ofstream& sort,const Enum_IO_XML enu);
    
    // lecture d'une ou plusieurs variables
    // peut-être appelée plusieurs fois,
    // stockage des infos dans Fonction_nD
    void Lecture_variables(string& nom_lu,UtilLecture * entreePrinc);
    // méthode pour savoir si le nom_lu est un mot clé relatif à la lecture de variables
    bool Est_relatif_a_lecture_variable(string& nom_lu)
     {if (   (nom_lu == "un_argument=")
          || (nom_lu == "deb_list_var_")
         )
           return true;
      else return false;
      };
 
    // affichage des variables de la fonction, dépend du niveau d'impression
    void Affichage_variables() const;
    
    // récupération des valeurs des variables globales et stockage dans le tableau
    // interne x_glob
    void Recup_Grandeurs_globales();

  private :
 
    // un tableau intermédiaire, en général vide, mais qui sert si on utilise
    // la méthode Val_avec_nbArgVariable
    Tableau <double >* xinter=NULL;
 
 
 };
 /// @}  // end of group

#endif  
