// 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 "GeomHexalin.h"
#include <math.h>
#include "GeomSeg.h"
#include "GeomQuadrangle.h"
#include "MathUtil.h"
#include "Coordonnee1.h"

// constructeur
//  la dimension est 3, on a 8 pt d'integration par défaut, 8 noeuds et 6 faces, 12 aretes

GeomHexalin::GeomHexalin(int nbi )  :
    GeomHexaCom(nbi,8,LINEAIRE),phi_M(),dphi_M()
   {  // coordonnees dans l'élément de référence des noeuds 
      ptelem(1) = Coordonnee(-1.,-1.,-1.); ptelem(2) = Coordonnee(1.,-1.,-1.); 
      ptelem(3) = Coordonnee(1.,1.,-1.);   ptelem(4) = Coordonnee(-1.,1.,-1.);
      ptelem(5) = Coordonnee(-1.,-1.,1.);  ptelem(6) = Coordonnee(1.,-1.,1.);
      ptelem(7) = Coordonnee(1.,1.,1.);    ptelem(8) = Coordonnee(-1.,1.,1.);
      // définition de la numérotation locale de l'élément de direction inverse
      INVCONNEC(1) = 1;INVCONNEC(2) = 4; INVCONNEC(3) = 3;INVCONNEC(4) = 2;
      INVCONNEC(5) = 5;INVCONNEC(6) = 8; INVCONNEC(7) = 7;INVCONNEC(8) = 6;
      // le tableau des tranches
      IND.Change_taille(1); IND(1)=8;
      //--------------------------------
      //def des arretes
      //--------------------------------
      int nbil =1;  // nb de pt d'integ par ligne
      int nbnel =2;   // nb de noeud du segment
      seg(1) = new GeomSeg(nbil,nbnel);
      for (int il=2;il<= NBSE; il++)  // ici NBSE = 12
           seg(il) = seg(1);
      // def des tableaux de connection des noeuds  des aretes
      for (int i =1;i<=NBSE;i++) NONS(i).Change_taille(2);
      // la description est fait selon le fichier EIMail
      NONS(1)(1) = 1;NONS(1)(2) = 2;NONS(2)(1) = 2;NONS(2)(2) = 3;
      NONS(3)(1) = 3;NONS(3)(2) = 4;NONS(4)(1) = 4;NONS(4)(2) = 1;
      NONS(5)(1) = 1;NONS(5)(2) = 5;NONS(6)(1) = 2;NONS(6)(2) = 6;
      NONS(7)(1) = 3;NONS(7)(2) = 7;NONS(8)(1) = 4;NONS(8)(2) = 8;
      NONS(9)(1) = 5;NONS(9)(2) = 6;NONS(10)(1) = 6;NONS(10)(2) = 7;
      NONS(11)(1) = 7;NONS(11)(2) = 8;NONS(12)(1) = 8;NONS(12)(2) = 5;
      //--------------------------------
      //def des faces
      //--------------------------------
      int nbis =4;  // nb de pt d'integ par facee
      int nbnes =4;   // nb de noeud de la face
      face(1) = new GeomQuadrangle(nbis,nbnes);
      for (int is=2;is<= NBFE; is++)  // ici NBFE = 6
           face(is) = face(1);
      // def des tableaux de connection des noeuds  des faces
      for (int i =1;i<=NBFE;i++) NONF(i).Change_taille(4); 
      // connection entre les noeuds des faces et les noeuds des elements
      NONF(1)(1)= 1; NONF(1)(2)= 4; NONF(1)(3)= 3; NONF(1)(4)= 2;
      NONF(2)(1)= 1; NONF(2)(2)= 5; NONF(2)(3)= 8; NONF(2)(4)= 4;
      NONF(3)(1)= 1; NONF(3)(2)= 2; NONF(3)(3)= 6; NONF(3)(4)= 5;
      NONF(4)(1)= 5; NONF(4)(2)= 6; NONF(4)(3)= 7; NONF(4)(4)= 8;
      NONF(5)(1)= 2; NONF(5)(2)= 3; NONF(5)(3)= 7; NONF(5)(4)= 6;
      NONF(6)(1)= 3; NONF(6)(2)= 4; NONF(6)(3)= 8; NONF(6)(4)= 7;
      // triangulation des différentes  faces
      // on se sert d'une part de l'élément de référence de chaque face
      // puis de la connection les faces par rapport à celle de l'élément
      // ici c'est le même élément pour toutes les faces
       // 1) récup du tableau de l'élément de référence de la face
      const Tableau<Tableau<Tableau<int> > > & tabi = face(1)->Trian_lin();
      int nbtria = tabi(1).Taille(); // nombre de triangle par face 
      // on est obligé de boucler sur tous les indices et de faire
      // de l'adressage indirecte
      for (int isf=1;isf<= NBFE; isf++)  // boucle sur les faces
       { NONFt(isf).Change_taille(nbtria);
         for (int if1=1;if1<= nbtria; if1++)  // boucle sur les triangles de la face
          { NONFt(isf)(if1).Change_taille(3);
            for (int in1=1;in1<= 3; in1++)  // boucle sur les noeuds du triangle
              NONFt(isf)(if1)(in1) = NONF(isf)(tabi(1)(if1)(in1));
            }
         }   
      // définition des fonctions d'interpolation et de leurs dérivées
      if (nbi == 8) // cas classique
        // on utilise des valeurs prédéfinies via deux methodes internes
        // fonctions d'interpolation globales
        { Phiphi();
         // derivees des fonctions d'interpolations
         DphiDphi();
         }
      else if ((nbi==1) || (nbi==27) || (nbi == 64))
        { // on utilise les méthodes internes pour calculer les fonctions
          // d'interpolation aux points d'intégrations
          for (int ptint=1;ptint<= Nbi(); ptint++)
            tabPhi(ptint) = Phi_point( ptInteg(ptint));
          for (int ptint=1;ptint<= Nbi(); ptint++)
            tabDPhi(ptint) = Dphi_point( ptInteg(ptint));
         };

    // ---- constitution du tableau Extrapol -----
    Calcul_extrapol(nbi);
};


// destructeur
GeomHexalin::~GeomHexalin() 
  { delete seg(1);
    delete face(1);
   };
// constructeur de copie
GeomHexalin::GeomHexalin(const GeomHexalin& a) :
  GeomHexaCom(a),phi_M(a.phi_M),dphi_M(a.dphi_M)
   { // la copie des parties pointées est à la charge de la classe spécifique
     // definition des  faces
     face(1) = new GeomQuadrangle(*((GeomQuadrangle*)(a.face(1))));
     // def des segments
     seg(1) = new GeomSeg(*((GeomSeg*)(a.seg(1)))) ;
     for (int il=2;il<= NBSE; il++)
           seg(il) = seg(1);
   };    
    
// création d'élément identiques : cette fonction est analogue à la fonction new
// elle y fait d'ailleurs appel. l'implantation est spécifique dans chaque classe
// dérivée
// pt est le pointeur qui est affecté par la fonction 
ElemGeomC0 * GeomHexalin::newElemGeomC0(ElemGeomC0 * pt) 
  { pt = new GeomHexalin(*this);
    return pt; 
   };

//--------- cas de coordonnees locales quelconques ---------------- 

    // retourne les fonctions d'interpolation au point M (en coordonnees locales)
const Vecteur& GeomHexalin::Phi_point(const Coordonnee& M)
  {
    #ifdef MISE_AU_POINT	 	   
     // verification de la dimension des coordonnees locales
     if (M.Dimension() != 3)
       { cout << "\n erreur la dimension des coordonnees locales :" << M.Dimension()
              <<"n\'est pas egale a 3 "
             << "\nGeomHexalin::Phi(Coordonnee& M)";
        Sortie(1);
      }
    #endif
    //Vecteur phi(NBNE); // tableau des fonctions d'interpolation
    // dimentionnement éventuelle du tableau des fonctions d'interpolation
    phi_M.Change_taille(NBNE); // si la taille est identique -> aucune action
    //------------------------------------------------------
    //        cas d'un Hexaedre trilineaire
    //------------------------------------------------------
    if (NBNE == 8)
      {  int nbnes = 2;  // nombre de noeud par cote
         Coordonnee X(1),Y(1),Z(1); 
         X(1) = M(1); Y(1) = M(2);Z(1) = M(3);  // coordonnees pour le segment
         //  fonctions d'interpolation
         int ne = 1;
         Vecteur tabPhiT(NBNE);
         for (int iz = 1;iz<= nbnes; iz++)
          for (int iy = 1;iy<= nbnes; iy++)
           for (int ix =1;ix<=nbnes;ix++)
            { tabPhiT(ne) = seg(1)->Phi_point(X)(ix) * seg(1)->Phi_point(Y)(iy) * seg(1)->Phi_point(Z)(iz);
              ne++;
             } 
         // numerotation suivant le standard habituel
         Tableau<int> ind(8);
//         ind(1) = 5; ind(2) = 6; ind(3) = 8; ind(4) = 7;
//         ind(5) = 1; ind(6) = 2; ind(7) = 4; ind(8) = 3;
         ind(1) = 1; ind(2) = 2; ind(3) = 4; ind(4) = 3;
         ind(5) = 5; ind(6) = 6; ind(7) = 8; ind(8) = 7;
         for (int ne = 1; ne<= 8; ne++)
                 phi_M(ne) = tabPhiT(ind(ne));
       }  
      else
       {cout << "\n erreur l'hexaedre de nombre de noeud NBNE = " << NBNE 
             << "\n n\'est pas implante !! ";
        cout << "\nGeomHexalin::Phi(Coordonnee& M) " << endl;     
        Sortie(1);
        }
    // retour de phi_M
    return phi_M;
   };
    // retourne les derivees des fonctions d'interpolation au point M (en coordonnees locales)
const Mat_pleine& GeomHexalin::Dphi_point(const Coordonnee& M)
  {  
   #ifdef MISE_AU_POINT	 	   
     // verification de la dimension des coordonnees locales
     if (M.Dimension() != 3)
       { cout << "\n erreur la dimension des coordonnees locales :" << M.Dimension()
              <<"n\'est pas egale a 3 "
             << "\nGeomHexalin::Dphi(Coordonnee& M)";
        Sortie(1);
      }
    #endif
//   Mat_pleine dphi(3,NBNE); // le tableau des derivees
    // le tableau des derivees: redimentionnement si nécessaire
    if ((dphi_M.Nb_ligne() != 3)&&(dphi_M.Nb_colonne() != NBNE))
      dphi_M.Initialise (3,NBNE,0.);
    //------------------------------------------------------
    //        cas d'un Hexaedre trilineaire
    //------------------------------------------------------
    if (NBNE == 8)
      {  int nbnes = 2;  // nombre de noeud par cote
         Coordonnee X(1),Y(1),Z(1); 
         X(1) = M(1); Y(1) = M(2);Z(1) = M(3);  // coordonnees pour le segment
         //  derivee des fonctions d'interpolation
         int ne = 1;
         Mat_pleine tabDPhiT(3,NBNE);
         for (int iz = 1;iz<= nbnes; iz++)
          for (int iy = 1;iy<= nbnes; iy++)
           for (int ix = 1;ix<= nbnes; ix++)
            { //tabDPhiT(1,ne) = seg(1)->Dphi(X)(1,ix) * seg(1)->Phi(Y)(iy) * seg(1)->Phi(Z)(iz);
              //tabDPhiT(2,ne) = seg(1)->Phi(X)(ix) * seg(1)->Dphi(Y)(1,iy) * seg(1)->Phi(Z)(iz);
              //tabDPhiT(3,ne) = seg(1)->Phi(X)(ix) * seg(1)->Phi(Y)(iy) * seg(1)->Dphi(Z)(1,iz);
              
              double phi_X_ix = seg(1)->Phi_point(X)(ix);
              double phi_Y_iy = seg(1)->Phi_point(Y)(iy);
              double phi_Z_iz = seg(1)->Phi_point(Z)(iz);
              tabDPhiT(1,ne) = seg(1)->Dphi_point(X)(1,ix) * phi_Y_iy              * phi_Z_iz;
              tabDPhiT(2,ne) = phi_X_ix              * seg(1)->Dphi_point(Y)(1,iy) * phi_Z_iz;
              tabDPhiT(3,ne) = phi_X_ix              * phi_Y_iy              * seg(1)->Dphi_point(Z)(1,iz);
              
              ne++;
             } 
         // numerotation suivant le standard habituel
         Tableau<int> ind(8);
//         ind(1) = 5; ind(2) = 6; ind(3) = 8; ind(4) = 7;
//         ind(5) = 1; ind(6) = 2; ind(7) = 4; ind(8) = 3;
         ind(1) = 1; ind(2) = 2; ind(3) = 4; ind(4) = 3;
         ind(5) = 5; ind(6) = 6; ind(7) = 8; ind(8) = 7;
         for (int ne = 1; ne<= 8; ne++)
               { dphi_M(1,ne) = tabDPhiT(1,ind(ne));
                 dphi_M(2,ne) = tabDPhiT(2,ind(ne));
                 dphi_M(3,ne) = tabDPhiT(3,ind(ne));
                }
        }         
      else
       { cout << "\n erreur le nombre de noeud demande :" << NBNE <<"n\'est pas implante "
             << "\nGeomHexalin::Dphi(Coordonnee& M)";
        Sortie(1);
      }
    // retour des derivees  
    return dphi_M;
   };
  
  
// constitution du tableau Extrapol
void GeomHexalin::Calcul_extrapol(int nbi)
{ // cas de l'extrapolation de grandeur des points d'intégrations aux noeuds
  // def du tableau de pondération tab(i)(j) qu'il faut appliquer
  // aux noeuds pour avoir la valeur aux noeuds 
  // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indir(i)) )) {tab(i)(j) * val_pt_integ(j) }
  // cas = 1: la valeur au noeud = la valeur au pt d'integ le plus près ou une moyenne des
  //          pt les plus près (si le nb de pt d'integ < nb noeud)
  //--- changement: 26 oct 2020: on fait une extrapolation tri-linéaire via les pti les plus proches

  switch  (nbi)
   { case 1: 
       { // cas avec un point d'intégration, quelque soit le nombre de noeuds, 
         // on reporte la valeur au pt d'integ, telle quelle au noeud
         Tableau<Tableau<int> > & indir = extrapol(1).indir;  // pour simplifier
         Tableau<Tableau<double > > & tab = extrapol(1).tab;    // pour simplifier
         for (int ne=1;ne<=NBNE;ne++)
         	{tab(ne).Change_taille(nbi);
           tab(ne)(1)=1.;
         	 indir(ne).Change_taille(1); indir(ne)(1)=1;
         	};
         break;
       }
   	 case 8:
        {  // cas avec 8 points d'intégration ,
           // on a deux méthodes
           extrapol.Change_taille(2);
           // tab est supposé être initialisé à 0.
           Tableau <Coordonnee>  gi_B,gi_H; // bases naturelle et duale
           
           // --- méthode 1 (par défaut), on utilise une extrapolation via un hexaèdre bi-linéaire
           {Tableau<Tableau<int> > & indir = extrapol(1).indir;  // pour simplifier
            Tableau<Tableau<double > > & tab = extrapol(1).tab;    // pour simplifier
            Tableau <int> indirect(nbi); // tableau de travail: on a 8 pondérations
            tab.Change_taille(NBNE);indir.Change_taille(NBNE);

            // on extrapole bi-linéairement vers les  noeuds en considérant
            // les 8 pti dans l'ordre actuel: il faut utiliser une indirection
            // car la numérotation des pti ne correspond pas à celle des noeuds d'un hexa bi-linéaire
            indirect(1) = 8; indirect(2) = 4; indirect(3) = 2; indirect(4) = 6;
            indirect(5) = 7; indirect(6) = 3; indirect(7) = 1; indirect(8) = 5;
            

            for (int ne=1; ne <= NBNE; ne++)
             { // il nous faut calculer les coordonnées locales.
               // sachant que les pti ici considérés, sont aux sommets d'un hexa linéaire orthogonal
               // on peut traiter séparément chaque composante
               Coordonnee theta(3); // les coordonnées que l'on cherche
               Vecteur phi_x(2); // le conteneur pour les fonctions d'interpolation
               Vecteur phi_y(2); // le conteneur pour les fonctions d'interpolation
               Vecteur phi_z(2); // le conteneur pour les fonctions d'interpolation
               {Tableau <int> indirect_local(2); // tableau de travail
                Coordonnee theta_loc(1); // le conteneur pour les coordonnées locales
                Tableau <Coordonnee>  gi_loc_B,gi_loc_H; // bases naturelle et duale
                Vecteur phi_loc(2); // le conteneur pour les fonctions d'interpolation
                // suivant x
                {indirect_local(1) = indirect(1);indirect_local(2) = indirect(2);
                 Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                 Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de l'origine
                 ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_x,theta_loc);
                 theta(1)=theta_loc(1); // on enregistre
                }
                // suivant y
                {indirect_local(1) = indirect(1);indirect_local(2) = indirect(4);
                 Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                 Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); //
                 ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_y,theta_loc);
                 theta(2)=theta_loc(1); // on enregistre
                }
                // suivant z
                {indirect_local(1) = indirect(1);indirect_local(2) = indirect(8);
                 Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                 Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); //
                 ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_z,theta_loc);
                 theta(3)=theta_loc(1); // on enregistre
                }
               };

               // maintenant on calcule les fct d'interpolation au noeud ne
               // via ses coordonnées locales theta
               const Vecteur& phiphi = this->Phi_point(theta);
               // et on enregistre
               indir(ne).Change_taille(nbi);
               tab(ne).Change_taille(nbi);
               // on boucle sur les pti de l'hexa linéaire d'interpolation
               for (int i=1;i<9;i++)
                {tab(ne)(indirect(i))=phiphi(i);
                 indir(ne)(i)=indirect(i);
                };
             }
           }; // fin méthode 1
     
           // --- deuxième méthode en utilisant un tétraèdre linéaire
           // le pb est que le choix du tétraèdre est vraiment arbitraire

           {// on extrapole linéairement vers les  noeuds en considérant à chaque fois les 4 pt d'intégration les plus près qui ne doivent pas être coplanaires
            Tableau<Tableau<int> > & indir = extrapol(2).indir;  // pour simplifier
            Tableau<Tableau<double > > & tab = extrapol(2).tab;    // pour simplifier
            tab.Change_taille(NBNE);indir.Change_taille(NBNE);
            //
            // -- le premier noeud
            {int ne = 1; indir(ne).Change_taille(4);
             indir(ne)(1)=8;indir(ne)(2)=4;indir(ne)(3)=6;indir(ne)(4)=7;
            }
            // -- le deuxième noeud
            {
             int ne = 2; indir(ne).Change_taille(4);
             indir(ne)(1)=4;indir(ne)(2)=2;indir(ne)(3)=6;indir(ne)(4)=3;
            }
            // -- le troisième noeud
            {int ne = 3; indir(ne).Change_taille(4);
             indir(ne)(1)=2;indir(ne)(2)=6;indir(ne)(3)=4;indir(ne)(4)=1;
            }
            // -- le quatrième noeud
            {int ne = 4; indir(ne).Change_taille(4);
             indir(ne)(1)=6;indir(ne)(2)=8;indir(ne)(3)=2;indir(ne)(4)=5;
            }
            // -- le cinquième noeud
            {int ne = 5; indir(ne).Change_taille(4);
             indir(ne)(1)=7;indir(ne)(2)=5;indir(ne)(3)=3;indir(ne)(4)=8;
            }
            // -- le sixième noeud
            {int ne = 6; indir(ne).Change_taille(4);
             indir(ne)(1)=3;indir(ne)(2)=7;indir(ne)(3)=1;indir(ne)(4)=4;
            }
            // -- le septième noeud
            {int ne = 7; indir(ne).Change_taille(4);
             indir(ne)(1)=1;indir(ne)(2)=3;indir(ne)(3)=5;indir(ne)(4)=2;
            }
            // -- le huitième noeud
            {int ne = 8; indir(ne).Change_taille(4);
             indir(ne)(1)=5;indir(ne)(2)=1;indir(ne)(3)=7;indir(ne)(4)=6;
            }
            
            // 2) ---  on calcule l'interpolation
            Coordonnee theta(3); // les coordonnées que l'on cherche
            Tableau <Coordonnee>  gi_B,gi_H; // bases naturelle et duale
            Vecteur phi_(4); // le conteneur pour les fonctions d'interpolation
            for (int ne = 1;ne<=NBNE; ne++)
             { tab(ne).Change_taille(nbi);// 8 pti
               Tableau <int>& indirect= indir(ne) ; // tableau de travail: on a 4 pondérations
               Bases_naturel_duales(indirect,gi_B,gi_H);
               Coordonnee O(ptInteg(indirect(1))); // def de l'origine
               ElemGeomC0::Coor_phi(O,gi_H,ptelem(ne),phi_,theta);
               tab(ne)(indirect(1)) = phi_(1);tab(ne)(indirect(2)) = phi_(2);
               tab(ne)(indirect(3)) = phi_(3);tab(ne)(indirect(4)) = phi_(4);
             };

            
           }; // fin méthode 2

       
// --- ancienne méthode
//         // cas avec 8 points d'intégration = le nombre de noeud, on exporte directement la valeur du
//   	     // pt d'integ le plus proche
//          int ne = 1; tab(ne)(8) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=8;
//          ne = 2; tab(ne)(4) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=4;
//          ne = 3; tab(ne)(2) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=2;
//          ne = 4; tab(ne)(6) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=6;
//          ne = 5; tab(ne)(7) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=7;
//          ne = 6; tab(ne)(3) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=3;
//          ne = 7; tab(ne)(1) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=1;
//          ne = 8; tab(ne)(5) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=5;
          break;  
   	 	}  // fin du cas avec 8 pt d'intégration
   	 case 27:
   	   { // cas avec 27 points d'intégration
                
         // on a une seules méthode
         Tableau <Coordonnee>  gi_B,gi_H; // bases naturelle et duale
         
         // --- méthode 1 (par défaut), on utilise une extrapolation via un hexaèdre bi-linéaire

         {Tableau<Tableau<int> > & indir = extrapol(1).indir;  // pour simplifier
          Tableau<Tableau<double > > & tab = extrapol(1).tab;    // pour simplifier
          Tableau <int> indirect(8); // tableau de travail: on a 8 pondérations
          tab.Change_taille(NBNE);indir.Change_taille(NBNE);
                
          // on essaie de faire une boucle mais il y a des exceptions ...
          // -- le  noeud 1
          {
           int ne = 1;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 1;indir(ne)(2)= 2;indir(ne)(3)= 5;indir(ne)(4)= 4;
           indir(ne)(5)=10;indir(ne)(6)=11;indir(ne)(7)=14;indir(ne)(8)=13;
          }
          // -- le deuxième noeud
          {
           int ne = 2;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 2;indir(ne)(2)= 3;indir(ne)(3)= 6;indir(ne)(4)= 5;
           indir(ne)(5)=11;indir(ne)(6)=12;indir(ne)(7)=15;indir(ne)(8)=14;
          }
          // -- le troisième noeud
          {int ne = 3;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 5;indir(ne)(2)= 6;indir(ne)(3)= 9;indir(ne)(4)= 8;
           indir(ne)(5)=14;indir(ne)(6)=15;indir(ne)(7)=18;indir(ne)(8)=17;
          }
          // -- le quatrième noeud
          {int ne = 4;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 4;indir(ne)(2)= 5;indir(ne)(3)= 8;indir(ne)(4)= 7;
           indir(ne)(5)=13;indir(ne)(6)=14;indir(ne)(7)=17;indir(ne)(8)=16;
          }
          // -- le cinquième noeud
          {int ne = 5;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 10;indir(ne)(2)= 11;indir(ne)(3)=14;indir(ne)(4)=13;
           indir(ne)(5)=19;indir(ne)(6)=20;indir(ne)(7)=23;indir(ne)(8)=22;
          }
          // -- le sixième noeud
          {int ne = 6;
           indir(ne).Change_taille(8);
           indir(ne)(1)= 11;indir(ne)(2)= 12;indir(ne)(3)= 15;indir(ne)(4)= 14;
           indir(ne)(5)=20;indir(ne)(6)=21;indir(ne)(7)=24;indir(ne)(8)=23;
          }
          // -- le septième noeud
           {int ne = 7;
            indir(ne).Change_taille(8);
            indir(ne)(1)=14;indir(ne)(2)=15;indir(ne)(3)=18;indir(ne)(4)=17;
            indir(ne)(5)=23;indir(ne)(6)=24;indir(ne)(7)=27;indir(ne)(8)=26;
           }
           // -- le huitième noeud
           {int ne = 8;
            indir(ne).Change_taille(8);
            indir(ne)(1)=13;indir(ne)(2)=14;indir(ne)(3)=17;indir(ne)(4)=16;
            indir(ne)(5)=22;indir(ne)(6)=23;indir(ne)(7)=26;indir(ne)(8)=25;
           }

                      
           // 2) ---  on calcule l'interpolation
           Coordonnee theta(3); // les coordonnées que l'on cherche
           for (int ne = 1;ne<28; ne++)
            {  indir(ne).Change_taille(8);
               // il nous faut calculer les coordonnées locales.
               // sachant que les pti ici considérés, sont aux sommets d'un hexa linéaire orthogonal
               // on peut traiter séparément chaque composante
               Coordonnee theta(3); // les coordonnées que l'on cherche
               Vecteur phi_x(2); // le conteneur pour les fonctions d'interpolation
               Vecteur phi_y(2); // le conteneur pour les fonctions d'interpolation
               Vecteur phi_z(2); // le conteneur pour les fonctions d'interpolation
               Tableau <int> indirect_local(2); // tableau de travail
               Coordonnee theta_loc(1); // le conteneur pour les coordonnées locales
               Tableau <Coordonnee>  gi_loc_B,gi_loc_H; // bases naturelle et duale
               Vecteur phi_loc(2); // le conteneur pour les fonctions d'interpolation
               // suivant x
               {indirect_local(1) = indirect(1);indirect_local(2) = indirect(2);
                Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de l'origine
                ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_x,theta_loc);
                theta(1)=theta_loc(1); // on enregistre
               }
               // suivant y
               {indirect_local(1) = indirect(1);indirect_local(2) = indirect(4);
                Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de
                ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_y,theta_loc);
                theta(2)=theta_loc(1); // on enregistre
               }
               // suivant z
               {indirect_local(1) = indirect(1);indirect_local(2) = indirect(8);
                Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
                Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2))));
                ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_z,theta_loc);
                theta(3)=theta_loc(1); // on enregistre
               }
               // maintenant on calcule les fct d'interpolation au noeud ne
               // via ses coordonnées locales theta
               const Vecteur& phiphi = this->Phi_point(theta);
               // et on enregistre
               tab(ne).Change_taille(nbi);
               // on boucle sur les pti de l'hexa linéaire d'interpolation
               for (int i=1;i<9;i++)
                tab(ne)(indir(ne)(i))=phiphi(i);
            };
          }; // fin de la méthode 1


//         // --- ancienne méthode
//         // on exporte directement la valeur du pt d'integ le plus proche
//          int ne = 1; tab(ne)(1) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=1;
//          ne = 2; tab(ne)(3) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=3;
//          ne = 3; tab(ne)(9) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=9;
//          ne = 4; tab(ne)(7) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=7;
//          ne = 5; tab(ne)(19) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=19;
//          ne = 6; tab(ne)(21) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=21;
//          ne = 7; tab(ne)(27) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=27;
//          ne = 8; tab(ne)(25) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=25;
          break;  
   	 	}  // fin du cas avec 27 pt d'intégration
   	 case 64:
   	   { // cas avec 64 points d'intégration
       
         // on considère une seule méthode
         Tableau <Coordonnee>  gi_B,gi_H; // bases naturelle et duale
         
         // --- méthode 1 (par défaut), on utilise une extrapolation via un hexaèdre bi-linéaire

         { Tableau<Tableau<int> > & indir = extrapol(1).indir;  // pour simplifier
           Tableau<Tableau<double > > & tab = extrapol(1).tab;    // pour simplifier
           tab.Change_taille(NBNE);indir.Change_taille(NBNE);

           // 1) ---  on commence par remplir les tableaux d'indirection
           // on utilise une numérotation de base issue des éléments 1D
           // -> c'est le numéro nee : on balaie x puis y puis z
           // et ne est le véritable numéro de noeud
           Tableau<int> jnd;
           jnd.Change_taille(NBNE);
           jnd(1) = 1; jnd(3) = 2; jnd(9) = 3; jnd(7) = 4;jnd(19) = 5;
           jnd(21) = 6; jnd(27) = 7; jnd(25) = 8; jnd(2) = 9;jnd(6) = 10;
           jnd(8) = 11; jnd(4) = 12; jnd(10) = 13; jnd(12) = 14;jnd(18) = 15;
           jnd(16) = 16; jnd(20) = 17; jnd(24) = 18; jnd(26) = 19;jnd(22) = 20;
           jnd(5) = 21; jnd(11) = 22; jnd(15) = 23; jnd(17) = 24;jnd(13) = 25;
           jnd(23) = 26; jnd(14) = 27;

           // -- le  noeud 1
           {
            int ne = 1;
            indir(ne).Change_taille(8);
            indir(ne)(1)= 1;indir(ne)(2)= 2;indir(ne)(3)= 6;indir(ne)(4)= 5;
            indir(ne)(5)=17;indir(ne)(6)=18;indir(ne)(7)=22;indir(ne)(8)=21;
           }
           // -- le deuxième noeud
           {int ne = 2;
            indir(ne).Change_taille(8);
            indir(ne)(1)= 3;indir(ne)(2)= 4;indir(ne)(3)= 8;indir(ne)(4)= 7;
            indir(ne)(5)=19;indir(ne)(6)=20;indir(ne)(7)=24;indir(ne)(8)=23;
           }

           // -- le troisième noeud
           {int ne = 3;
            indir(ne).Change_taille(8);
            indir(ne)(1)=11;indir(ne)(2)=12;indir(ne)(3)=16;indir(ne)(4)=15;
            indir(ne)(5)=27;indir(ne)(6)=28;indir(ne)(7)=32;indir(ne)(8)=31;
           }

           // -- le quatrième noeud
           {int ne = 4;
            indir(ne).Change_taille(8);
            indir(ne)(1)= 9;indir(ne)(2)=10;indir(ne)(3)=14;indir(ne)(4)=13;
            indir(ne)(5)=25;indir(ne)(6)=26;indir(ne)(7)=30;indir(ne)(8)=29;
           }

           // pour les autres noeuds, on décale suivant z: de 32
           // noeuds 5 à 9
           for (int ne = 5; ne < 9; ne++)
              {int nbase= ne-4;
               indir(ne).Change_taille(8);
               for (int i=1;i<5;i++ )
                 {indir(ne)(i)= indir(nbase)(i) + 32;
                  indir(ne)(i+4)= indir(nbase)(i+4) + 32;
                 }
              };
              
           // 2) ---  on calcule l'interpolation
           Coordonnee theta(3); // les coordonnées que l'on cherche
           for (int ne = 1;ne<28; ne++)
            {
              // il nous faut calculer les coordonnées locales.
              // sachant que les pti ici considérés, sont aux sommets d'un hexa linéaire orthogonal
              // on peut traiter séparément chaque composante
              Vecteur phi_x(2); // le conteneur pour les fonctions d'interpolation
              Vecteur phi_y(2); // le conteneur pour les fonctions d'interpolation
              Vecteur phi_z(2); // le conteneur pour les fonctions d'interpolation
              Tableau <int> indirect_local(2); // tableau de travail
              Coordonnee theta_loc(1); // le conteneur pour les coordonnées locales
              Tableau <Coordonnee>  gi_loc_B,gi_loc_H; // bases naturelle et duale
              Vecteur phi_loc(2); // le conteneur pour les fonctions d'interpolation
              // suivant x
              {indirect_local(1) = indir(ne)(1);indirect_local(2) = indir(ne)(2);
               Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
               Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de l'origine
               ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_x,theta_loc);
               theta(1)=theta_loc(1); // on enregistre
              }
              // suivant y
              {indirect_local(1) = indir(ne)(1);indirect_local(2) = indir(ne)(4);
               Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
               Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de
               ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_y,theta_loc);
               theta(2)=theta_loc(1); // on enregistre
              }
              // suivant z
              {indirect_local(1) = indir(ne)(1);indirect_local(2) = indir(ne)(8);
               Bases_naturel_duales(indirect_local,gi_loc_B,gi_loc_H);
               Coordonnee O(0.5*(ptInteg(indirect_local(1))+ptInteg(indirect_local(2)))); // def de
               ElemGeomC0::Coor_phi(O,gi_loc_H,ptelem(ne),phi_z,theta_loc);

               theta(3)=theta_loc(1); // on enregistre
              }
              // maintenant on calcule les fct d'interpolation au noeud ne
              // via ses coordonnées locales theta
              const Vecteur& phiphi = this->Phi_point(theta);
              // et on enregistre
              tab(ne).Change_taille(nbi);
              // on boucle sur les pti de l'hexa linéaire d'interpolation
              for (int i=1;i<9;i++)
               tab(ne)(indir(ne)(i))=phiphi(i);

            };

         }; // fin de la méthode 1

       
//         // --- ancienne méthode
//          // on exporte directement la valeur du pt d'integ le plus proche
//          int ne = 1; tab(ne)(1) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=1;
//          ne = 2; tab(ne)(4) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=4;
//          ne = 3; tab(ne)(16) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=16;
//          ne = 4; tab(ne)(13) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=13;
//          ne = 5; tab(ne)(49) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=49;
//          ne = 6; tab(ne)(52) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=52;
//          ne = 7; tab(ne)(64) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=64;
//          ne = 8; tab(ne)(61) = 1.;indir(ne).Change_taille(1); indir(ne)(1)=61;
          break;  
   	 	}  // fin du cas avec 64 pt d'intégration
          
     default:
       { cout << "\n erreur le nombre de point d'integration demande :" << nbi <<"n\'est pas implante "
              << "\nGeomTriangle::Calcul_extrapol(..";
         Sortie(1);
       };
   };

};