// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) <https://www.irdl.fr/>.
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL  : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//
// For more information, please consult: <https://herezh.irdl.fr/>.

//#include "Debug.h"
# include "Met_abstraite.h"   
# include "Util.h"
# include "TypeConsTens.h"
using namespace std;  //introduces namespace std
#include <cmath>
  
//  =========================================================================================
//  vu la taille des executables le fichier est decompose en trois
// le premier : Met_abstraite1s2.cp concerne les constructeurs, destructeur et 
//              la gestion des variables
// le deuxième :  Met_abstraite2s2.cp concerne  le calcul des méthodes publiques
// le troisième:  Met_abstraite2s2.cp concerne  le calcul des méthodes privées
//  =========================================================================================

// ***********$ il faut utiliser des références pour optimiser l'opérateur parenthèse
/// ceci dans la plupart des routines gourmandes !!!!!!!!!!!!!!!!!!!!



// METHODES PUBLIQUES :
//  ------------------------ calculs ----------------------------------------
	 // cas explicite à t, toutes les grandeurs sont a 0 ou t	
	 // gradV_instantane : true : calcul du gradient de vitesse instantannée 
     // premier_calcul : true : cas d'un premier calcul -> toutes les grandeurs sont calculées
     //                  false: uniquement les grandeurs à t sont calculées	    
 const Met_abstraite::Expli&  Met_abstraite::Cal_explicit_t
		( const Tableau<Noeud *>& tab_noeud,bool gradV_instantane, const  Mat_pleine& dphi,int nombre_noeud
          ,const Vecteur& phi,bool premier_calcul)
	{ if (premier_calcul)
	    { Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
	      Calcul_gijBB_0 ();  // metrique base naturelle
	      Calcul_gijHH_0 ();  // composantes controvariantes à 0
	      Calcul_giH_0();     // base duale
       Jacobien_0();   // jacobien initiale
     };
      // calcul des grandeurs à t
	  Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
///	  Calcul_gradVBB_moyen_t(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
	  Calcul_gijBB_t ();  //      "
	  Calcul_gijHH_t ();  // composantes controvariantes à t
	  Jacobien_t();         // calcul du jacobien a t
	  Calcul_giH_t();    // base duale à t
	  D_giB_t(dphi,nombre_noeud,phi);   //
//	  DgradVmoyBB_t(); // variation du gradient moyen
	  D_gijBB_t();    //variation de la  metrique en BB
	  if (gradV_instantane)
	    {  
       #ifdef MISE_AU_POINT
        if (!(tab_noeud(1)->Existe_ici(V1))) // on vérifie que les vitesses existent aux noeuds
           { cout << "\nErreur : pas de ddl de vitesse pour le calcul du gradient instantanne ";
             cout << "\n  Met_abstraite::Cal_explicit_t(..." << endl;
             Sortie(1);
            } 
       #endif
	      Calcul_gradVBB_t(tab_noeud,dphi,nombre_noeud); // calcul du gradient de vitesse
		   };
   // liberation des tenseurs intermediaires
   LibereTenseur();
  //    return ex;  
   return ex_expli;	  
	};
	
	 // cas explicite à tdt, toutes les grandeurs sont a 0 ou tdt	
	 // gradV_instantane : true : calcul du gradient de vitesse instantannée 
     // premier_calcul : true : cas d'un premier calcul -> toutes les grandeurs sont calculées
     //                  false: uniquement les grandeurs à t sont calculées	    
const  Met_abstraite::Expli_t_tdt&  Met_abstraite::Cal_explicit_tdt
                ( const Tableau<Noeud *>& tab_noeud,bool gradV_instantane, const  Mat_pleine& dphi
                 ,int nombre_noeud,const Vecteur& phi,bool premier_calcul)
	{ if (premier_calcul)
	    { Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
	      Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
	      Calcul_gijBB_0 ();  // metrique base naturelle
//---debug
//     string tutut;
//     cout << "/n Met_abstraite::Cal_explicit_tdt: une donnee "; cin >> tutut;
//-- fin debug	  
	      Calcul_gijHH_0 ();  // composantes controvariantes à 0
	      Calcul_giH_0();     // base duale
       Jacobien_0();   // jacobien initiale
	      ///	  Calcul_gradVBB_moyen_t(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
	      Calcul_gijBB_t ();  // metrique  à t
//---debug
//     cout << "/n Met_abstraite::Cal_explicit_tdt: une donnee "; cin >> tutut;
//-- fin debug	  
	      Calcul_gijHH_t ();  // metrique  à t
//---debug
//     string titit;
//    cout << "/n Met_abstraite::Cal_explicit_tdt: apres Calcul_gijHH_t (); "; cin >> tutut;
//-- fin debug	  
	      Calcul_giH_t();     // base duale
       Jacobien_t();   // jacobien à t
     };
      // calcul des grandeurs à tdt
	   Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
	   ///	  Calcul_gradVBB_moyen_tdt(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
 	  Calcul_gijBB_tdt ();  //      "
//---debug
//     string tutut;
//     cout << "/n Met_abstraite::Cal_explicit_tdt: une donnee "; cin >> tutut;
//-- fin debug	  
	   Calcul_gijHH_tdt ();        // composantes controvariantes à tdt
//---debug
//     string titit;
//     cout << "/n Met_abstraite::Cal_explicit_tdt: apres Calcul_gijHH_tdt (); "; cin >> tutut;
//-- fin debug	  
    Jacobien_tdt();         // calcul du jacobien a tdt
////---debug
//    #ifdef MISE_AU_POINT
//    if (ParaGlob::NiveauImpression() > 2)
//      if ((jacobien_tdt <= 0.)|| (std::isinf(jacobien_tdt))||( std::isnan(jacobien_tdt))) // vérif du jacobien
//       {int nbn = tab_noeud.Taille();
//        cout << "\n *** attention jacobien negatif (Met_abstraite::Cal_explicit_tdt(..) , info sur les noeuds: \n";
//        for (int i=1;i<=nbn;i++)
//           tab_noeud(i)->Affiche(cout);
//       };
//    #endif
////--- fin debug

    Calcul_giH_tdt();    // base duale à tdt
    D_giB_tdt(dphi,nombre_noeud,phi);   //
    D_gijBB_tdt();    //variation de la  metrique en BB
    if (gradV_instantane)
	    {  
      #ifdef MISE_AU_POINT
       if (!(tab_noeud(1)->Existe_ici(V1))) // on vérifie que les vitesses existent aux noeuds
         { cout << "\nErreur : pas de ddl de vitesse pour le calcul du gradient instantanne ";
           cout << "\n  Met_abstraite::Cal_explicit_tdt(..." << endl;
           Sortie(1);
          } 
       #endif
	      Calcul_gradVBB_tdt(tab_noeud,dphi,nombre_noeud); // calcul du gradient de vitesse
		   };
    // liberation des tenseurs intermediaires
    LibereTenseur();
//---debug
//     string titit;
//     cout << "/n Met_abstraite::Cal_explicit_tdt: apres LibereTenseur(); "; cin >> tutut;
//-- fin debug	  
    return ex_expli_t_tdt;	  
	};
	
// cas implicite, toutes les grandeurs sont a 0 ou t+dt	
// lorsque avec_D est false alors il n'y a pas de calcul des variations seconde de la métrique
// gradV_instantane : true : calcul du gradient de vitesse instantannée
// premier_calcul : true : cas d'un premier calcul -> toutes les grandeurs sont calculées
//                  false: uniquement les grandeurs à t sont calculées
// avec_var_Xi  : par défaut true, si false indique que l'on ne calcule pas les variations / au ddl Xi
const Met_abstraite::Impli& Met_abstraite::Cal_implicit
              ( const  Tableau<Noeud *>& tab_noeud,bool gradV_instantane, const  Mat_pleine& dphi, 
                int nombre_noeud,const Vecteur& phi,bool premier_calcul,bool avec_var_Xi)
	{if (premier_calcul)
	  {Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
	   Calcul_gijBB_0 ();    // metrique base naturelle
	   Calcul_gijHH_0 ();  // composantes controvariantes à 0
	   Calcul_giH_0();     // base duale
    Jacobien_0();   // jacobien initiale
	   Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
	   ///	  Calcul_gradVBB_moyen_t(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
       /// 	  gradVmoyBB_t(dphi); // calcul variation du gradient moyen à t
	   Calcul_gijBB_t ();  // métrique    a t
////--- debug
//cout << "\n debug Met_abstraite::Cal_implicit ";
//cout << "\n gijBB_t= "; gijBB_t->Ecriture(cout);
//cout << endl;
////--- fin debug
	   Calcul_gijHH_t ();  // métrique    a t
	   Calcul_giH_t();    // base duale à t
    Jacobien_t();   // jacobien à t
	   }

	 Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
	 ///	  Calcul_gradVBB_moyen_tdt(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
 	 ///      DgradVmoyBB_tdt(dphi); // calcul variation du gradient moyen à tdt
	 Calcul_gijBB_tdt ();  //     de la métrique     finale
	 Calcul_gijHH_tdt ();  // composantes controvariantes
	 Jacobien_tdt();       // calcul du jacobien a tdt
	 Calcul_giH_tdt();     // base duale
  if (avec_var_Xi)
	   { D_giB_tdt(dphi,nombre_noeud,phi);   //
	     D_gijBB_tdt();    //variation de la  metrique en BB et de la variation du gradient de vitesse moyen à tdt
	     D_giH_tdt();         // variation de la base duale
	     D_gijHH_tdt();    //variation de la  metrique en HH
	     Djacobien_tdt();    // variation du jacobien
    };
     
////---debug
//cout << "\n base 0 " << (*giB_0);
//cout << "\n base t " << (*giB_t);
//cout << "\n base tdt " << (*giB_tdt);
////--- fin debug
     
     
	 if (gradV_instantane)
	    {  
          #ifdef MISE_AU_POINT
	        if (!(tab_noeud(1)->Existe_ici(V1))) // on vérifie que les vitesses existent aux noeuds
			 { cout << "\nErreur : pas de ddl de vitesse pour le calcul du gradient instantanne ";
			   cout << "\n  Met_abstraite::Cal_explicit_tdt(..." << endl;
			   Sortie(1);
			  } 
          #endif
	      Calcul_gradVBB_tdt(tab_noeud,dphi,nombre_noeud); // calcul du gradient de vitesse
	      DgradVBB_tdt(dphi); // calcul de la variation du gradient de vitesse instantannée
		 }
	     
     // liberation des tenseurs intermediaires
     LibereTenseur();   
     return ex_impli;
	};

// calcul de gijHH_0 et de giH_0 juste après le calcul implicite ou explicite (sinon il y a erreur)
const Met_abstraite::gijHH_0_et_giH_0& Met_abstraite::Cal_gijHH_0_et_giH_0_apres_im_expli()
 { Calcul_gijHH_0 ();  // métrique    en deux contravariants à t=0
   Calcul_giH_0();    // base duale  à t=0
   return ex_gijHH_0_et_giH_0;
  }; 
           
        //   calcul et récupération de la variation seconde de la métrique à t+dt
        //   total = true : indique que le calcul est complet, à partir des données de base 
        //                  c-a-d calcul de la variation de vecteur de base puis calcul de la variation seconde
        //         = false: le calcul est simplifié, on considère que la variation des vecteurs de base vient
        //                  juste d'être calculé, dans un calcul implicit, on ne calcul alors que la variation seconde
const Tableau2 <TenseurBB * > & Met_abstraite::CalVar2GijBBtdt
                                    (bool total,const  Mat_pleine& dphi,int nombre_noeud,const Vecteur& phi)
  { if (total)
	   D_giB_tdt(dphi,nombre_noeud,phi);   
    // puis variation seconde
    D2_gijBB_tdt();    
    return d2_gijBB_tdt;                                		
  };

// --------------- cas de la dynamique --------------------	
	
		// calcul pour la matrice masse
const Met_abstraite::Dynamiq& Met_abstraite::Cal_pourMatMass
              ( const  Tableau<Noeud *>& tab_noeud, const  Mat_pleine& dphi, 
              int nombre_noeud,const Vecteur& phi)
  {  Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
	    Calcul_gijBB_0 ();    // metrique base naturelle
     Jacobien_0();   // jacobien initiale
//	 Calcul_gradVBB_moyen_t(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
//	 Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
//	 Calcul_gradVBB_moyen_tdt(tab_noeud,dphi,nombre_noeud); // gradient de vitesse moyen
//	 Calcul_gijBB_tdt ();  //     de la métrique     finale
//	 Jacobien_tdt();       // calcul du jacobien a tdt
     // liberation des tenseurs intermediaires
     LibereTenseur();   
	    return ex_Dynamiq;
	};

		// ========== remontee aux informations =========================
// pour la remontee au infos duaux	
const Met_abstraite::InfoImp& Met_abstraite::Cal_InfoImp
   ( const  Tableau<Noeud *>& tab_noeud,  const Mat_pleine& dphi, 
     const Vecteur& phi, int nombre_noeud)
  {   Calcul_M0(tab_noeud,phi,nombre_noeud);
      Calcul_Mtdt(tab_noeud,phi,nombre_noeud);
      Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
      Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
      Calcul_gijBB_0 ();  //      "
      Calcul_gijHH_0 ();        // composantes controvariantes
      Calcul_gijBB_tdt ();  //      "
      Calcul_gijHH_tdt ();        // composantes controvariantes
      // bases duales
      Calcul_giH_0(); 
      Calcul_giH_tdt(); 
      
      // retour des infos
      // liberation des tenseurs intermediaires
      LibereTenseur();   
//      return ex; 
      return ex_InfoImp;
   };
   
const Met_abstraite::InfoExp_t& Met_abstraite::Cal_InfoExp_t
     ( const Tableau<Noeud *>& tab_noeud, const  Mat_pleine& dphi,
       const Vecteur& phi, int nombre_noeud)
  {   Calcul_M0(tab_noeud,phi,nombre_noeud);
      Calcul_Mt(tab_noeud,phi,nombre_noeud);
      Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
      Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
      Calcul_gijBB_0 ();  //      "
      Calcul_gijHH_0 ();        // composantes controvariantes
      Calcul_gijBB_t ();  //      "
      Calcul_gijHH_t ();        // composantes controvariantes
      // bases duales
      Calcul_giH_0();
      Calcul_giH_t(); 
      // retour des infos
      // liberation des tenseurs intermediaires
      LibereTenseur();   
//      return ex;
      return ex_InfoExp_t;    
   };
   
const Met_abstraite::InfoExp_tdt& Met_abstraite::Cal_InfoExp_tdt
     ( const Tableau<Noeud *>& tab_noeud, const  Mat_pleine& dphi,
       const Vecteur& phi, int nombre_noeud)
  {   Calcul_M0(tab_noeud,phi,nombre_noeud);
      Calcul_Mtdt(tab_noeud,phi,nombre_noeud);
      Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
      Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
      Calcul_gijBB_0 ();  //      "
      Calcul_gijHH_0 ();        // composantes controvariantes
      Calcul_gijBB_tdt ();  //      "
      Calcul_gijHH_tdt ();        // composantes controvariantes
      // bases duales
      Calcul_giH_0();
      Calcul_giH_tdt();
      // retour des infos
      // liberation des tenseurs intermediaires
      LibereTenseur();   
      return ex_InfoExp_tdt;    
   };
      
// cas sortie d'info à 0 t et tdt: point, giB, giH,
// calcul des termes de la classe Info0_t_tdt 	
const Met_abstraite::Info0_t_tdt& Met_abstraite::Cal_Info0_t_tdt
     ( const Tableau<Noeud *>& tab_noeud,  const  Mat_pleine& dphi
      ,const Vecteur& phi, int nombre_noeud)
  {   Calcul_M0(tab_noeud,phi,nombre_noeud);
      Calcul_Mt(tab_noeud,phi,nombre_noeud);
      Calcul_Mtdt(tab_noeud,phi,nombre_noeud);
      Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
      Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
      Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a tdt
      Calcul_gijBB_0 ();  //      "
      Calcul_gijHH_0 ();        // composantes controvariantes
      Calcul_gijBB_t ();  //      "
      Calcul_gijHH_t ();        // composantes controvariantes
      Calcul_gijBB_tdt ();  //      "
      Calcul_gijHH_tdt ();        // composantes controvariantes
      // bases duales
      Calcul_giH_0();
      Calcul_giH_t();
      Calcul_giH_tdt(); 
      // retour des infos
      // liberation des tenseurs intermediaires
      LibereTenseur();   
      return ex_Info0_t_tdt;    
   };

// cas du calcul de la déformation d'Almansi uniquement
const Met_abstraite::Pour_def_Almansi Met_abstraite::Cal_pour_def_Almansi_au_temps
     (Enum_dure temps,const Tableau<Noeud *>& tab_noeud,const  Mat_pleine& dphi,int nombre_noeud
     ,const Vecteur& phi)
 { Met_abstraite::Pour_def_Almansi pdamsi;
   Calcul_giB_0(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t=0
   Calcul_gijBB_0 ();  // metrique base naturelle
   pdamsi.gijBB_0=gijBB_0;
   switch (temps)
    { case TEMPS_t:
       { // calcul des grandeurs à t
         Calcul_giB_t(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
         Calcul_gijBB_t ();  //      "
         pdamsi.gijBB=gijBB_t;
	        break;
       }
      case TEMPS_tdt:
       { // calcul des grandeurs à tdt
         Calcul_giB_tdt(tab_noeud,dphi,nombre_noeud,phi); // calcul de la base a t
         Calcul_gijBB_tdt ();  //      "
         pdamsi.gijBB=gijBB_tdt;
	        break;
	      }
      case TEMPS_0:
       { // on ne fait rien, c'est déjà calculé
         break;
       }
	   };
  return pdamsi;
 }; 

// cas du calcul de la déformation logarithmique uniquement
const Met_abstraite::Pour_def_log Met_abstraite::Cal_pour_def_log_au_temps
		     (Enum_dure ,const Tableau<Noeud *>& ,const  Mat_pleine& 
		     ,int ,const Vecteur& ) 
		     	{cout << "\n erreur, calcul non fonctionnelle !! "
		     	      << "\n Met_abstraite::Pour_def_log Met_abstraite::Cal_pour_def_log_au_temps(.." << endl;
		     	 Sortie(1);
		     		// pour l'instant rien
		     		Met_abstraite::Pour_def_log toto;
		     		return toto;
		     	}; 
		     	
// construction d'une métrique umat
//  - construction d'une métrique qui dépend du paramétrage matériel = X_(0)^a 
//  - en fonction d'une métrique normale fonction de l'interpolation sur 
//    les éléments de référence c'est-à-dire theta^i
const Met_abstraite::Umat_cont& Met_abstraite::Construction_Umat(const Met_abstraite::Impli& ex)
	{     // construction de la métrique umat associée qui correspond à l'opérateur gradient,
       // c'est-à-dire la métrique correspondant aux coordonnées initiales considérées comme
       // paramétrage matériel 
       // d'où dans ce cas gijBB_0 et gijHH_0 correspondent à l'identité
       // a priori on est en dim=3
       // *** modif février 2018: on considère aussi le cas et nb_vecteur = 2
       #ifdef MISE_AU_POINT
         if ((dim_base!= 3))// || (nbvec_base != 3))
   	       { cout << "\n erreur la dimension est different de trois"
   	              << " dim_base = " << dim_base //<< " nbvec_base= " << nbvec_base
   	              << "\n Met_abstraite::Construction_Umat(...";
   	         Sortie(1);     
   	        };
         if (nbvec_base != ex.giB_0->NbVecteur())
           { cout << "\n erreur le nombre de vecteur " << nbvec_base
                  << " est different de celui de la base transmise " << ex.giB_0->NbVecteur()
                   << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
            };
       #endif
  
  
       switch (ex.giB_0->NbVecteur())
        { case 3: *gijHH_0 = IdHH3;*gijBB_0 = IdBB3; break;
          case 2: *gijHH_0 = IdHH2;*gijBB_0 = IdBB2; break;
          case 1: *gijHH_0 = IdHH1;*gijBB_0 = IdBB1;break;
          default:
           { cout << "\n erreur pas de vecteur de base defini"
                  << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
           };
           break;
        };

       // on ne les touches pas
       // on doit faire un changement de base pour les autres grandeurs
       // cas des vecteurs de base
       ex.giB_t->ChangeBase_theta_vers_Xi(*giB_t,*(ex.giH_0));
       ex.giB_tdt->ChangeBase_theta_vers_Xi(*giB_tdt,*(ex.giH_0));
       ex.giH_t->ChangeBase_theta_vers_Xi(*giH_t,*(ex.giB_0));
       ex.giH_tdt->ChangeBase_theta_vers_Xi(*giH_tdt,*(ex.giB_0));
  
       
       // puis on complète en fonction du nombre de vecteur dans ex
       // si ex en 2D -> on complète avec un vecteur normal unitaire
       // si ex en 1D -> on complète avec deux vecteurs normaux unitaires
  
       switch (ex.giB_0->NbVecteur())
        { case 1: giB_t->CoordoB(2) = giB_tdt->CoordoB(2) = giB_t->CoordoB(3) = giB_tdt->CoordoB(3)= CoordonneeB(0,0,1);
                  giH_t->CoordoH(2) = giH_tdt->CoordoH(2) = giH_t->CoordoH(3) = giH_tdt->CoordoH(3)= CoordonneeH(0,0,1);
                  break;
          case 2: giB_t->CoordoB(3) = giB_tdt->CoordoB(3)= CoordonneeB(0,0,1);
                  giH_t->CoordoH(3) = giH_tdt->CoordoH(3)= CoordonneeH(0,0,1);
                  break;
          case 3: *gijHH_0 = IdHH3;*gijBB_0 = IdBB3;break;
          default:
           { cout << "\n erreur pas de vecteur de base defini"
                  << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
           };
           break;
        };
       // cas des métriques
       Calcul_gijBB_t ();  //      "
       Calcul_gijHH_t ();  // composantes controvariantes à t
       Calcul_gijBB_tdt ();  //      "
	      Calcul_gijHH_tdt ();  // composantes controvariantes à t
       // les jacobiens
       Jacobien_t();   // jacobien à t
       Jacobien_tdt();  // et à tdt

       return umat_cont;		
	};

// construction d'une métrique umat
//  - construction d'une métrique qui dépend du paramétrage matériel = X_(0)^a
//  - en fonction d'une métrique normale fonction de l'interpolation sur
//    les éléments de référence c'est-à-dire theta^i
const Met_abstraite::Umat_cont& Met_abstraite::Construction_Umat(const Met_abstraite::Umat_cont& ex)
 {  // construction de la métrique umat associée qui correspond à l'opérateur gradient,
       // c'est-à-dire la métrique correspondant aux coordonnées initiales considérées comme
       // paramétrage matériel
       // a priori on est en dim=3
       // *** modif février 2018: on considère le cas et nb_vecteur = 3
       #ifdef MISE_AU_POINT
         if ((dim_base!= 3))// || (nbvec_base != 3))
           { cout << "\n erreur la dimension est different de trois"
                  << " dim_base = " << dim_base //<< " nbvec_base= " << nbvec_base
                  << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
            };
         if (nbvec_base != ex.giB_0->NbVecteur())
           { cout << "\n erreur le nombre de vecteur " << nbvec_base
                  << " est different de celui de la base transmise " << ex.giB_0->NbVecteur()
                   << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
            };
       #endif
  
  
       switch (ex.giB_0->NbVecteur())
        { case 3: *gijHH_0 = IdHH3;*gijBB_0 = IdBB3; break;
          case 2: *gijHH_0 = IdHH2;*gijBB_0 = IdBB2; break;
          case 1: *gijHH_0 = IdHH1;*gijBB_0 = IdBB1;break;
          default:
           { cout << "\n erreur pas de vecteur de base defini"
                  << "\n Met_abstraite::Construction_Umat(...";
             Sortie(1);
           };
           break;
        };

       // on ne les touches pas
       // on doit faire un changement de base pour les autres grandeurs
       // cas des vecteurs de base
       ex.giB_t->ChangeBase_theta_vers_Xi(*giB_t,*(ex.giH_0));
       ex.giB_tdt->ChangeBase_theta_vers_Xi(*giB_tdt,*(ex.giH_0));
       ex.giH_t->ChangeBase_theta_vers_Xi(*giH_t,*(ex.giB_0));
       ex.giH_tdt->ChangeBase_theta_vers_Xi(*giH_tdt,*(ex.giB_0));
  
  
//       // puis on complète en fonction du nombre de vecteur dans ex
//       // si ex en 2D -> on complète avec un vecteur normal unitaire
//       // si ex en 1D -> on complète avec deux vecteurs normaux unitaires
//
//       switch (ex.giB_0->NbVecteur())
//        { case 1: giB_t->CoordoB(2) = giB_tdt->CoordoB(2) = giB_t->CoordoB(3) = giB_tdt->CoordoB(3)= CoordonneeB(0,0,1);
//                  giH_t->CoordoH(2) = giH_tdt->CoordoH(2) = giH_t->CoordoH(3) = giH_tdt->CoordoH(3)= CoordonneeH(0,0,1);
//                  break;
//          case 2: giB_t->CoordoB(3) = giB_tdt->CoordoB(3)= CoordonneeB(0,0,1);
//                  giH_t->CoordoH(3) = giH_tdt->CoordoH(3)= CoordonneeH(0,0,1);
//                  break;
//          case 3: *gijHH_0 = IdHH3;*gijBB_0 = IdBB3;break;
//          default:
//           { cout << "\n erreur pas de vecteur de base defini"
//                  << "\n Met_abstraite::Construction_Umat(...";
//             Sortie(1);
//           };
//           break;
//        };
       // cas des métriques
   //    (ex.gijBB_tdt)->BaseAbsolue(*gijBB_tdt,*(ex.giH_0));
   //    (ex.gijHH_tdt)->BaseAbsolue(*gijHH_tdt,*(ex.giB_0));
   //    ex.gijBB_t->BaseAbsolue(*gijBB_t,*(ex.giH_0));
   //    ex.gijHH_t->BaseAbsolue(*gijHH_t,*(ex.giB_0));
  
       Calcul_gijBB_t ();  //      "
       Calcul_gijHH_t ();  // composantes controvariantes à t
       Calcul_gijBB_tdt ();  //      "
       Calcul_gijHH_tdt ();  // composantes controvariantes à t
       // les jacobiens
       Jacobien_t();   // jacobien à t
       Jacobien_tdt();  // et à tdt

       return umat_cont;
 };

// ========== utilise par le contact =========================

// calcul d'un point M0 en fonction de phi et des coordonnees a 0
const Coordonnee & Met_abstraite::PointM_0 // ( stockage a t=0)
		  ( const Tableau<Noeud *>& tab_noeud, const Vecteur& Phi)
  { Calcul_M0(tab_noeud,Phi,nomb_noeud);
    return *M0;
   };

// calcul d'un point M en fonction de phi et des coordonnees a t
const Coordonnee & Met_abstraite::PointM_t // ( stockage a t)
		  ( const Tableau<Noeud *>& tab_noeud, const Vecteur& Phi)
  { Calcul_Mt(tab_noeud,Phi,nomb_noeud);
    return *Mt;
   };
   
// calcul de la variation d'un point M par rapport aux ddl , 
// en fonction de phi et des coordonnees a t
const Tableau<Coordonnee> & Met_abstraite::D_PointM_t // ( stockage a t)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi)
  { Calcul_d_Mt(tab_noeud,Phi,nomb_noeud);
    return *d_Mt;
   };
		  

// calcul d'un point M en fonction de phi et des coordonnees a tdt
const Coordonnee & Met_abstraite::PointM_tdt // ( stockage a tdt)
		  ( const Tableau<Noeud *>& tab_noeud, const Vecteur& Phi)
  { Calcul_Mtdt(tab_noeud,Phi,nomb_noeud);
    return *Mtdt;
   };
   
// calcul de la variation d'un point M par rapport aux ddl , 
// en fonction de phi et des coordonnees a tdt
const Tableau<Coordonnee> & Met_abstraite::D_PointM_tdt // ( stockage a tdt)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi)
  { Calcul_d_Mtdt(tab_noeud,Phi,nomb_noeud);
    return *d_Mtdt;
   };

// calcul de la vitesse du point M en fonction de phi et des coordonnees a 0
// dans le cas où les ddl de vitesse existent, ils sont directement interpolés
// dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
const Coordonnee & Met_abstraite::VitesseM_0 // ( stockage a t=0)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi)
  { if (tab_noeud(1)->Existe_ici(V1))
      { Calcul_V0(tab_noeud,Phi,nomb_noeud); }
    else 
      { Calcul_V_moy0(tab_noeud,Phi,nomb_noeud); };
    return *V0;  
   };
// idem mais au noeud passé en paramètre  
const Coordonnee & Met_abstraite::VitesseM_0(const Noeud* noeud)
  { if (noeud->Existe_ici(V1)) { Calcul_V0(noeud); }
    else                       { Calcul_V_moy0(noeud); };
    return *V0;  
   };
		  
// calcul de la vitesse du point M en fonction de phi et des coordonnees a t
// dans le cas où les ddl de vitesse existent, ils sont directement interpolés
// dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
const Coordonnee & Met_abstraite::VitesseM_t // ( stockage a t=t)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi)
  { if (tab_noeud(1)->Existe_ici(V1))
      { Calcul_Vt(tab_noeud,Phi,nomb_noeud); }
    else 
      { Calcul_V_moyt(tab_noeud,Phi,nomb_noeud); };
    return *Vt;  
   };
// idem mais au noeud passé en paramètre  
const Coordonnee & Met_abstraite::VitesseM_t(const Noeud* noeud)
  { if (noeud->Existe_ici(V1)) { Calcul_Vt(noeud); }
    else                       { Calcul_V_moyt(noeud); };
    return *Vt;  
   };

// calcul de la variation de la vitesse du point M par rapport aux ddl , 
// en fonction de phi et des coordonnees a t
// dans le cas où les ddl de vitesse existent, ils sont directement interpolés
// dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
// ddl_vitesse : indique si oui ou non il s'agit de variation par rapport 
//               aux ddl de vitesse ou au ddl de position 
const Tableau<Coordonnee> & Met_abstraite::D_VitesseM_t // ( stockage a t)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi,bool ddl_vitesse)
  { if (tab_noeud(1)->Existe_ici(V1))
      { Calcul_d_Vt(tab_noeud,Phi,nomb_noeud); ddl_vitesse = true;}
    else 
      { Calcul_d_V_moyt(tab_noeud,Phi,nomb_noeud); ddl_vitesse = false;};
    return *d_Vt;  
   };
// idem mais au noeud passé en paramètre  
const Tableau<Coordonnee> & Met_abstraite::D_VitesseM_t(const Noeud* noeud,bool ddl_vitesse)
  { if (noeud->Existe_ici(V1)) { Calcul_d_Vt(noeud); ddl_vitesse = true;}
    else                       { Calcul_d_V_moyt(noeud); ddl_vitesse = false; };
    return *d_Vt;  
   };
		  
// calcul de la vitesse du point M en fonction de phi et des coordonnees a tdt
// dans le cas où les ddl de vitesse existent, ils sont directement interpolés
// dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
const Coordonnee & Met_abstraite::VitesseM_tdt // ( stockage a tdt)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi)
  { if (tab_noeud(1)->Existe_ici(V1))
      { Calcul_Vtdt(tab_noeud,Phi,nomb_noeud); }
    else 
      { Calcul_V_moytdt(tab_noeud,Phi,nomb_noeud);};
    return *Vtdt;  
   };
// idem mais au noeud passé en paramètre  
const Coordonnee & Met_abstraite::VitesseM_tdt(const Noeud* noeud)
  { if (noeud->Existe_ici(V1)) { Calcul_Vtdt(noeud); }
    else                       { Calcul_V_moytdt(noeud); };
    return *Vtdt;  
   };

// calcul de la variation de la vitesse du point M par rapport aux ddl , 
// en fonction de phi et des coordonnees a tdt
// dans le cas où les ddl de vitesse existent, ils sont directement interpolés
// dans le cas où ils n'existent pas, on utilise les vitesses moyennes : delta M / delta t 
// ddl_vitesse : indique si oui ou non il s'agit de variation par rapport 
//               aux ddl de vitesse ou au ddl de position 
const Tableau<Coordonnee> & Met_abstraite::D_VitesseM_tdt // ( stockage a tdt)
		  (const Tableau<Noeud *>& tab_noeud,const Vecteur& Phi,bool ddl_vitesse)
  { if (tab_noeud(1)->Existe_ici(V1))
      { Calcul_d_Vtdt(tab_noeud,Phi,nomb_noeud); ddl_vitesse = true;}
    else 
      { Calcul_d_V_moytdt(tab_noeud,Phi,nomb_noeud); ddl_vitesse = false; };
    return *d_Vtdt;  
   };
// idem mais au noeud passé en paramètre  
const Tableau<Coordonnee> & Met_abstraite::D_VitesseM_tdt(const Noeud* noeud,bool ddl_vitesse)
  { if (noeud->Existe_ici(V1)) { Calcul_d_Vtdt(noeud); ddl_vitesse = true;}
    else                       { Calcul_d_V_moytdt(noeud); ddl_vitesse = false; };
    return *d_Vtdt;  
   };

// calcul de l'accélération du point M en fonction de phi et des coordonnees a 0
      // dans le cas où les ddl d'accélération existent, ils sont directement interpolés
      // sinon erreur
const Coordonnee & Met_abstraite::AccelerationM_0 // ( stockage a t=0)
  (const Tableau<Noeud *>& tab_noeud,const Vecteur& phi)
  { if (tab_noeud(1)->Existe_ici(GAMMA1))
      { Calcul_gamma0(tab_noeud,phi,nomb_noeud); }
    else
      { cout << "\n erreur l'acceleration n'existe pas aux noeuds"
             << "\n Met_abstraite::AccelerationM_0(..." ;
        Sortie(1);
      };
    return *gamma0;
   };

// idem mais au noeud passé en paramètre
const Coordonnee & Met_abstraite::AccelerationM_0 (const Noeud* noeud)
  { if (noeud->Existe_ici(GAMMA1)) { Calcul_gamma0(noeud); }
    else
    { cout << "\n erreur l'acceleration n'existe pas au noeud"
           << "\n Met_abstraite::AccelerationM_0(..." ;
      Sortie(1);
    };
    return *gamma0;
   };

// idem à t
const Coordonnee & Met_abstraite::AccelerationM_t // ( stockage a t=t)
  (const Tableau<Noeud *>& tab_noeud,const Vecteur& phi)
{ if (tab_noeud(1)->Existe_ici(GAMMA1))
    { Calcul_gammat(tab_noeud,phi,nomb_noeud); }
  else
    { cout << "\n erreur l'acceleration n'existe pas aux noeuds"
           << "\n Met_abstraite::AccelerationM_t(..." ;
      Sortie(1);
    };
  return *gammat;
 };
// idem mais au noeud passé en paramètre
const Coordonnee & Met_abstraite::AccelerationM_t (const Noeud* noeud)
{ if (noeud->Existe_ici(GAMMA1)) { Calcul_gammat(noeud); }
  else
  { cout << "\n erreur l'acceleration n'existe pas au noeud"
         << "\n Met_abstraite::AccelerationM_t(..." ;
    Sortie(1);
  };
  return *gammat;
 };

// idem à tdt
const Coordonnee & Met_abstraite::AccelerationM_tdt // ( stockage a tdt)
  (const Tableau<Noeud *>& tab_noeud,const Vecteur& phi)
{ if (tab_noeud(1)->Existe_ici(GAMMA1))
    { Calcul_gammatdt(tab_noeud,phi,nomb_noeud); }
  else
    { cout << "\n erreur l'acceleration n'existe pas aux noeuds"
           << "\n Met_abstraite::AccelerationM_tdt(..." ;
      Sortie(1);
    };
  return *gammatdt;
 };
// idem mais au noeud passé en paramètre
const Coordonnee & Met_abstraite::AccelerationM_tdt (const Noeud* noeud)
{ if (noeud->Existe_ici(GAMMA1)) { Calcul_gammatdt(noeud); }
  else
  { cout << "\n erreur l'acceleration n'existe pas au noeud"
         << "\n Met_abstraite::AccelerationM_tdt(..." ;
    Sortie(1);
  };
  return *gammatdt;
 };

// calcul de la base naturel ( stockage a t=0) au point correspondant  au dphi
const BaseB& Met_abstraite::BaseNat_0   // en fonction des coordonnees a t=0
		  ( const Tableau<Noeud *>& tab_noeud, const Mat_pleine& dphi,const Vecteur& phi)
  { Calcul_giB_0 (tab_noeud,dphi,nomb_noeud,phi);
    return *giB_0;
   };
		  
// calcul de la base naturel ( stockage a t) au point correspondant  au dphi
const BaseB& Met_abstraite::BaseNat_t   // en fonction des coordonnees a t
		  ( const Tableau<Noeud *>& tab_noeud, const Mat_pleine& dphi,const Vecteur& phi)
  { Calcul_giB_t (tab_noeud,dphi,nomb_noeud,phi);
    return *giB_t;
   };
		  
// calcul de la base naturel ( stockage a t=tdt) au point correspondant  au dphi
const BaseB& Met_abstraite::BaseNat_tdt   // en fonction des coordonnees a tdt
		  ( const Tableau<Noeud *>& tab_noeud, const Mat_pleine& dphi,const Vecteur& phi)
  { Calcul_giB_tdt (tab_noeud,dphi,nomb_noeud,phi);
    return *giB_tdt;
   };
			  
// calcul de la variation de la base naturel, au point correspondant  au dphi en fonction des coord a tdt
// nécessite que la base naturelle ait été calculée auparavant
const Tableau <BaseB>& Met_abstraite::d_BaseNat_tdt // ( stockage a tdt)
  (const Tableau<Noeud *>& tab_noeud,const  Mat_pleine& dphi,const Vecteur& phi)
  { D_giB_tdt(dphi,tab_noeud.Taille(),phi);   //
    return *d_giB_tdt;
   };
		  
// calcul de la base naturelle et duale ( stockage a t=0) en fonction des coord a 0 
void Met_abstraite::BaseND_0( const Tableau<Noeud *>& tab_noeud,const Mat_pleine& dphi,
                              const Vecteur& phi,BaseB& bB,BaseH& bH)
  { Calcul_giB_0 (tab_noeud,dphi,nomb_noeud,phi);
    Calcul_gijBB_0 ();  //      "
	   Calcul_gijHH_0 ();        // composantes controvariantes
    Calcul_giH_0 ();
    bB = *giB_0;
    bH =  *giH_0;
   };
// calcul de la base naturelle et duale ( stockage a t) en fonction des coord a t 
void Met_abstraite::BaseND_t( const Tableau<Noeud *>& tab_noeud, const Mat_pleine& dphi,
                              const Vecteur& phi,BaseB& bB,BaseH& bH)
  { Calcul_giB_t (tab_noeud,dphi,nomb_noeud,phi);
    Calcul_gijBB_t ();  //      "
	   Calcul_gijHH_t ();        // composantes controvariantes
    Calcul_giH_t ();
    bB = *giB_t;
    bH =  *giH_t;
   };
// calcul de la base naturelle et duale ( stockage a tdt) en fonction des coord a tdt 
void Met_abstraite::BaseND_tdt( const Tableau<Noeud *>& tab_noeud, const Mat_pleine& dphi,
                                const Vecteur& phi,BaseB& bB,BaseH& bH)
  { Calcul_giB_tdt (tab_noeud,dphi,nomb_noeud,phi);
    Calcul_gijBB_tdt ();  //      "
    Calcul_gijHH_tdt ();        // composantes controvariantes
    Calcul_giH_tdt ();
    bB = *giB_tdt;
    bH =  *giH_tdt;
   };

// ====== informations diverses (mais cohérentes, c-a-d, peuvent être appelées directement sans init) ====
double Met_abstraite::JacobienInitial(const  Tableau<Noeud *>& tab_noeud,const Mat_pleine& tabDphi
                                       ,int nombre_noeud,const Vecteur& phi)
	{ Calcul_giB_0(tab_noeud,tabDphi,nombre_noeud,phi); // calcul de la base a t=0
	  Jacobien_0(); // calcul du jacobien
   return jacobien_0; // retour
	};