// FICHIER : Met_Sfe1s3.cc
// CLASSE : Met_Sfe1

// 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 <iostream>
using namespace std;  //introduces namespace std
#include <math.h>
#include <stdlib.h>
#include "Sortie.h"


#include "Met_Sfe1.h"


//  =========================================================================================
//  vu la taille des executables le fichier est decompose en quatre
// le premier : Met_Sfe1s1.cp concerne les constructeurs, destructeur et 
//              la gestion des variables
// le second :  Met_Sfe1s2.cp concerne  le calcul des grandeurs publics
// le troisieme : Met_Sfe1s3.cp concerne  le calcul des grandeurs protegees, et des courbures pour SFE1 et SFE2 et QSFE1
// le quatrième : Met_Sfe1s4.cp concerne  le calcul des courbures pour les éléments SFE3 et QSFE3
//  =========================================================================================
		  
		  	        
//==================== METHODES PROTEGEES===============================
   
// calcul des normales a la facette		  
void Met_Sfe1::Calcul_N_0 ()
   { N_0 = (Util::ProdVec_coorB((*aiB_0)(1),(*aiB_0)(2))).Normer();};
void Met_Sfe1::Calcul_N_t ()
   { N_t = (Util::ProdVec_coorB((*aiB_t)(1),(*aiB_t)(2)));
     norme_N_t = N_t.Norme();
     N_t /= norme_N_t;
   };
void Met_Sfe1::Calcul_N_tdt ()
   { N_tdt = (Util::ProdVec_coorB((*aiB_tdt)(1),(*aiB_tdt)(2)));
     norme_N_tdt = N_tdt.Norme();
     N_tdt /= norme_N_tdt;
   };

//== calcul des variations de la normales
// il faut avant le calcul des ap_alpha_t et de épaisseur à t
void Met_Sfe1::Cal_d_N_t()
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
	   CoordonneeB d_NN; // un vecteur de travail
    for (int iddl=1;iddl<= nbddlx;iddl++)
      { // tout d'abord on calcul la variation de la normale non normée
    	   d_NN =   (Util::ProdVec_coorB((*d_aiB_t)(iddl)(1),(*aiB_t)(2)))
    	          + (Util::ProdVec_coorB((*aiB_t)(1),(*d_aiB_t)(iddl)(2)));
       	// maintenant on calcul la variation du vecteur normal unitaire
        (*d_N_t)(iddl) =  Util::VarUnVect_coorB(N_t,d_NN,norme_N_t);
       };
	};

// il faut avant le calcul des ap_alpha_tdt et de épaisseur à tdt
void Met_Sfe1::Cal_d_N_tdt() 
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
	   CoordonneeB d_NN; // un vecteur de travail
    for (int iddl=1;iddl<= nbddlx;iddl++)
      { // tout d'abord on calcul la variation de la normale non normée
    	   d_NN =   (Util::ProdVec_coorB((*d_aiB_tdt)(iddl)(1),(*aiB_tdt)(2)))
    	          + (Util::ProdVec_coorB((*aiB_tdt)(1),(*d_aiB_tdt)(iddl)(2)));
    	   // maintenant on calcul la variation du vecteur normal unitaire
        (*d_N_tdt)(iddl) =  Util::VarUnVect_coorB(N_tdt,d_NN,norme_N_tdt);
       };
	};
	
// ---- calcul des points
	// calcul du point a t0
void Met_Sfe1::Calcul_M0( const Tableau<Noeud *>& , const  Vecteur& phiH, int )
      { // on considère qu'il y a deux points dans l'épaisseur, un a -h/2 et l'autre à h/2
          *M0 = *P0 +   (N_0 * (epais.epaisseur0 * 0.5 * (phiH(2)-phiH(1)))).Coor_const();};
void Met_Sfe1::Calcul_Mt( const Tableau<Noeud *>& , const  Vecteur& phiH, int )
      { // on considère qu'il y a deux points dans l'épaisseur, un a -h/2 et l'autre à h/2
          *Mt = *Pt +   (N_t * (epais.epaisseur_t * 0.5 * (phiH(2)-phiH(1)))).Coor_const();};
void Met_Sfe1::Calcul_Mtdt( const Tableau<Noeud *>& ,  const Vecteur& phiH, int )
      { // on considère qu'il y a deux points dans l'épaisseur, un a -h/2 et l'autre à h/2
          *Mtdt = *Ptdt +   (N_tdt * (epais.epaisseur_tdt * 0.5 * (phiH(2)-phiH(1)))).Coor_const();};

// cas de l'épaisseur interpolée à 0
void Met_Sfe1::Calcul_epaisseur_0(const Tableau<Noeud *>& tab_noeud, const Vecteur& phiS)
 {  double & epaisseur = epais.epaisseur0;
    epaisseur = 0.; // init
	for (int r=1;r<=nbNoeudCentral;r++)
       epaisseur += tab_noeud(r)->Valeur_0(EPAIS) * phiS(r);
	};
	    
// cas de l'épaisseur interpolée à t
void Met_Sfe1::Calcul_epaisseur_t(const Tableau<Noeud *>& tab_noeud, const Vecteur& phiS)
 {  double & epaisseur = epais.epaisseur_t;
    epaisseur = 0.; // init
	for (int r=1;r<=nbNoeudCentral;r++)
       epaisseur += tab_noeud(r)->Valeur_t(EPAIS) * phiS(r);
	};    

// cas de l'épaisseur interpolée à tdt
void Met_Sfe1::Calcul_epaisseur_tdt(const Tableau<Noeud *>& tab_noeud, const Vecteur& phiS)
 {  double & epaisseur = epais.epaisseur_tdt;
    epaisseur = 0.; // init
	for (int r=1;r<=nbNoeudCentral;r++)
       epaisseur += tab_noeud(r)->Valeur_tdt(EPAIS) * phiS(r);
	};    

// calcul de la variation de l'épaisseur par rapport aux ddl         
void Met_Sfe1::D_epaisseur_t(const  Vecteur& phiS)
	{ // l'épaisseur ne dépend que des ddl d'épaisseur
	  for (int r=1;r<=nbNoeudCentral;r++)
	    (*d_epais)(r).epaisseur_t = phiS(r);		
	};

// calcul de la variation de l'épaisseur par rapport aux ddl         
void Met_Sfe1::D_epaisseur_tdt(const  Vecteur& phiS)
	{ // l'épaisseur ne dépend que des ddl d'épaisseur
	  for (int r=1;r<=nbNoeudCentral;r++)
	    (*d_epais)(r).epaisseur_tdt = phiS(r);		
	};

//==  calcul de la variation de N,alpha
void Met_Sfe1::Cal_d_N_alpha_t()
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
	   for (int iddl=1;iddl<= nbddlx;iddl++)
     { // variation de la derivee du vecteur normal
	      (*d_N_alpha_t_1)(iddl).ConstructionAPartirDe_H(
	                    -(dcurb_t(iddl)(1,1) * (*aiH_t)(1) + curb_t(1,1) * (*d_aiH_t)(iddl)(1) 
	                    +dcurb_t(iddl)(1,2) * (*aiH_t)(2) + curb_t(1,2) * (*d_aiH_t)(iddl)(2)));  
	      (*d_N_alpha_t_2)(iddl).ConstructionAPartirDe_H(
	                    -(dcurb_t(iddl)(2,1) * (*aiH_t)(1) + curb_t(2,1) * (*d_aiH_t)(iddl)(1) 
	                    + dcurb_t(iddl)(2,2) * (*aiH_t)(2) + curb_t(2,2) * (*d_aiH_t)(iddl)(2))); 
    };
 };

void Met_Sfe1::Cal_d_N_alpha_tdt()
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
	   for (int iddl=1;iddl<= nbddlx;iddl++)
     { // variation de la derivee du vecteur normal
	      (*d_N_alpha_tdt_1)(iddl).ConstructionAPartirDe_H(
	                    -(dcurb_tdt(iddl)(1,1) * (*aiH_tdt)(1) + curb_tdt(1,1) * (*d_aiH_tdt)(iddl)(1) 
	                    +dcurb_tdt(iddl)(1,2) * (*aiH_tdt)(2) + curb_tdt(1,2) * (*d_aiH_tdt)(iddl)(2)));  
	      (*d_N_alpha_tdt_2)(iddl).ConstructionAPartirDe_H(
	                    -(dcurb_tdt(iddl)(2,1) * (*aiH_tdt)(1) + curb_tdt(2,1) * (*d_aiH_tdt)(iddl)(1) 
	                    + dcurb_tdt(iddl)(2,2) * (*aiH_tdt)(2) + curb_tdt(2,2) * (*d_aiH_tdt)(iddl)(2))); 
    };
 };

// ------ calcul des bases pour la surface médiane -------

// calcul de la base  naturel a t0  pour la surface médiane: partie a_alpha
void Met_Sfe1::Calcul_a_alpha_B_0
 (  const Tableau<Noeud *>& tab_noeud,  const Mat_pleine& dphi, int ,const Vecteur&)
  {
    #ifdef MISE_AU_POINT	 	 
	   if  (aiB_0 == NULL)
      { cout << "\nErreur : la base a t=0 n'est pas dimensionne !\n";
        cout << "void Met_Sfe1::Calcul_aiB_0 \n";
        Sortie(1);
      };
    #endif
	   for (int i=1;i<= 2;i++)
	    {for (int a=1;a<= dim_base;a++)
		     { double & aib0_i_a = aiB_0->CoordoB(i)(a);
		       aib0_i_a = 0.;
		       for (int r=1;r<=nbNoeudCentral;r++)
			        { aib0_i_a += tab_noeud(r)->Coord0()(a) * dphi(i,r);
			        };
		     };
	    };
 };
// calcul de la base  naturel a t    pour la surface médiane: partie a_alpha
void Met_Sfe1::Calcul_a_alpha_B_t
 (  const Tableau<Noeud *>& tab_noeud, const  Mat_pleine& dphi, int ,const Vecteur&)
  {
    #ifdef MISE_AU_POINT	 	 
	   if  (aiB_t == NULL)
			  { cout << "\nErreur : la base a t n'est pas dimensionne !\n";
			    cout << "void Met_Sfe1::Calcul_aiB_t \n";
			    Sortie(1);
			  };
    #endif
	   for (int i=1;i<= 2;i++)
	     {for (int a=1;a<= dim_base;a++)
		      { double & aibt_i_a = aiB_t->CoordoB(i)(a);
		        aibt_i_a = 0.;
          for (int r=1;r<=nbNoeudCentral;r++)
			         { aibt_i_a += tab_noeud(r)->Coord1()(a) * dphi(i,r);
			         };
		      };
	    };
 };

// calcul de la base  naturel a tdt    pour la surface médiane: partie a_alpha
void Met_Sfe1::Calcul_a_alpha_B_tdt
 (  const Tableau<Noeud *>& tab_noeud, const  Mat_pleine& dphi, int ,const Vecteur&)
 {
   #ifdef MISE_AU_POINT
	  if  (aiB_tdt == NULL)
     { cout << "\nErreur : la base a t+dt n'est pas dimensionne !\n";
       cout << "void Met_Sfe1::Calcul_aiB_tdt \n";
       Sortie(1);
     };
   #endif
   for (int i=1;i<= 2;i++)
     {for (int a=1;a<= dim_base;a++)
        { double & aibtdt_i_a = aiB_tdt->CoordoB(i)(a);
          aibtdt_i_a = 0.;
          for (int r=1;r<=nbNoeudCentral;r++)
            { aibtdt_i_a += tab_noeud(r)->Coord2()(a) * dphi(i,r);
            };
		     };
	    };
};
   		 

//==  calcul de la variation des bases pour la surface médiane: partie a_alpha
// ici il ne s'agit uniquement que de la variation de a_alpha et pas a_3
 void Met_Sfe1::D_a_alpha_B_t( const  Mat_pleine& dphi, int ,const  Vecteur & )
  { int indice; 
    // derivees de aBi par rapport a XHbr      
    for (int b = 1; b<= dim_base; b++)
      for (int r = 1; r <= nbNoeudCentral; r++)
         { indice = (r-1)*dim_base + b;
           BaseB & d_aiB_t_indice=(*d_aiB_t)(indice);
           for (int i =1;i<=2;i++)  // alpha = 1 et 2 uniquement
              { d_aiB_t_indice.CoordoB(i).Zero();
                d_aiB_t_indice.CoordoB(i)(b)=dphi(i,r);
               }
          };              
  };
// ici il ne s'agit uniquement que de la variation de a_alpha et pas a_3
 void Met_Sfe1::D_a_alpha_B_tdt(  const Mat_pleine& dphi, int ,const  Vecteur &)
  { int indice;       
    for (int b = 1; b<= dim_base; b++)
      for (int r = 1; r <= nbNoeudCentral; r++)
         { indice = (r-1)*dim_base + b;
           BaseB & d_aiB_tdt_indice=(*d_aiB_tdt)(indice);
           for (int i =1;i<=2;i++)  // alpha = 1 et 2 uniquement
              { d_aiB_tdt_indice.CoordoB(i).Zero();
                d_aiB_tdt_indice.CoordoB(i)(b)=dphi(i,r);
               }
          }              
  };
   
//==  calcul de la variation de a_3_B
void Met_Sfe1::D_a_3_B_t()
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
    // calcul de la variation de a3B par rapport au ddlxi
    for (int iddl=1;iddl<= nbddlx;iddl++)
    	 (*d_aiB_t)(iddl).CoordoB(3) =  (epais.epaisseur_t * 0.5) * (*d_N_t)(iddl);
    // calcul de la variation en fonction des ddl d'épaisseur 
    int nbddl_total = nbddlx + nbNoeudCentral;int ih=1;
    for (int iddl=nbddlx+1;iddl <= nbddl_total;iddl++,ih++)
	 	 (*d_aiB_t)(iddl).CoordoB(3) = ((*d_epais)(ih).epaisseur_t * 0.5 ) * N_t;
 };

void Met_Sfe1::D_a_3_B_tdt()
  { int nbddlx = tab_ddl.NbDdl_famille(X1);
    // calcul de la variation de a3B par rapport au ddlxi
    for (int iddl=1;iddl<= nbddlx;iddl++)
    	 (*d_aiB_tdt)(iddl).CoordoB(3) =  (epais.epaisseur_tdt * 0.5) * (*d_N_tdt)(iddl);
    // calcul de la variation en fonction des ddl d'épaisseur 
    int nbddl_total = nbddlx + nbNoeudCentral;int ih=1;
    for (int iddl=nbddlx+1;iddl <= nbddl_total;iddl++,ih++)
	 	 (*d_aiB_tdt)(iddl).CoordoB(3) = ((*d_epais)(ih).epaisseur_tdt * 0.5 ) * N_tdt;
 };
		  
// --------- calcul de la base  naturel a t0 ------ 
// neccessite le calcul prealable de la courbure et de la base naturelle et duale de la facette
// également l'épaisseur interpolée si on est avec des éléments 3D
void Met_Sfe1::Calcul_giB_0
 (   const  Tableau<Noeud *>& ,  const Mat_pleine& , int , const  Vecteur& phiH)
   { 
    #ifdef MISE_AU_POINT	 	 
	   if  (giB_0 == NULL)
     { cout << "\nErreur : la base a t=0 n'est pas dimensionne !\n";
       cout << "void Met_Sfe1::Calcul_giB_0 \n";
       Sortie(1);
     };
    #endif
    // vecteur de base gi,
    // 	theta^3 = (phiH(2)-phiH(1));
    double z0 = epais.epaisseur0 * 0.5 * (phiH(2)-phiH(1));
    // ici il n'y a pas le terme de variation de h par rapport au theta^alpha
    giB_0->CoordoB(1) = (*aiB_0)(1) + N_alpha_0_1 * z0;
    giB_0->CoordoB(2) = (*aiB_0)(2) + N_alpha_0_2 * z0;
    if (tCalEpais) // cas 3D
          giB_0->CoordoB(3) = (*aiB_0)(3);
  };

// calcul de la base  naturel a t  
// neccessite le calcul prealable de la courbure et de la base naturelle et duale de la facette
void Met_Sfe1::Calcul_giB_t
 (  const  Tableau<Noeud *>& , const  Mat_pleine& , int, const  Vecteur& phiH)
   {	
    #ifdef MISE_AU_POINT	 	 
    if  (giB_t == NULL)
     { cout << "\nErreur : la base a t n'est pas dimensionne !\n";
       cout << "void Met_Sfe1::Calcul_giB_t \n";
       Sortie(1);
     };
    #endif
    // vecteur de base gi
    double z_t = epais.epaisseur_t * 0.5 * (phiH(2)-phiH(1));
    // ici il n'y a pas le terme de variation de h par rapport au theta^alpha
    giB_t->CoordoB(1) = (*aiB_t)(1) + N_alpha_t_1 * z_t;
    giB_t->CoordoB(2) = (*aiB_t)(2) + N_alpha_t_2 * z_t;
    if (tCalEpais) // cas 3D
          giB_t->CoordoB(3) = (*aiB_t)(3);
  };
// calcul de la base  naturel a tdt  
// neccessite le calcul prealable de la courbure et de la base naturelle et duale de la facette
void Met_Sfe1::Calcul_giB_tdt
 (  const Tableau<Noeud *>& , const  Mat_pleine& , int, const  Vecteur& phiH)
   {
    #ifdef MISE_AU_POINT	 	 
    if  (giB_tdt == NULL)
     { cout << "\nErreur : la base a t+dt n'est pas dimensionne !\n";
       cout << "void Met_Sfe1::Calcul_giB_tdt \n";
       Sortie(1);
     };
    #endif
	
    // vecteur de base gi
    double z_tdt = epais.epaisseur_tdt * 0.5 * (phiH(2)-phiH(1));
    // ici il n'y a pas le terme de variation de h par rapport au theta^alpha
    giB_tdt->CoordoB(1) = (*aiB_tdt)(1) + N_alpha_tdt_1 * z_tdt;
    giB_tdt->CoordoB(2) = (*aiB_tdt)(2) + N_alpha_tdt_2 * z_tdt;
    if (tCalEpais) // cas 3D
          giB_tdt->CoordoB(3) = (*aiB_tdt)(3);
  };
   
//------------// variation des vecteurs de base
// il faut au par avant  avoir calculé la variation de l'épaisseur si on est en 3D
 void Met_Sfe1::D_giB_t( const  Mat_pleine& , int ,  const Vecteur & phiH)
  { double z_t = epais.epaisseur_t * 0.5 * (phiH(2)-phiH(1));
    int nbddlx = tab_ddl.NbDdl_famille(X1);
	
    for (int iddl=1;iddl<= nbddlx;iddl++)
     { // vecteur de base gi
       (*d_giB_t)(iddl).CoordoB(1) = (*d_aiB_t)(iddl)(1) + (*d_N_alpha_t_1)(iddl) * z_t;
       (*d_giB_t)(iddl).CoordoB(2) = (*d_aiB_t)(iddl)(2) + (*d_N_alpha_t_2)(iddl) * z_t;
     };
    // cas 3D
    if (tCalEpais) 
      {// variation de giB3 = en fait celle de aiB3
       int nbddl_total = nbddlx + nbNoeudCentral;
       for (int iddl=1;iddl<= nbddl_total;iddl++)
           (*d_giB_t)(iddl).CoordoB(3) = (*d_aiB_t)(iddl)(3);
       // ensuite les vecteurs g1B et g2B dépendent aussi des ddl d'épaisseur
       // on calcul donc cette variation, et on en profite pour calculer également la variation de g3B
       // en fonction des ddl d'épaisseur 
       int ih=1;
       for (int iddl=nbddlx+1;iddl <= nbddl_total;iddl++,ih++)
        {(*d_giB_t)(iddl).CoordoB(1) = ((*d_epais)(ih).epaisseur_t * 0.5 * (phiH(2)-phiH(1))) * N_alpha_t_1;
         (*d_giB_t)(iddl).CoordoB(2) = ((*d_epais)(ih).epaisseur_t * 0.5 * (phiH(2)-phiH(1))) * N_alpha_t_2;
    	   };
      };  
  };

 void Met_Sfe1::D_giB_tdt( const  Mat_pleine& , int , const  Vecteur & phiH)
  { double z_tdt = epais.epaisseur_tdt * 0.5 * (phiH(2)-phiH(1));
    int nbddlx = tab_ddl.NbDdl_famille(X1);
	
    for (int iddl=1;iddl<= nbddlx;iddl++)
     {// vecteur de base gi
      (*d_giB_tdt)(iddl).CoordoB(1) = (*d_aiB_tdt)(iddl)(1) + (*d_N_alpha_tdt_1)(iddl) * z_tdt;
      (*d_giB_tdt)(iddl).CoordoB(2) = (*d_aiB_tdt)(iddl)(2) + (*d_N_alpha_tdt_2)(iddl) * z_tdt;

      #ifdef MISE_AU_POINT
       if (ParaGlob::NiveauImpression() > 5)
        {if  (((*d_giB_tdt)(iddl)(1).Norme() > 10000.) || ((*d_giB_tdt)(iddl)(1).Norme() < -10000.)
           || ((*d_giB_tdt)(iddl)(2).Norme() > 10000.) || ((*d_giB_tdt)(iddl)(2).Norme() < -10000.) )
          {cout << "\n attention erreur , les  d_giB_tdt sont trop grand "
                << "\n Met_Sfe1::D_giB_tdt(..."
                << " (*d_giB_tdt)(iddl)(1).Norme()=" << (*d_giB_tdt)(iddl)(1).Norme()
                << " (*d_giB_tdt)(iddl)(2).Norme()=" << (*d_giB_tdt)(iddl)(2).Norme()
                << " (*d_aiB_tdt)(iddl)(1).Norme()=" << (*d_aiB_tdt)(iddl)(1).Norme()
                << " (*d_aiB_tdt)(iddl)(2).Norme()=" << (*d_aiB_tdt)(iddl)(2).Norme()
                << " (*d_N_alpha_tdt_1)(iddl).Norme()=" << (*d_N_alpha_tdt_1)(iddl).Norme()
                << " (*d_N_alpha_tdt_2)(iddl).Norme()=" << (*d_N_alpha_tdt_2)(iddl).Norme()
                << endl ;
          };
        };
      #endif         
     };
    // cas 3D
    if (tCalEpais) 
      {// variation de giB3 = en fait celle de aiB3
       int nbddl_total = nbddlx + nbNoeudCentral;
       for (int iddl=1;iddl<= nbddl_total;iddl++)
           (*d_giB_tdt)(iddl).CoordoB(3) = (*d_aiB_tdt)(iddl)(3);
       // ensuite les vecteurs g1B et g2B dépendent aussi des ddl d'épaisseur
       // on calcul donc cette variation, et on en profite pour calculer également la variation de g3B
       // en fonction des ddl d'épaisseur
       int ih=1; 
       for (int iddl=nbddlx+1;iddl <= nbddl_total;iddl++,ih++)
        {(*d_giB_tdt)(iddl).CoordoB(1) = ((*d_epais)(ih).epaisseur_tdt * 0.5 * (phiH(2)-phiH(1))) * N_alpha_tdt_1;
         (*d_giB_tdt)(iddl).CoordoB(2) = ((*d_epais)(ih).epaisseur_tdt * 0.5 * (phiH(2)-phiH(1))) * N_alpha_tdt_2;
        };
      };
  };

//-----------// calcul du tenseur de courbure  dans la base naturelle
// on utilise un tenseur non symétrique, bien qu'en théorie la courbure est symétrique
// suivant les différentes méthodes de calcul, le tenseur en sortie est symétrique ou pas
// on peut toujours le symétriser, si l'on veut un tenseur symétrique
// on a : N,al = - b_{al be} . a^{be}
// plusieurs cas sont etudies suivant l'instant considere
  // a l'instant t = 0
Tenseur_ns2BB& Met_Sfe1::courbure_0 ( const Tableau<Noeud *>& tab_noeud
       ,Tableau <EnuTypeCL> const & tabTypeCL,Tableau <Coordonnee3> const & vplan)
  { Tableau<Coordonnee3> tab_coor(6);
    // actuellement les courbures s'obtiennent à l'aide des noeuds sommets du triangle
    // du milieu et des noeuds externes: on est pour l'instant dans un cadre de triangle
    for (int i=1;i< 4;i++) // les 3 noeuds sommet interne
      tab_coor(i) = tab_noeud(i)->Coord0();
    for (int i=1;i< 4;i++) // les noeuds externes
     tab_coor(i+3) = tab_noeud(i+nbNoeudCentral)->Coord0();
//    for (int i=1;i<=6;i++)
//      tab_coor(i) = tab_noeud(i)->Coord0();
    curb_0 =  (this->*PtCourbure)(tab_coor,(*aiB_0),(*aiH_0),tabTypeCL,vplan);
    return curb_0;
  };
// a l'instant t 
Tenseur_ns2BB& Met_Sfe1::courbure_t ( const Tableau<Noeud *>& tab_noeud
       ,Tableau <EnuTypeCL> const & tabTypeCL,Tableau <Coordonnee3> const & vplan)
  { Tableau<Coordonnee3> tab_coor(6);
    // actuellement les courbures s'obtiennent à l'aide des noeuds sommets du triangle
    // du milieu et des noeuds externes: on est pour l'instant dans un cadre de triangle
    for (int i=1;i< 4;i++) // les 3 noeuds sommet interne
      tab_coor(i) = tab_noeud(i)->Coord1();
    for (int i=1;i< 4;i++) // les noeuds externes
     tab_coor(i+3) = tab_noeud(i+nbNoeudCentral)->Coord1();
//    for (int i=1;i<=6;i++)
//      tab_coor(i) = tab_noeud(i)->Coord1();
    curb_t =  (this->*PtCourbure)(tab_coor,(*aiB_t),(*aiH_t),tabTypeCL,vplan);
    return curb_t;
  };
// a l'instant t+dt
Tenseur_ns2BB& Met_Sfe1::courbure_tdt ( const Tableau<Noeud *>& tab_noeud
       ,Tableau <EnuTypeCL> const & tabTypeCL,Tableau <Coordonnee3> const & vplan)
  { Tableau<Coordonnee3> tab_coor(6);
    // actuellement les courbures s'obtiennent à l'aide des noeuds sommets du triangle
    // du milieu et des noeuds externes: on est pour l'instant dans un cadre de triangle
    for (int i=1;i< 4;i++) // les 3 noeuds sommet interne
      tab_coor(i) = tab_noeud(i)->Coord2();
    for (int i=1;i< 4;i++) // les noeuds externes
     tab_coor(i+3) = tab_noeud(i+nbNoeudCentral)->Coord2();
//    for (int i=1;i<=6;i++)
//      tab_coor(i) = tab_noeud(i)->Coord2();
    curb_tdt = (this->*PtCourbure)(tab_coor,(*aiB_tdt),(*aiH_tdt),tabTypeCL,vplan);
    return curb_tdt;
  };
       
//--------------// calcul du tenseur de courbure et de sa variation 
// plusieurs cas sont etudies suivant l'instant considere
// a l'instant t 
void Met_Sfe1::Dcourbure_t 
 ( const Tableau<Noeud *>& tab_noeud,Tenseur_ns2BB& curb,TabOper<Tenseur_ns2BB>& dcurb
       ,Tableau <EnuTypeCL> const & tabTypeCL,Tableau <Coordonnee3> const & vplan)
  { Tableau<Coordonnee3> tab_coor(6);
    // actuellement les courbures s'obtiennent à l'aide des noeuds sommets du triangle
    // du milieu et des noeuds externes: on est pour l'instant dans un cadre de triangle
    for (int i=1;i< 4;i++) // les 3 noeuds sommet interne
      tab_coor(i) = tab_noeud(i)->Coord1();
    for (int i=1;i< 4;i++) // les noeuds externes
     tab_coor(i+3) = tab_noeud(i+nbNoeudCentral)->Coord1();
//    for (int i=1;i<=6;i++)
//      tab_coor(i) = tab_noeud(i)->Coord1();
    (this->*PtDcourbure) (tab_coor,(*aiB_t),*d_aiB_t,(*aiH_t),*d_aiH_t,curb,dcurb,tabTypeCL,vplan);
  };
// a l'instant t+dt
void Met_Sfe1::Dcourbure_tdt 
 ( const Tableau<Noeud *>& tab_noeud,Tenseur_ns2BB& curb,TabOper<Tenseur_ns2BB>& dcurb
       ,Tableau <EnuTypeCL> const & tabTypeCL,Tableau <Coordonnee3> const & vplan)
  { Tableau<Coordonnee3> tab_coor(6);
    // actuellement les courbures s'obtiennent à l'aide des noeuds sommets du triangle
    // du milieu et des noeuds externes: on est pour l'instant dans un cadre de triangle
    for (int i=1;i< 4;i++) // les 3 noeuds sommet interne
      tab_coor(i) = tab_noeud(i)->Coord2();
    for (int i=1;i< 4;i++) // les noeuds externes
     tab_coor(i+3) = tab_noeud(i+nbNoeudCentral)->Coord2();
//    for (int i=1;i<=6;i++)
//      tab_coor(i) = tab_noeud(i)->Coord2();
    (this->*PtDcourbure) (tab_coor,(*aiB_tdt),*d_aiB_tdt,(*aiH_tdt),*d_aiH_tdt,curb,dcurb,tabTypeCL,vplan);
  };

// ----------- routines internes pour calculer les différentes formes de courbures 

// routine generale de calcul de la courbure
// cas 1: calcul des 3 courbures suivant les 3 cotés
Tenseur_ns2BB Met_Sfe1::Courbure1
  ( const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB , const BaseH & aiH 
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )

   { Vecteur curbp(3),curbi(3); // : les tenseurs de courbures d'abord dans les axes
     // locaux des arretes du triangle puis dans le repere naturel: b11,b12,b22
     Mat_pleine mat(3,3); // matrice pour calculer le tenseur de courbure 
     // calcul de la normale centrale 
     Coordonnee3 N(Util::ProdVec_coorBN(aiB(1),aiB(2)).Normer());
     // calcul du centre de gravite
     Coordonnee3 G((tab_coor(1) + tab_coor(2) + tab_coor(3)) / 3.);
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise indi un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Coordonnee3 Ni(3); // normale du triangle exterieur
     // def des différentes grandeurs
     Coordonnee3 G2;
     Coordonnee3 H2G2,CB,U1,CG2,C_G,CA,dNdV;
     Coordonnee3 U2p;   
     for (int ncot=1;ncot<=3;ncot++)
       { // on utilise les notations : triangle principal DBC et secondaire BAC
         // on cherche a calculer la longueur H2G2
          // simplification de l'ecriture (vérifiée)
        const  Coordonnee3& D = tab_coor(indi(ncot));
        const  Coordonnee3& B = tab_coor(indi(ncot+1));
        const  Coordonnee3& C = tab_coor(indi(ncot+2));
        const  Coordonnee3& A = tab_coor(indi(ncot)+3);
         if (D != A) // cas ou le noeud externe existe
          { // calcul de G2, centre de gravite du triangle exterieur           
           G2 = (B + C + A) / 3.;
           // calcul de U1                      
           CB = B - C;
           U1 = CB / CB.Norme(); 
           // vecteur CG2
           CG2 = G2 - C;
           // longueur h2G2 et g_h1 et calcul du vecteur H2G2 norme
           // tout d'abord H2G2 ce situe dans le plan de la facette externe
           H2G2 = CG2 - (CG2 * U1) * U1;
           double h2G2 = H2G2.Norme();
           double unSurh2G2= 1./h2G2;
           // maintenant on considere la direction H2G2, ramenée dans le plan de la facette centrale: U2p
           U2p = Util::ProdVec_coor(N,U1);                    
           C_G = G - C; // on met un _ car ce nom existe pour une autre routine
           double g_h1 = sqrt ( C_G * C_G - ( C_G * U1)* ( C_G * U1)) ; 
           // calcul de la normale du triangle exterieur
           CA = A - C;
           Ni =  (Util::ProdVec_coor(CB,CA)).Normer(); 
           // calcul de la derivee de la normale
           dNdV = ( Ni - N) / ( g_h1 + h2G2);
           // courbure dans la direction  U2p
           curbp(ncot) = - dNdV * U2p;
           }
         else // cas ou il n'y a pas de noeud externe 
          { // la courbure est nulle
            curbp(ncot) = 0.;
            // la direction de la courbure nulle est normale au cote
            // c-a-d le produit vectoriel de la normale avec le cote
            CB = B - C;
            double norCB = CB.Norme();
            U1 = CB / norCB;
            U2p = Util::ProdVec_coor(N,U1);
           }
         // calcul de la matrice de passage de Ualpha a aalpha
         double Beta21 = U2p * aiH.Coordo(1);
         double Beta22 = U2p * aiH.Coordo(2);
         // remplissage de la matrice mat
         mat(ncot,1) = Beta21*Beta21;
         mat(ncot,2) = 2.* Beta21*Beta22;
         mat(ncot,3) = Beta22*Beta22;
        };
	 
      // calcul du tenseur de courbure dans la base ai
      Mat_pleine mati = mat.Inverse();
      curbi = mati * curbp;
      // retour de la courbure
      Tenseur_ns2BB curb;
      curb.Coor(1,1)=curbi(1); curb.Coor(1,2)=curb.Coor(2,1)=curbi(2); curb.Coor(2,2)=curbi(3);
      return curb;	 
   };
       
// routine generale de calcul de la courbure et de sa variation
// en sortie : curb , la courbure  b11,b12,b22
//            dcurb , la variation de courbure.
// On ne considere dans les variations que les termes relatif aux ddl qui font varier
// les normales
// cas 1: calcul des 3 courbures suivant les 3 cotés
void Met_Sfe1::Dcourbure1
 (  const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB
    , const Tableau <BaseB>& DaiB,const BaseH & aiH
    , const Tableau <BaseH>& DaiH,Tenseur_ns2BB& curb,TabOper <Tenseur_ns2BB>& dcurb
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )
   { int nbddl = (nbNoeudCentral+3)*3; //18;   // nombre de ddl total
     Coordonnee3 Nul; // le vecteur nul de dim 3, pour les initialisations
     Vecteur curbi(3); // la courbure sous forme de vecteur
     Vecteur curbp(3); // : les tenseurs de courbures  dans les axes
                       // locaux des arretes du triangle
     double untiers=1./3.;
     Vecteur vecNul(3); // un vecteur nul pour l'initialisation                  
     Tableau <Vecteur> dcurbp(nbddl,vecNul); // variation des courbures
     Mat_pleine mat(3,3); // matrice pour calculer le tenseur de courbure
     Tableau <Mat_pleine> dmat(nbddl,mat); 
     // calcul de la normale centrale 
     Coordonnee3 NN(Util::ProdVec_coorBN(aiB(1),aiB(2))); // normale non normee
     double nor = NN.Norme(); // la norme
     Coordonnee3 N = NN / nor;
     Coordonnee3 DNN; // vecteur intermediaire
     // calcul du centre de gravite
     Coordonnee3 G ((tab_coor(1) + tab_coor(2) + tab_coor(3)) * untiers);
     // et le tableau de ses variations
     Tableau <Coordonnee3> dG(nbddl,Nul); 
     // calcul de la variation de la normale centrale et du centre de gravité: vérifiée
     Tableau <Coordonnee3> dN(nbddl,Nul);
     // on s'intéresse ici qu'aux ddl de la face centrale
     for (int inc=1;inc<=3;inc++) // indice du numéro de noeud de la face centrale
       for (int ib=1;ib<=3;ib++)
       	{ // cas de la normale
       	  int i1=(inc-1)*3+ib;
          DNN = Util::ProdVec_coorBN(DaiB(i1)(1),aiB(2)) + Util::ProdVec_coorBN(aiB(1),DaiB(i1)(2));
          dN(i1) = Util::VarUnVect_coor(NN,DNN,nor);
          // cas du centre de gravité
          dG(i1)=untiers*Ia(ib);
       	};
          
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Coordonnee3 NNi,Ni; // normale du triangle exterieur 
     // -------- declaration pour la boucle sur les 3 cotes ------------
     Coordonnee3 G2(3); // init a zero et a 3 composantes 
     Tableau <Coordonnee3> dB(nbddl,Nul),dC(nbddl,Nul),dA(nbddl,Nul),dG2(nbddl,Nul) ; // variation des points
     Vecteur d_g_h1(nbddl);
     Coordonnee3 CB,U1,CG2,H2G2,U2p;
     Tableau <Coordonnee3> dCB(nbddl,Nul),dU1(nbddl,Nul);
     Coordonnee3 C_G,CA,dNdV;
     Tableau <Coordonnee3> dCA(nbddl,Nul),dNi(nbddl,Nul);
     Coordonnee3 ddNdv; 
     for (int ncot=1;ncot<=3;ncot++)
      { // on utilise les notations : triangle principal DBC et secondaire BAC
        // on cherche a calculer la longueur H2G2
           // simplification de l'ecriture
       const  Coordonnee3& D = tab_coor(indi(ncot));
       const  Coordonnee3& B = tab_coor(indi(ncot+1));
       const  Coordonnee3& C = tab_coor(indi(ncot+2));
       const  Coordonnee3& A = tab_coor(indi(ncot)+3);
        if (D != A) // cas ou le noeud externe existe
        {// calcul de G2, centre de gravite du triangle exterieur           
         G2 = (B + C + A) * untiers;
         // calcul de U1                      
         CB = B - C;
         double norCB = CB.Norme();
         U1 = CB / norCB;
         // vecteur CG2
         CG2 = G2 - C;
         // longueur h2G2 et g_h1 et calcul du vecteur H2G2 norme
         // tout d'abord H2G2 ce citue dans le plan de la facette externe
         H2G2 = CG2 - (CG2 * U1) * U1;
         double h2G2 = H2G2.Norme();
         double unSurh2G2= 1./h2G2;
         // maintenant on considere la direction H2G2, ramenée dans le plan de la facette centrale: U2p
         U2p = Util::ProdVec_coor(N,U1);                    
         C_G = G - C;
         double g_h1 = sqrt ( C_G * C_G - ( C_G * U1) * ( C_G * U1) ) ;
         // calcul de la normale du triangle exterieur
         CA = A - C;
         NNi =  Util::ProdVec_coor(CB,CA);
         double norNi = NNi.Norme();
         Ni =  NNi/norNi;
         // calcul de la derivee de la normale
         dNdV = ( Ni - N) / ( g_h1 + h2G2);
         // courbure dans la direction  U2p
         curbp(ncot) = - dNdV * U2p;
         // calcul de la matrice de passage de Ualpha a aalpha
         double Beta21 = U2p * aiH.Coordo(1);
         double Beta22 = U2p * aiH.Coordo(2);
         // remplissage de la matrice mat
         mat(ncot,1) = Beta21*Beta21;
         mat(ncot,2) = 2.* Beta21*Beta22;
         mat(ncot,3) = Beta22*Beta22;
         
         // calcul des variations
           // 1 - initialisation des vecteurs inter
         ddNdv.Zero();
           // 2 - init en fct des ddl
         for (int idi=1; idi<= nbddl; idi++)
           { dCA(idi).Zero(); dCB(idi).Zero();dNi(idi).Zero();
             dB(idi).Zero();dC(idi).Zero();dA(idi).Zero(); 
             dU1(idi).Zero();d_g_h1.Zero();dG2(idi).Zero();
            }; 
           // 3 - variation non nulle des Ni pour certaine valeur d'indice   
         for (int ia=1;ia<= 3;ia++)
           { // on a 3 indices pour chaque ia, pour lesquels la variation est non nulle
             // dans cette boucle on n'utilise pas systematiquement les 4 indices
             int  jnB = (indi(ncot+1)-1)*3+ia; // vérifié
             int jnC = (indi(ncot+2)-1)*3+ia;
             int jnA = 9+(ncot-1)*3+ia; //vérifié
             // tout d'abord les variations des points
             dB(jnB) = Ia(ia);
             dC(jnC) = Ia(ia);dA(jnA) = Ia(ia);
             dG2(jnA) = untiers * Ia(ia);dG2(jnB) = untiers * Ia(ia);dG2(jnC) = untiers * Ia(ia);
             // vecteur CB
             dCB(jnB) = dB(jnB); dCB(jnC) = - dC(jnC);
             // Vecteur CA = A - C
             dCA(jnC) = -dC(jnC); dCA(jnA) = dA(jnA);
             // Vecteur Ni =  (Util::ProdVec_coor(CB,CA)).Normer()
             dNi(jnC) = Util::VarUnVect_coor(NNi,(Util::ProdVec_coor(dCB(jnC),CA)+Util::ProdVec_coor(CB,dCA(jnC))),norNi);
             dNi(jnB) = Util::VarUnVect_coor(NNi,(Util::ProdVec_coor(dCB(jnB),CA)+Util::ProdVec_coor(CB,dCA(jnB))),norNi);
             dNi(jnA) = Util::VarUnVect_coor(NNi,(Util::ProdVec_coor(dCB(jnA),CA)+Util::ProdVec_coor(CB,dCA(jnA))),norNi);
             // Vecteur U1 = CB / norCB;
             dU1(jnC) = Util::VarUnVect_coor(CB,dCB(jnC),norCB);
             dU1(jnB) = Util::VarUnVect_coor(CB,dCB(jnB),norCB);
            };
         for (int ib=1;ib<= 3;ib++) // indice de coordonnées
           { // on a 4 indices pour chaque ia, pour lesquels la variation est non nulle
             // mais ici on utilise systematiquement les 4 indices d'ou une seconde boucle
             // egalement moins de stockage intermediaire
             // jnb[0] -> D, jnb[1] -> B, jnb[2] -> C, jnb[3] -> A,
             int jnb[4] = {(indi(ncot)-1)*3+ib,(indi(ncot+1)-1)*3+ib,
                          (indi(ncot+2)-1)*3+ib,9+(ncot-1)*3+ib};
             for (int jb=0;jb<=3;jb++)
               { // variation de g_h1
                 Coordonnee3 d_CG =dC(jnb[jb])-dG(jnb[jb]);
                 double d_CGsur2 = (d_CG * C_G);
                 double d_CG_U1 = d_CG * U1 + C_G * dU1(jnb[jb]);
                 double d_g_h1 = (d_CGsur2 - d_CG_U1)/g_h1;
                 // variation de h2G2
                 Coordonnee3 d_CG2 =dC(jnb[jb])-dG2(jnb[jb]);
                 Coordonnee3 d_H2G2 =d_CG2 - (d_CG2 * U1 + CG2 * dU1(jnb[jb])) * U1
                                           - (CG2 * U1) *dU1(jnb[jb]);
                 double d_h2G2 = (H2G2 * d_H2G2)/h2G2;
                 // vecteur dNdV = ( Ni - N) / ( g_h1 + h2G2)
                 ddNdv = ((dNi(jnb[jb]) - dN(jnb[jb])) 
                         - (Ni-N) * (d_g_h1 + d_h2G2) / ( g_h1 + h2G2)) / ( g_h1 + h2G2); 
                 // variation de U2p
                 Coordonnee3 d_U2p = Util::ProdVec_coor(dN(jnb[jb]),U1)+Util::ProdVec_coor(N,dU1(jnb[jb]));
                 // courbure  curbp(ncot) = dNdV * U2p;
                 dcurbp(jnb[jb])(ncot) = - (ddNdv * U2p + dNdV * d_U2p); 
                 // -- variation des composantes de mat
                 double d_Beta21 = d_U2p * aiH.Coordo(1) + U2p * DaiH(jnb[jb]).Coordo(1);
                 double d_Beta22 = d_U2p * aiH.Coordo(2) + U2p * DaiH(jnb[jb]).Coordo(2);
                 dmat(jnb[jb])(ncot,1)= 2. * Beta21 * d_Beta21;     
                 dmat(jnb[jb])(ncot,2)= 2. * (d_Beta21 * Beta22 + Beta21 * d_Beta22);     
                 dmat(jnb[jb])(ncot,3)= 2. * Beta22 * d_Beta22;     
                };             
            } 
         }
        else // cas ou il n'y a pas de noeud externe 
        { // la courbure est nulle
          curbp(ncot) = 0.;
          // la direction de la courbure nulle est normale au cote
          // c-a-d le produit vectoriel de la normale avec le cote
          CB = B - C;
          double norCB = CB.Norme();
          U1 = CB / norCB;
          H2G2 = Util::ProdVec_coor(N,U1);
          // calcul de la matrice de passage de Ualpha a aalpha
          double Beta21 = H2G2 * aiH.Coordo(1);
          double Beta22 = H2G2 * aiH.Coordo(2);
          // remplissage de la matrice mat
          mat(ncot,1) = Beta21*Beta21;
          mat(ncot,2) = 2.* Beta21*Beta22;
          mat(ncot,3) = Beta22*Beta22;
          
        }
      }; //-- fin de la boucle sur les trois cotés
      
     // calcul du tenseur de courbure dans la base ai
     Mat_pleine mati = mat.Inverse();
     curbi = mati * curbp;
     curb.Coor(1,1)=curbi(1); curb.Coor(1,2)=curb.Coor(2,1)=curbi(2); curb.Coor(2,2)=curbi(3);
     // idem pour les variations
     Mat_pleine dmata(mat); // une matrice intermédiaire
     for (int ddl=1;ddl<=nbddl;ddl++)
         { // tout d'abord le calcul de la variation de l'inverse de mat
           dmata = -(mati * dmat(ddl) * mati);
           // puis la variation de la courbure
           curbi = mati * dcurbp(ddl) + dmata * curbp;
           Tenseur_ns2BB& dcur = dcurb(ddl);
           dcur.Coor(1,1)=curbi(1); dcur.Coor(1,2)=dcur.Coor(2,1)=curbi(2); dcur.Coor(2,2)=curbi(3);
         };
   };

// test si la courbure est anormalement trop grande
// inf_normale : indique en entrée le det mini pour la courbure en locale
// retour 1:  si tout est ok,
//        0:  une courbure trop grande a été détecté
int Met_Sfe1::Test_courbure_anormale1(double inf_normale,const Tableau<Coordonnee3>& tab_coor
                 , const BaseB & aiB , const BaseH & aiH)
 {// pour l'instant cette méthode n'est pas alimentée on le signale
  if (ParaGlob::NiveauImpression()> 8)
    cout << "\n *** attention, cette methode n'est pas implante pour la courbure 1 "
         << "\n Met_Sfe1::Test_courbure_anormale1(... "<<endl;
  return 1; // retour par défaut
 };

// routine generale de calcul de la courbure
// cas 2: moyenne des normales de part et autres des arrêtes
Tenseur_ns2BB Met_Sfe1::Courbure2
  ( const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB , const BaseH &  
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )
   { Tenseur_ns2BB curb; // : les tenseurs de courbures d'abord dans les axes
     // au lieu d'utiliser des expressions condensées (en commentaire)
     // on utilise exactement la même procédure que pour dcurb
     // car sinon on a de très petites différences qui ensuite
     // conduisent à des différences non négligeables sur les def
     // calcul de la normale centrale
     // Coordonnee3 N((Util::ProdVec_coorBN(aiB(1),aiB(2))).Normer());
    
     // calcul de la normale centrale 
     Coordonnee3 NN(Util::ProdVec_coorBN(aiB(1),aiB(2))); // normale non normee
     double nor = NN.Norme(); // la norme
     Coordonnee3 N = NN / nor;
    
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise indi un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Tableau <Coordonnee3> t_Ni(3); // les 3 normales du triangle exterieur
//cout << "\n  N= "<<N;
     Coordonnee3 NNi,Ni,NietN; // normale du triangle exterieur 
     for (int ncot=1;ncot<=3;ncot++)
       { // on utilise les notations : triangle principal DBC et secondaire BAC
         // on cherche a calculer la longueur H2G2
          // simplification de l'ecriture (vérifiée)
        const  Coordonnee3& D = tab_coor(indi(ncot));
        const  Coordonnee3& B = tab_coor(indi(ncot+1));
        const  Coordonnee3& C = tab_coor(indi(ncot+2));
        const  Coordonnee3& A = tab_coor(indi(ncot)+3);
         if (D != A) // cas ou le noeud externe existe
          {// calcul de la normale du triangle exterieur
           Coordonnee3 CB = B - C;
           Coordonnee3 CA = A - C;
           //t_Ni(ncot) = ((Util::ProdVec_coor(CB,CA)).Normer() + N).Normer();
           
          NNi =  Util::ProdVec_coor(CB,CA);
          double norNi = NNi.Norme();
          Ni =  NNi/norNi;
          NietN=(Ni + N);
          double norNietN = NietN.Norme();
          t_Ni(ncot) = NietN / norNietN; 
           }
         else // cas ou il n'y a pas de noeud externe 
          { // on utilise la normale actuelle comme normale sur l'arrête
            t_Ni(ncot) = N;
           };
        };
      // calcul de la variation de la normale
      Coordonnee3 dN_1 = 2.*(t_Ni(1)-t_Ni(2));
      Coordonnee3 dN_2 = 2.*(t_Ni(1)-t_Ni(3));
      // courbure
      curb.Coor(1,1)=-dN_1 * aiB.Coordo(1);
      curb.Coor(1,2)=-dN_1 * aiB.Coordo(2);
      curb.Coor(2,1)=-dN_2 * aiB.Coordo(1);
      curb.Coor(2,2)=-dN_2 * aiB.Coordo(2);
      // retour de la courbure
      return curb;	 
   };
       
// routine generale de calcul de la courbure et de sa variation
// en sortie : curb , la courbure  b11,b12,b22
//            dcurb , la variation de courbure.
// On ne considere dans les variations que les termes relatif aux ddl qui font varier
// les normales
// cas 2: moyenne des normales de part et autres des arrêtes
void Met_Sfe1::Dcourbure2
 (  const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB
    , const Tableau <BaseB>& DaiB,const BaseH & 
    , const Tableau <BaseH>& ,Tenseur_ns2BB& curb,TabOper <Tenseur_ns2BB>& dcurb
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )
   { int nbddl = (nbNoeudCentral+3)*3; //18;   // nombre de ddl total
     Coordonnee3 Nul; // le vecteur nul de dim 3, pour les initialisations
     
     double untiers=1./3.;                  
     // calcul de la normale centrale 
     Coordonnee3 NN(Util::ProdVec_coorBN(aiB(1),aiB(2))); // normale non normee
     double nor = NN.Norme(); // la norme
     Coordonnee3 N = NN / nor;
     Coordonnee3 DNN; // vecteur intermediaire
     // calcul de la variation de la normale centrale et du centre de gravité: vérifiée
     Tableau <Coordonnee3> dN(nbddl,Nul);
     // on s'intéresse ici qu'aux ddl de la face centrale
     for (int inc=1;inc<=3;inc++) // indice du numéro de noeud de la face centrale
       for (int ib=1;ib<=3;ib++)
       	{ // cas de la normale
       	  int i1=(inc-1)*3+ib;
          DNN = Util::ProdVec_coorBN(DaiB(i1)(1),aiB(2)) 
               + Util::ProdVec_coorBN(aiB(1),DaiB(i1)(2));
          dN(i1) = Util::VarUnVect_coor(NN,DNN,nor);
       	};
          
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Coordonnee3 NNi,Ni,NietN; // normale du triangle exterieur 
     // -------- declaration pour la boucle sur les 3 cotes ------------
     Coordonnee3 CB,CA;
     Tableau <Coordonnee3> t_Ni(3); // les 3 normales du triangle exterieur
     Tableau <Tableau <Coordonnee3> > d_t_Ni(nbddl,t_Ni); // le tableau des variations
     Coordonnee3 dA,dB,dC,dNi; 
//cout << "\n NN= "<<NN <<" nor= "<< nor <<" N= "<<N;
     for (int ncot=1;ncot<=3;ncot++)
      { // on utilise les notations : triangle principal DBC et secondaire BAC
        // on cherche a calculer la longueur H2G2
           // simplification de l'ecriture
       const  Coordonnee3& D = tab_coor(indi(ncot));
       const  Coordonnee3& B = tab_coor(indi(ncot+1));
       const  Coordonnee3& C = tab_coor(indi(ncot+2));
       const  Coordonnee3& A = tab_coor(indi(ncot)+3);
        if (D != A) // cas ou le noeud externe existe
        {CB = B - C;
         double norCB = CB.Norme();
         // calcul de la normale du triangle exterieur
         CA = A - C;
         NNi =  Util::ProdVec_coor(CB,CA);
         double norNi = NNi.Norme();
         Ni =  NNi/norNi;
         NietN=(Ni + N);
         double norNietN = NietN.Norme();
         t_Ni(ncot) = NietN / norNietN; 
//cout << "\n CB= "<<CB <<" CA= "<< CA
//     << "t_Ni("<<ncot<<")= "<<t_Ni(ncot);
//cout << "\n norNi= "<< norNi<< " norNietN= "<< norNietN;
         
         // calcul des variations
         for (int ia=1;ia<= 3;ia++)
          {{// indice de A: jnA
//            int jnA = 9+(ncot-1)*3+ia;
//modif pour généraliser             int jnA = 9+(ncot-1)*3+ia; //vérifié
            int jnA = nbNoeudCentral*3+(ncot-1)*3+ia;
            dA = Ia(ia);
            //dCA = dA;
            // Vecteur Ni =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNi = Util::VarUnVect_coor(NNi,(Util::ProdVec_coor(CB,dA)),norNi);
            d_t_Ni(jnA)(ncot) = Util::VarUnVect_coor(NietN,(dNi+dN(jnA)),norNietN);
           }
           {// indice de B: jnB
            int  jnB = (indi(ncot+1)-1)*3+ia;
            dB = Ia(ia);
            //dCB = dB;
            // Vecteur Ni =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNi = Util::VarUnVect_coor(NNi,(Util::ProdVec_coor(dB,CA)),norNi);
            d_t_Ni(jnB)(ncot) = Util::VarUnVect_coor(NietN,(dNi+dN(jnB)),norNietN);
           }
           {// indice de C: jnC
            int jnC = (indi(ncot+2)-1)*3+ia;
            dC = Ia(ia);
            //dCB = -dC; dCA= -dC;
            // Vecteur Ni =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNi = Util::VarUnVect_coor(NNi,-(Util::ProdVec_coor(dC,CA)+Util::ProdVec_coor(CB,dC)),norNi);
            d_t_Ni(jnC)(ncot) = Util::VarUnVect_coor(NietN,(dNi+dN(jnC)),norNietN);
           }
           {// indice de D: jnD
            int jnD = (indi(ncot)-1)*3+ia;
            // Vecteur Ni =  (Util::ProdVec_coor(CB,CA)).Normer()
            // dNi = vecteur nul;
            d_t_Ni(jnD)(ncot) = Util::VarUnVect_coor(NietN,(dN(jnD)),norNietN);
           }
          }; // fin du for sur ia
        }
        else // cas ou il n'y a pas de noeud externe 
        { // on utilise la normale actuelle comme normale sur l'arrête
          t_Ni(ncot) = N;
//cout << "\n t_Ni("<<ncot<<")= "<<t_Ni(ncot);
          // et pour les variations, celle de N
          for (int ia=1;ia<= 3;ia++)
           { // indice de B: jnB
             int  jnB = (indi(ncot+1)-1)*3+ia;
             d_t_Ni(jnB)(ncot) = dN(jnB);
             // indice de C: jnC
             int jnC = (indi(ncot+2)-1)*3+ia;
             d_t_Ni(jnC)(ncot) = dN(jnC);
             // indice de D: jnD
             int jnD = (indi(ncot)-1)*3+ia;
             d_t_Ni(jnD)(ncot) = dN(jnD);
           }; // fin du for sur ia
         };
        
      }; //-- fin de la boucle sur les trois cotés
      
     // calcul de la variation de la normale
     Coordonnee3 dN_1 = 2.*(t_Ni(1)-t_Ni(2));
     Coordonnee3 dN_2 = 2.*(t_Ni(1)-t_Ni(3));
     // courbure
     curb.Coor(1,1)=-dN_1 * aiB.Coordo(1);
     curb.Coor(1,2)=-dN_1 * aiB.Coordo(2);
     curb.Coor(2,1)=-dN_2 * aiB.Coordo(1);
     curb.Coor(2,2)=-dN_2 * aiB.Coordo(2);
//cout << "\n 2) curb= "; curb.Ecriture(cout);
//cout << endl;
    
     // calcul des variations de la courbure par rapport au ddl
     for (int ddl=1;ddl<=nbddl;ddl++)
     	{Tenseur_ns2BB& dcur = dcurb(ddl);
     	 dcur.Coor(1,1) = (-2.) * ((d_t_Ni(ddl)(1)-d_t_Ni(ddl)(2)) * aiB.Coordo(1))  - dN_1 * DaiB(ddl).Coordo(1);
       dcur.Coor(1,2)= -(2.* (d_t_Ni(ddl)(1)-d_t_Ni(ddl)(2)) * aiB.Coordo(2) +      (dN_1 * DaiB(ddl).Coordo(2)));
       dcur.Coor(2,1)= -(2.*(d_t_Ni(ddl)(1)-d_t_Ni(ddl)(3)) * aiB.Coordo(1) +      (dN_2 * DaiB(ddl).Coordo(1)));
     	 dcur.Coor(2,2) = (-2.) * ((d_t_Ni(ddl)(1)-d_t_Ni(ddl)(3)) * aiB.Coordo(2)) - dN_2 * DaiB(ddl).Coordo(2);
     	};
   };

// test si la courbure est anormalement trop grande
// inf_normale : indique en entrée le det mini pour la courbure en locale
// retour 1:  si tout est ok,
//        0:  une courbure trop grande a été détecté
int Met_Sfe1::Test_courbure_anormale2(double inf_normale,const Tableau<Coordonnee3>& tab_coor
                 , const BaseB & aiB , const BaseH & aiH)
 {// pour l'instant cette méthode n'est pas alimentée on le signale
  if (ParaGlob::NiveauImpression()> 8)
    cout << "\n *** attention, cette methode n'est pas implante pour la courbure 2 "
         << "\n Met_Sfe1::Test_courbure_anormale2(... "<<endl;
  return 1; // retour par défaut
 };

// routine (3) generale de calcul de la courbure
// cas 3: moyenne pondérée des normales de part et autres des arrêtes, et localisation du point sur l'arrête
Tenseur_ns2BB Met_Sfe1::Courbure3
  ( const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB , const BaseH & aiH 
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )

   { // calcul de la normale centrale 
     Coordonnee3 N((Util::ProdVec_coorBN(aiB(1),aiB(2))).Normer());
     // calcul du centre de gravite
     Coordonnee3 G = (tab_coor(1) + tab_coor(2) + tab_coor(3)) / 3.;
     // les coordonnées locales non nulles des points origines des normales sur les arrêtes
     // on les initialise comme si les points étaient au milieu des arrêtes
     double theta1_H1=0.5; double theta2_H1=0.5; 
     double theta2_H2=0.5; double theta1_H3=0.5;
     // origine
     const Coordonnee3& Op=tab_coor(1);// origine du repère local
     
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise indi un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Tableau <Coordonnee3> t_Ni(3); // normale du triangle exterieur
     // def des différentes grandeurs
     Coordonnee3 Ne; // normale courante du triangle extérieur
     Coordonnee3 CB,CA,CD; Coordonnee3 G2;
     Coordonnee3 U1,HaA,OpHi;  
     for (int ncot=1;ncot<=3;ncot++)
       { // on utilise les notations : triangle principal DBC et secondaire BAC
         // on cherche a calculer la longueur H2G2
          // simplification de l'ecriture (vérifiée)
        const  Coordonnee3& D = tab_coor(indi(ncot));
        const  Coordonnee3& B = tab_coor(indi(ncot+1));
        const  Coordonnee3& C = tab_coor(indi(ncot+2));
        const  Coordonnee3& A = tab_coor(indi(ncot)+3);
         if (D != A) // cas ou le noeud externe existe
          {// calcul de G2, centre de gravite du triangle exterieur           
           G2 = (B + C + A) / 3.;
           // calcul de U1                      
           CB = B - C;
           CA = A - C;
           U1 = CB / CB.Norme(); 
           // longueur HaA et HdD et calcul du vecteur HaA norme
           // tout d'abord HaA ce situe dans le plan de la facette externe
           HaA = CA - (CA * U1) * U1;
           double haA = HaA.Norme();
           double unSurhaA= 1./haA;
           CD = D - C; 
           double dHd = sqrt ( CD * CD - ( CD * U1)* ( CD * U1)) ; 
           // calcul de la normale du triangle exterieur
           Ne =  (Util::ProdVec_coor(CB,CA)).Normer(); 
           // calcul de la normale
           t_Ni(ncot) = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA))).Normer();
           // calcul des coordonnées de la position des normales sur les arrêtes
           double beta = 0.5 * (G + G2 - 2. * B) * U1;
           OpHi=B+beta*U1-Op;
           switch (ncot)
           	{case 1: theta1_H1=OpHi*aiH.Coordo(1);theta2_H1=OpHi*aiH.Coordo(2); break;
           	 case 2: theta2_H2=OpHi*aiH.Coordo(2); break;
           	 case 3: theta1_H3=OpHi*aiH.Coordo(1); break;
           	};
           }
         else // cas ou il n'y a pas de noeud externe 
          {// on utilise comme normale extérieure la normale du triangle central
           t_Ni(ncot) = N; 
           // on utilise le point milieu de l'arrête pour le positionnement de la normale
           // normalement les points sont déjà initialisés
          };
       };
	 
     // calcul des coefficients des fonctions d'interpolation
     double s= theta1_H1 * theta2_H2 - theta1_H3 * theta2_H2 + theta2_H1 * theta1_H3;
     double a_r1= theta2_H2 / s; double b_r1 = theta1_H3 / s; double c_r1 = -theta1_H3 * theta2_H2/s;
     double a_r2= -theta2_H1 / s; double b_r2 = 1./theta2_H2 - theta1_H3 * theta2_H1 /theta2_H2/ s; 
                                               double c_r2 = -theta1_H3 * theta2_H1/s;
     double a_r3= 1./theta1_H3 - theta1_H1 * theta2_H2 /theta1_H3/ s; double b_r3 = - theta1_H1 / s; 
                                               double c_r3 = theta2_H2 * theta1_H1 /s;
     // calcul de la variation de la normale
     Coordonnee3 d_N_1= t_Ni(1) * a_r1 + t_Ni(2) * a_r2 + t_Ni(3) * a_r3 ;
     Coordonnee3 d_N_2= t_Ni(1) * b_r1 + t_Ni(2) * b_r2 + t_Ni(3) * b_r3 ;
     // calcul de la courbure
     Tenseur_ns2BB curb;
     curb.Coor(1,1) = - d_N_1 * aiB.Coordo(1); curb.Coor(1,2) = - d_N_1 * aiB.Coordo(2);
     curb.Coor(2,1) = - d_N_2 * aiB.Coordo(1); curb.Coor(2,2) = - d_N_2 * aiB.Coordo(2);
     // retour de la courbure
     return curb;	 
   };

// test si la courbure est anormalement trop grande
// inf_normale : indique en entrée le det mini pour la courbure en locale
// retour 1:  si tout est ok,
//        0:  une courbure trop grande a été détecté
int Met_Sfe1::Test_courbure_anormale3(double inf_normale,const Tableau<Coordonnee3>& tab_coor
                 , const BaseB & aiB , const BaseH & aiH)
 {// pour l'instant cette méthode n'est pas alimentée on le signale
  if (ParaGlob::NiveauImpression()> 8)
    cout << "\n *** attention, cette methode n'est pas implante pour la courbure 3 "
         << "\n Met_Sfe1::Test_courbure_anormale1(... "<<endl;
  return 1; // retour par défaut
 };

// routine (3) generale de calcul de la courbure et de sa variation
// en sortie : curb , la courbure  b11,b12,b22
//            dcurb , la variation de courbure.
// On ne considere dans les variations que les termes relatif aux ddl qui font varier
// les normales
// cas 3: moyenne pondérée des normales de part et autres des arrêtes, et localisation du point sur l'arrête
void Met_Sfe1::Dcourbure3
 (  const Tableau<Coordonnee3>& tab_coor, const BaseB & aiB
    , const Tableau <BaseB>& DaiB,const BaseH & aiH
    , const Tableau <BaseH>& DaiH,Tenseur_ns2BB& curb,TabOper <Tenseur_ns2BB>& dcurb
    ,Tableau <EnuTypeCL> const & ,Tableau <Coordonnee3> const & )
   { int nbddl = (nbNoeudCentral+3)*3; //18;   // nombre de ddl total
     Coordonnee3 Nul; // le vecteur nul de dim 3, pour les initialisations

     // les coordonnées locales non nulles des points origines des normales sur les arrêtes
     // on les initialise comme si les points étaient au milieu des arrêtes
     double theta1_H1=0.5; double theta2_H1=0.5; 
     double theta2_H2=0.5; double theta1_H3=0.5;
     // origine
     const Coordonnee3& Op=tab_coor(1);// origine du repère local
     Tableau <Coordonnee3> dOp(nbddl,Nul);
     dOp(1)=Ia(1);dOp(2)=Ia(2);dOp(3)=Ia(3);
     // et les variations
     Vecteur d_theta1_H1(nbddl), d_theta2_H1(nbddl), d_theta2_H2(nbddl), d_theta1_H3(nbddl); 
     double untiers=1./3.;                  
     // calcul du centre de gravite
     Coordonnee3 G = (tab_coor(1) + tab_coor(2) + tab_coor(3)) * untiers;
     // et le tableau de ses variations
     Tableau <Coordonnee3> dG(nbddl,Nul); 

     // calcul de la normale centrale 
     Coordonnee3 NN(Util::ProdVec_coorBN(aiB(1),aiB(2))); // normale non normee
     double nor = NN.Norme(); // la norme
     Coordonnee3 N = NN / nor;
     Coordonnee3 DNN; // vecteur intermediaire
     // calcul de la variation de la normale centrale et du centre de gravité: vérifiée
     Tableau <Coordonnee3> dN(nbddl,Nul);
     // on s'intéresse ici qu'aux ddl de la face centrale
     for (int inc=1;inc<=3;inc++) // indice du numéro de noeud de la face centrale
       for (int ib=1;ib<=3;ib++)
       	{ // cas de la normale
       	  int i1=(inc-1)*3+ib;
          DNN = Util::ProdVec_coorBN(DaiB(i1)(1),aiB(2)) 
               + Util::ProdVec_coorBN(aiB(1),DaiB(i1)(2));
          dN(i1) = Util::VarUnVect_coor(NN,DNN,nor);
          // cas du centre de gravité
          dG(i1)=untiers*Ia(ib);
       	};
          
     // le meme calcul est effectue pour les trois cotes du triangle principale
        //1- on utilise un tableau d'indice pour ne pas etre embete par les modulos 3
        // 2- on boucle sur le cotes du triangle
     Tableau <Coordonnee3> t_Ni(3); // normale du triangle exterieur
     Tableau < Tableau <Coordonnee3> > d_t_Ni(nbddl,t_Ni); // les dérivées, initialisées à celle de dN
     Coordonnee3 NNi; // normale du triangle exterieur 
     // def des différentes grandeurs
     Coordonnee3 Ne,NNe; // normale courante du triangle extérieur et sa valeur non normée
     Coordonnee3 CB,CA,CD; Coordonnee3 G2,dG2;
     Coordonnee3 U1,HaA,OpHi; Coordonnee3  BgimoinsGB;
     // -------- declaration pour la boucle sur les 3 cotes ------------     
     Coordonnee3 dA,dB,dC,dD,d_U1,dNe,d_HaA,d_NNi,d_Op,d_OpHi;
     Coordonnee3 t_NNi; // normale courante non normée sur l'arrête
     for (int ncot=1;ncot<=3;ncot++)
      { // on utilise les notations : triangle principal DBC et secondaire BAC
        // on cherche a calculer la longueur H2G2
           // simplification de l'ecriture
       const  Coordonnee3& D = tab_coor(indi(ncot));
       const  Coordonnee3& B = tab_coor(indi(ncot+1));
       const  Coordonnee3& C = tab_coor(indi(ncot+2));
       const  Coordonnee3& A = tab_coor(indi(ncot)+3);
        if (D != A) // cas ou le noeud externe existe
        {// calcul de G2, centre de gravite du triangle exterieur           
         G2 = (B + C + A) * untiers;
         // calcul de U1                      
         CB = B - C;
         CA = A - C;
         double norCB = CB.Norme();
         U1 = CB / norCB;
         // longueur HaA et HdD et calcul du vecteur HaA norme
         // tout d'abord HaA ce situe dans le plan de la facette externe
         HaA = CA - (CA * U1) * U1;
         double haA = HaA.Norme();
         double unSurhaA= 1./haA;
         CD = D - C; 
         double dHd = sqrt ( CD * CD - ( CD * U1)* ( CD * U1)) ;
//         double distH = dHd + haA;
//         double inv_distH = 1./distH; double inv_distH2 =  inv_distH * inv_distH;
         // calcul de la normale du triangle exterieur
         NNe =  (Util::ProdVec_coor(CB,CA)); 
         double norNe = NNe.Norme();
         Ne =  NNe/norNe; 
         // calcul de la normale
         t_NNi = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA)));
         double nor_t_NNi = t_NNi.Norme();
         t_Ni(ncot) = t_NNi / nor_t_NNi;
         // calcul des coordonnées de la position des normales sur les arrêtes
         BgimoinsGB = (G + G2 - 2. * B);
         double beta = 0.5 * BgimoinsGB * U1;
         OpHi=B+beta*U1-Op;
         switch (ncot)
         	{case 1: theta1_H1=OpHi*aiH.Coordo(1);theta2_H1=OpHi*aiH.Coordo(2); break;
         	 case 2: theta2_H2=OpHi*aiH.Coordo(2); break;
         	 case 3: theta1_H3=OpHi*aiH.Coordo(1); break;
         	}; 
         
         // calcul des variations
         for (int ia=1;ia<= 3;ia++)
          {{// indice de A: jnA, noeud extérieur
// modif pour généraliser            int jnA = 9+(ncot-1)*3+ia;
            int jnA = nbNoeudCentral*3+(ncot-1)*3+ia;
            dA = Ia(ia);
            //dCA = dA;
            // Vecteur Ne =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNe = Util::VarUnVect_coor(NNe,(Util::ProdVec_coor(CB,dA)),norNe);
            // ici d_CB=0 donc d_U1=0
            // ici d_CD=0 donc d_dHd=0
            d_HaA = dA - (dA * U1) * U1;
            double d_haA = HaA * d_HaA * unSurhaA ;
            // t_Ni(ncot) = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA))).Normer();
            d_NNi = (dNe*(dHd/(dHd+haA)) + dN(jnA)*(haA/(dHd+haA)))
                     + (Ne*(-dHd*d_haA/(dHd+haA)/(dHd+haA)) + N*(d_haA/(dHd+haA)))
                     + ( N*(-haA*d_haA/(dHd+haA)/(dHd+haA)));
            d_t_Ni(jnA)(ncot) = Util::VarUnVect_coor(t_NNi,d_NNi,nor_t_NNi);
            // maintenant la variation des theta
            // G2 = (B + C + A) * untiers;
            dG2 = dA * untiers;
            //  beta = 0.5 * (G + G2 - 2. * B) * U1;
            // ici dG(jnA) = 0
            double d_beta = 0.5 * (dG2 * U1);
            d_OpHi=d_beta*U1;  // OpHi=B+beta*U1-Op;
            switch (ncot)
         	 {case 1: {d_theta1_H1(jnA)=d_OpHi*aiH.Coordo(1);d_theta2_H1(jnA)=d_OpHi*aiH.Coordo(2); break;}
         	  case 2:  d_theta2_H2(jnA)=d_OpHi*aiH.Coordo(2); break;
         	  case 3:  d_theta1_H3(jnA)=d_OpHi*aiH.Coordo(1); break;
         	};
           }
           {// indice de B: jnB, noeud de la facette centrale
            int  jnB = (indi(ncot+1)-1)*3+ia;
            dB = Ia(ia); // d_CB = dB, d_CA=0
            d_U1= Util::VarUnVect_coor(CB,dB,norCB);
            // HaA = CA - (CA * U1) * U1;
            d_HaA =  - ((CA*d_U1) * U1 +(CA * U1) * d_U1);
            double d_haA = HaA * d_HaA * unSurhaA ;
            // d_CD = 0; dHd = sqrt ( CD * CD - ( CD * U1)* ( CD * U1)) ;
            double d_dHd = - ( CD * d_U1)* ( CD * U1) / dHd ; 
            // Vecteur Ne =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNe = Util::VarUnVect_coor(NNe,(Util::ProdVec_coor(dB,CA)),norNe);
            // t_Ni(ncot) = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA))).Normer();
            d_NNi = (dNe*(dHd/(dHd+haA)) + dN(jnB)*(haA/(dHd+haA)))
                     + (Ne*(d_dHd/(dHd+haA)) + N*(d_haA/(dHd+haA)))
                     + (Ne*(-dHd*d_haA/(dHd+haA)/(dHd+haA))+ N*(-haA*d_haA/(dHd+haA)/(dHd+haA)))
                     + (Ne*(-dHd*d_dHd/(dHd+haA)/(dHd+haA)) + N*(-haA*d_dHd/(dHd+haA)/(dHd+haA)));
            d_t_Ni(jnB)(ncot) = Util::VarUnVect_coor(t_NNi,d_NNi,nor_t_NNi);
            // maintenant la variation des theta
            // G2 = (B + C + A) * untiers;
            dG2 = dB * untiers;
            //  beta = 0.5 * (G + G2 - 2. * B) * U1;
            double d_beta = 0.5 * ((dG(jnB) + dG2 - 2. * dB) * U1 + BgimoinsGB * d_U1);
 //           if (ncot == 3) {d_Op=dB;} else { d_Op= Nul;};
//            d_OpHi=dB + d_beta*U1+beta*d_U1-d_Op;
            d_OpHi=dB + d_beta*U1+beta*d_U1-dOp(jnB);
            
            switch (ncot)
         	 {case 1: {d_theta1_H1(jnB)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnB).Coordo(1);
         	           d_theta2_H1(jnB)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnB).Coordo(2); break; }
         	  case 2:  d_theta2_H2(jnB)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnB).Coordo(2); break;
         	  case 3:  d_theta1_H3(jnB)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnB).Coordo(1); break;
         	};
           }
           {// indice de C: jnC
            int jnC = (indi(ncot+2)-1)*3+ia;
            dC = Ia(ia);
            //dCB = -dC; dCA= -dC; U1 = CB / norCB;
            d_U1= Util::VarUnVect_coor(CB,-dC,norCB);
            // HaA = CA - (CA * U1) * U1;
            d_HaA = -dC - ((-dC * U1)+(CA*d_U1)) * U1 -(CA * U1) * d_U1;
            double d_haA = HaA * d_HaA * unSurhaA ;
            // d_CD = -dC; dHd = sqrt ( CD * CD - ( CD * U1)* ( CD * U1)) ; 
            double d_dHd = - (CD*dC + ( CD * d_U1- dC*U1) * ( CD * U1) ) / dHd ; 
            // Vecteur Ne =  (Util::ProdVec_coor(CB,CA)).Normer()
            dNe = Util::VarUnVect_coor(NNe,(-(Util::ProdVec_coor(dC,CA)+Util::ProdVec_coor(CB,dC))),norNe);
            // t_Ni(ncot) = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA))).Normer();
            d_NNi = (dNe*(dHd/(dHd+haA)) + dN(jnC)*(haA/(dHd+haA)))
                     + (Ne*(d_dHd/(dHd+haA)) + N*(d_haA/(dHd+haA)))
                     + (Ne*(-dHd*d_haA/(dHd+haA)/(dHd+haA)) + N*(-haA*d_haA/(dHd+haA)/(dHd+haA)))
                     + (Ne*(-dHd*d_dHd/(dHd+haA)/(dHd+haA)) + N*(-haA*d_dHd/(dHd+haA)/(dHd+haA)));
            d_t_Ni(jnC)(ncot) = Util::VarUnVect_coor(t_NNi,d_NNi,nor_t_NNi);
            // maintenant la variation des theta
            // G2 = (B + C + A) * untiers;
            dG2 = dC * untiers;
            //  beta = 0.5 * (G + G2 - 2. * B) * U1;
            double d_beta = 0.5 * ((dG(jnC) + dG2 ) * U1 + BgimoinsGB * d_U1);
//            if (ncot == 2) {d_Op=dC;} else { d_Op= Nul;};
//            d_OpHi=d_beta*U1+beta*d_U1-d_Op;
            d_OpHi=d_beta*U1+beta*d_U1-dOp(jnC);
            
            switch (ncot)
         	 {case 1: {d_theta1_H1(jnC)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnC).Coordo(1);
         	           d_theta2_H1(jnC)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnC).Coordo(2); break; }
         	  case 2: d_theta2_H2(jnC)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnC).Coordo(2); break;
         	  case 3: d_theta1_H3(jnC)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnC).Coordo(1); break;
         	};
           }
           {// indice de D: jnD
            int jnD = (indi(ncot)-1)*3+ia;
            // d_CB = 0; d_CA = 0 ==> d_U1=0 
            // d_HaA = 0, et d_haA = 0
            // d_CD = dD; 
            // dHd = sqrt ( CD * CD - ( CD * U1)* ( CD * U1)) ; 
            double d_dHd = (CD*dD - (dD * U1) * ( CD * U1) ) / dHd ;
            // Vecteur Ne =  (Util::ProdVec_coor(CB,CA)).Normer()
            //dNe = 0
            // t_Ni(ncot) = (Ne*(dHd/(dHd+haA)) + N*(haA/(dHd+haA))).Normer();
            d_NNi = (dN(jnD)*(haA/(dHd+haA)))
                     + (Ne*(d_dHd/(dHd+haA)))
                     + (Ne*(-dHd*d_dHd/(dHd+haA)/(dHd+haA)) + N*(-haA*d_dHd/(dHd+haA)/(dHd+haA)));
            d_t_Ni(jnD)(ncot) = Util::VarUnVect_coor(t_NNi,d_NNi,nor_t_NNi);
            // maintenant la variation des theta
            // G2 = (B + C + A) * untiers;
            //dG2 = 0;
            //  beta = 0.5 * (G + G2 - 2. * B) * U1;
            double d_beta = 0.5 * (dG(jnD) * U1);
//            if (ncot == 1) {d_Op=dD;} else { d_Op= Nul;};
            // dB=0
//            d_OpHi=d_beta*U1-d_Op;
            d_OpHi=d_beta*U1-dOp(jnD);
            
            switch (ncot)
         	 {case 1: {d_theta1_H1(jnD)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnD).Coordo(1);
         	           d_theta2_H1(jnD)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnD).Coordo(2); break; }
         	  case 2:  d_theta2_H2(jnD)=d_OpHi*aiH.Coordo(2)+OpHi*DaiH(jnD).Coordo(2); break;
         	  case 3:  d_theta1_H3(jnD)=d_OpHi*aiH.Coordo(1)+OpHi*DaiH(jnD).Coordo(1); break;
         	};
           }
          }; // fin du for sur ia
         
         }
        else // cas ou il n'y a pas de noeud externe 
        { // on utilise la normale actuelle comme normale sur l'arrête
          t_Ni(ncot) = N;
          // et pour les variations, celle de N
          for (int ia=1;ia<= 3;ia++)
           { // indice de B: jnB
             int  jnB = (indi(ncot+1)-1)*3+ia;
             d_t_Ni(jnB)(ncot) = dN(jnB);
             // indice de C: jnC
             int jnC = (indi(ncot+2)-1)*3+ia;
             d_t_Ni(jnC)(ncot) = dN(jnC);
             // indice de D: jnD
             int jnD = (indi(ncot)-1)*3+ia;
             d_t_Ni(jnD)(ncot) = dN(jnD);
           }; // fin du for sur ia
          // concernant les variations des coordonnées des positions des normales,
          // ces variations sont nulles, on n'y touche pas
         };
      }; //-- fin de la boucle sur les trois cotés
      
	 
     // calcul des coefficients des fonctions d'interpolation
     double s= theta1_H1 * theta2_H2 - theta1_H3 * theta2_H2 + theta2_H1 * theta1_H3;
     double a_r1= theta2_H2 / s; double b_r1 = theta1_H3 / s; double c_r1 = -theta1_H3 * theta2_H2/s;
     double a_r2= -theta2_H1 / s; double b_r2 = 1./theta2_H2 - theta1_H3 * theta2_H1 /theta2_H2/ s; 
                                               double c_r2 = -theta1_H3 * theta2_H1/s;
     double a_r3= 1./theta1_H3 - theta1_H1 * theta2_H2 /theta1_H3/ s; double b_r3 = - theta1_H1 / s; 
                                               double c_r3 = theta2_H2 * theta1_H1 /s;
     // calcul de la variation de la normale
     Coordonnee3 d_N_1= t_Ni(1) * a_r1 + t_Ni(2) * a_r2 + t_Ni(3) * a_r3 ;
     Coordonnee3 d_N_2= t_Ni(1) * b_r1 + t_Ni(2) * b_r2 + t_Ni(3) * b_r3 ;
     // calcul de la courbure (non symétrique)
     curb.Coor(1,1) = - d_N_1 * aiB.Coordo(1); curb.Coor(1,2) = - d_N_1 * aiB.Coordo(2);
     curb.Coor(2,1) = - d_N_2 * aiB.Coordo(1); curb.Coor(2,2) = - d_N_2 * aiB.Coordo(2);
     // retour de la courbure

     double unsurs = 1./s; double unsurs2=unsurs * unsurs ;
     for (int ddl=1;ddl<=nbddl;ddl++)
      { // tout d'abord le calcul de la variation des coeff des fonctions d'interpolation
        double d_s = d_theta1_H1(ddl) * theta2_H2 + theta1_H1 * d_theta2_H2(ddl)
                   - d_theta1_H3(ddl) * theta2_H2 - theta1_H3 * d_theta2_H2(ddl)
                   + d_theta2_H1(ddl) * theta1_H3 + theta2_H1 * d_theta1_H3(ddl);
        double d_a_r1 = d_theta2_H2(ddl) * unsurs - theta2_H2 * d_s * unsurs2; 
        double d_b_r1 = d_theta1_H3(ddl) * unsurs - theta1_H3 * d_s * unsurs2; 
        double d_a_r2 = -d_theta2_H1(ddl) * unsurs + theta2_H1 * d_s * unsurs2; 
        double d_b_r2 = - d_theta2_H2(ddl)/theta2_H2/theta2_H2 
                        - d_theta1_H3(ddl) * theta2_H1 /theta2_H2* unsurs 
                        - theta1_H3 * d_theta2_H1(ddl) /theta2_H2* unsurs
                        + theta1_H3 * theta2_H1 * d_theta2_H2(ddl)/theta2_H2/theta2_H2 * unsurs 
                        + theta1_H3 * theta2_H1 * d_s /theta2_H2 * unsurs2; 
        double d_a_r3 = -d_theta1_H3(ddl)/theta1_H3/theta1_H3 
                        - d_theta1_H1(ddl) * theta2_H2 /theta1_H3* unsurs 
                        - theta1_H1 * d_theta2_H2(ddl) /theta1_H3* unsurs
                        + theta1_H1 * theta2_H2 * d_theta1_H3(ddl)/theta1_H3/theta1_H3 * unsurs 
                        + theta1_H1 * theta2_H2 * d_s/theta1_H3 * unsurs2; 
        double d_b_r3 = - d_theta1_H1(ddl) * unsurs  + theta1_H1 * d_s * unsurs2; 
        // calcul de la variation de la normale
        Coordonnee3 d_d_N_1=  d_t_Ni(ddl)(1) * a_r1 + t_Ni(1) * d_a_r1
                            + d_t_Ni(ddl)(2) * a_r2 + t_Ni(2) * d_a_r2 
                            + d_t_Ni(ddl)(3) * a_r3 + t_Ni(3) * d_a_r3;
        Coordonnee3 d_d_N_2=  d_t_Ni(ddl)(1) * b_r1 + t_Ni(1) * d_b_r1 
                            + d_t_Ni(ddl)(2) * b_r2 + t_Ni(2) * d_b_r2
                            + d_t_Ni(ddl)(3) * b_r3 + t_Ni(3) * d_b_r3;
        // variation de la courbure
        Tenseur_ns2BB& dcur = dcurb(ddl);
        dcur.Coor(1,1) = - (d_d_N_1 * aiB.Coordo(1)+ d_N_1 * DaiB(ddl).Coordo(1));
        dcur.Coor(1,2) = - (d_d_N_1 * aiB.Coordo(2)- d_N_1 * DaiB(ddl).Coordo(2));
        dcur.Coor(2,1) = - (d_d_N_2 * aiB.Coordo(1)- d_N_2 * DaiB(ddl).Coordo(2));
        dcur.Coor(2,2) = - (d_d_N_2 * aiB.Coordo(2)- d_N_2 * DaiB(ddl).Coordo(1));
      }; 

   };

