// 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 "ElemThermi.h"
#include <iomanip>
#include "ConstMath.h"
#include "Util.h"
#include "Coordonnee2.h"
#include "Coordonnee3.h"
#include "TypeConsTens.h"
#include "TypeQuelconqueParticulier.h"

        
// retourne la liste de tous les  types de ddl interne actuellement utilisés
// par l'élément (actif ou non), sont exclu de cette liste les ddl des noeuds
// reliés à l'élément (ddl implique grandeur uniquement scalaire !)
List_io <Ddl_enum_etendu> ElemThermi::Les_type_de_ddl_internes(bool) const
   { List_io <Ddl_enum_etendu> ret;
     switch (ParaGlob::Dimension())
     { case 1 :
        {ret.push_back(TEMP); ret.push_back(FLUXD1);
         ret.push_back(GRADT1); ret.push_back(DGRADT1);
//         ret.push_back(string("Green-Lagrange11"));ret.push_back(string("Almansi11"));ret.push_back(string("logarithmique11"));
         break;
         }
       case 2 :
        {ret.push_back(TEMP); ret.push_back(FLUXD1);ret.push_back(FLUXD2);
         ret.push_back(GRADT1); ret.push_back(GRADT2);
         ret.push_back(DGRADT1); ret.push_back(DGRADT2);
//         ret.push_back(EPS22); ret.push_back(EPS12);
         break;
         }
       case 3 :
        {ret.push_back(TEMP);
         ret.push_back(FLUXD1);ret.push_back(FLUXD2);ret.push_back(FLUXD3);
         ret.push_back(GRADT1); ret.push_back(GRADT2); ret.push_back(GRADT3);
         ret.push_back(DGRADT1); ret.push_back(DGRADT2);
//         ret.push_back(string("Green-Lagrange11")); ret.push_back(string("Green-Lagrange22"));
         break;
         }
      };
    // cas des invariants
//    tab_Dee(107).nom = "norme_gradT"     ;tab_Dee(107).enu = GRADT1;tab_Dee(107).posi_nom = nbenumddl + 107;
//    tab_Dee(108).nom = "norme_DgradT"     ;tab_Dee(108).enu = DGRADT1;tab_Dee(108).posi_nom = nbenumddl + 108;
//    tab_Dee(109).nom = "norme_dens_flux"     ;tab_Dee(109).enu = FLUXD1;tab_Dee(109).posi_nom = nbenumddl + 109;
    
    ret.push_back(string("norme_gradT"));
    ret.push_back(string("norme_DgradT"));
    ret.push_back(string("norme_dens_flux"));
    // cas de l'existence de l'erreur
    if (fluxErreur != NULL)  ret.push_back(ERREUR);
//    // cas des énergies locales
//    ret.push_back(string("energie_elastique"));
//    ret.push_back(string("dissipation_plastique"));
//    ret.push_back(string("dissipation_visqueuse"));
    // cas des coordonnées du points
    switch (ParaGlob::Dimension())
      {case 3: ret.push_back(X3);
       case 2: ret.push_back(X2);
       case 1: ret.push_back(X1);
       };
    // retour
    return ret;   
   };

// retourne la liste abondée de tous les  données particulières interne actuellement utilisés
// par l'élément (actif ou non), sont exclu de cette liste les données particulières des noeuds
// reliés à l'élément
List_io <TypeQuelconque> ElemThermi::Les_types_particuliers_internes(bool absolue) const
  { List_io <TypeQuelconque> ret;
    // on s'intéresse au information stockée au niveau des points d'intégration
    // 1° récupéreration les grandeurs 
    //    a) cas des grandeurs liées à la déformation
    def->ListeGrandeurs_particulieres(absolue,ret);
    //    b) cas des grandeurs liées à la loi de comportement mécanique 
    loiTP->ListeGrandeurs_particulieres(absolue,ret);
    //    c) cas des grandeurs liées à la loi de comportement thermo-physique 
    if (loiComp != NULL) loiComp->ListeGrandeurs_particulieres(absolue,ret);
    //    d) cas des infos stockés aux points d'intégration, donc par l'élément
    Grandeur_scalaire_double grand_courant; // def d'une grandeur courante 
    // def d'un type quelconque représentatif à chaque grandeur
    // a priori ces grandeurs sont défini aux points d'intégration 
    //    e) cas des infos stockés à l'élément
    //  $$$ cas du volume total : 
    TypeQuelconque typQ3(VOLUME_ELEMENT,SIG11,grand_courant);
    ret.push_back(typQ3);

    //    f) cas des infos calculable à la demande sur l'élément
    //  $$$ cas des volumes entre les plans et l'élément dans le cas ou l'élément des de surface
    //      et que le calcul est 3D :
    if ((ParaGlob::Dimension()==3)&&(Type_geom_generique(id_geom)==SURFACE))
    {Grandeur_coordonnee grandCoordonnee(3); // un type courant 
       TypeQuelconque typQ4(VOL_ELEM_AVEC_PLAN_REF,SIG11,grandCoordonnee);
       ret.push_back(typQ4);
     };
    // liberation des tenseurs intermediaires
    LibereTenseur(); 
    return ret;
    }; 
     
// retourne la liste des grandeurs évoluées interne actuellement utilisés
// par l'élément, c'est-à-dire directement sous forme de vecteur, tenseurs ....		 
List_io <TypeQuelconque> ElemThermi::Les_type_evolues_internes(bool absolue) const
  { List_io <TypeQuelconque> liTQ;
    // def des grandeurs courantes de type coordonnee
   {Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
    // maintenant on définit une grandeur typique de type Grandeur_coordonnee
    Grandeur_coordonnee gt(coor); 
    // def d'un type quelconque représentatif  pour chaque grandeur
    {TypeQuelconque typQ(FLUXD,FLUXD1,gt);liTQ.push_back(typQ);};
    {TypeQuelconque typQ(GRADT,GRADT1,gt);liTQ.push_back(typQ);};
    {TypeQuelconque typQ(DGRADT,DGRADT1,gt);liTQ.push_back(typQ);};
    // pour la position il s'agit de la position du point d'intégration
    {TypeQuelconque typQ(POSITION_GEOMETRIQUE,FLUXD1,gt);liTQ.push_back(typQ);};
    };
   
    // retour
    return liTQ;   
   };
        
// récupération de grandeurs particulières au numéro d'ordre  = iteg  
// celles-ci peuvent être quelconques
// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
void ElemThermi::Grandeur_particuliere (bool absolue,List_io<TypeQuelconque>& liTQ,int iteg)
   { // on s'intéresse au information stockée au niveau des points d'intégration
     // pour tenir compte du fait qu'il peut y avoir plusieurs fois la même information, ces dernières sont systématiquement
     // stockées dans des tableaux, et on associe à ce tableau un indice qui indique aux méthodes appelées, à quel endroit
     // elles doivent écrire les infos. les indices sont stockés dans une liste de même dim que liTQ
     list <int> decal(liTQ.size(),0.);  // on initi tous les membres à 0

     // 1° on commence par récupérer les grandeurs 
     //    a) cas des grandeurs liées à la déformation
     // met à jour les données spécifiques du point considéré
     def->Mise_a_jour_data_specif(tabSaveDefDon(iteg));		
     def->Grandeur_particuliere(absolue,liTQ);
     //    b) cas des grandeurs liées à la loi de comportement thermo-physique 
     loiComp->Grandeur_particuliere(absolue,liTQ,tabSaveDon(iteg),decal);
// pour le débug ----
//cout << "\n debug ElemThermi::Grandeur_particuliere  " <<  liTQ << endl; // débug
// fin pour le débug ----     
     //    c) cas des grandeurs liées à la loi de comportement thermo-physique 
     if (loiTP != NULL) loiTP->Grandeur_particuliere(absolue,liTQ,tabSaveTP(iteg),decal);
     // 2° on change éventuellement de repère (local en global) si nécessaire
     //    a) définition des grandeurs qui sont indépendante de la boucle qui suit
     def->ChangeNumInteg(iteg);  // on change le numéro de point d'intégration courant
     // dimension des vecteurs de base de la métrique
     int dim = met->Dim_vec_base();
     // calcul des matrices de passages
     // calcul des matrices de passages
     Mat_pleine* gamma0=NULL; Mat_pleine* gammat=NULL; Mat_pleine* gammatdt=NULL;
     Mat_pleine* beta0=NULL; Mat_pleine* betat=NULL; Mat_pleine* betatdt=NULL;
     List_io<TypeQuelconque>::iterator il,ilfin = liTQ.end();
     for (il=liTQ.begin();il!=ilfin;il++)
      { TypeQuelconque& tipParticu = (*il); // pour simplifier
        // n'intervient que si la grandeur est active: 
        if ((*il).Activite())
        { // on regarde si c'est une grandeur locale ou pas 
          if (tipParticu.TypeExpressionGrandeur()==0)
            // cas d'une grandeur exprimée dans le repère locale, changement de repère
            { // calcul des matrices de passages, au premier passage
              if (gamma0 == NULL)
               { gamma0 = new Mat_pleine(dim,dim); gammat = new Mat_pleine(dim,dim);gammatdt= new Mat_pleine(dim,dim);
                 const Met_abstraite::Info0_t_tdt& ex = def->Remont0_t_tdt(absolue,*gamma0,*gammat,*gammatdt);
                 beta0 = new Mat_pleine(gamma0->Inverse().Transpose());
                 betat = new Mat_pleine(gammat->Inverse().Transpose());
                 betatdt = new Mat_pleine(gammatdt->Inverse().Transpose());
               };
              tipParticu.Change_repere(*beta0,*betat,*betatdt,*gamma0,*gammat,*gammatdt);
            };
          // on utilise la boucle également pour mettre à jour les grandeurs particulières liés à l'élément  
            
          // 1) -----cas du module de compressibilité ou de cisaillement totale
          switch (tipParticu.EnuTypeQuelconque().EnumTQ())
            {//    e) cas des infos stockés à l'élément
             case  VOLUME_ELEMENT:
              { *((Grandeur_scalaire_double*) tipParticu.Grandeur_pointee())=volume;break;}
             //    d) cas des infos calculable à la demande sur l'élément
             case VOL_ELEM_AVEC_PLAN_REF:
              { *((Grandeur_coordonnee*) tipParticu.Grandeur_pointee())=VolumePlan();break;}
             default: break; // sinon rien
            };
        };

       };
      // suppression des bases de passages
      if (gamma0 != NULL)
       {delete gamma0; delete gammat; delete gammatdt; delete beta0; delete betat; delete betatdt;};
      // liberation des tenseurs intermediaires
      LibereTenseur();   
    };                             	
// retourne la liste de toutes les  grandeurs quelconques relatives aux faces de
// l'élément (actif ou non),
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
List_io <TypeQuelconque> ElemThermi::Les_type_quelconque_de_face(bool absolue) const
   {  cout << "\n **** méthode  non implantée **** "
           << "\n List_io <TypeQuelconque> ElemThermi::Les_type_quelconque_de_face(.... "
           << flush;
      Sortie(1);
   };
   
// retourne la liste de toutes les  grandeurs quelconques relatives aux arêtes de
// l'élément (actif ou non),
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
List_io <TypeQuelconque> ElemThermi::Les_type_quelconque_de_arete(bool absolue) const
{  cout << "\n **** méthode  non implantée **** "
        << "\n List_io <TypeQuelconque> ElemThermi::Les_type_quelconque_de_arete(.... "
        << flush;
   Sortie(1);
};
                         
// récupération de grandeurs particulières pour une face au numéro d'ordre  = iteg
// celles-ci peuvent être quelconques
// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
void ElemThermi::Grandeur_particuliere_face(bool absolue,List_io<TypeQuelconque>& liTQ,int face, int iteg)
{  cout << "\n **** méthode  non implantée **** "
        << "\n List_io <TypeQuelconque> ElemThermi::Grandeur_particuliere_face(.... "
        << flush;
   Sortie(1);
};

// récupération de grandeurs particulières pour une arête au numéro d'ordre  = iteg
// celles-ci peuvent être quelconques
// en retour liTQ est modifié et contiend les infos sur les grandeurs particulières
// absolue: indique si oui ou non on sort les tenseurs dans la base absolue ou une base particulière
void ElemThermi::Grandeur_particuliere_arete(bool absolue,List_io<TypeQuelconque>& liTQ,int arete, int iteg)
{  cout << "\n **** méthode  non implantée **** "
        << "\n List_io <TypeQuelconque> ElemThermi::Grandeur_particuliere_arete(.... "
        << flush;
   Sortie(1);
};

// --- transfert des grandeurs des points d'intégration aux noeuds 
// transfert de ddl des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, on ne remplace pas)
// les ddl doivent déjà exister aux noeuds sinon erreur
// il doit s'agir du même type de répartition de pt d'integ pour toutes les grandeurs
// tab_val(i)(j) : valeur associée au i ième pt d'integ et au j ième ddl_enum_etendu
void ElemThermi::TransfertAjoutAuNoeuds(const List_io < Ddl_enum_etendu >& lietendu
                                     ,const Tableau <Tableau <double> > & tab_val,int cas) 
{List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end();
 // on récupère l'élément géométrique associé au ddl pur du premier ddl étendu,
 ili = lietendu.begin();
 Enum_ddl enu = (*ili).Enum();
 const ElemGeomC0& elemgeom = ElementGeometrie(enu);
 // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément
 // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers
 // du tableau des noeuds
 int nbn = elemgeom.Nbne();
 
 int indice = 1;
 for (ili = lietendu.begin();ili!=ilifin;ili++,indice++)
  { // récupération des tableaux d'indiçage pour le calcul aux noeuds
    const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas);
    // calcul des valeurs aux noeuds
    // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) }
	   for (int ine=1;ine<=nbn;ine++)
     { Ddl_etendu& de = tab_noeud(ine)->ModifDdl_etendu(*ili);
       Tableau <int>& indir = contExtra.indir(ine); // pour simplifier
       int nbindir = indir.Taille();
       for (int j=1; j<= nbindir; j++)
           de.Valeur() += contExtra.tab(ine)(indir(j)) * tab_val(indir(j))(indice);
     };
  };
};

// transfert de type quelconque des points d'intégrations (de tous) aux noeuds d'un éléments (on ajoute aux noeuds, 
// on ne remplace pas). Les types quelconques doivent déjà exister.
// un tableau tab_liQ  correspondent aux grandeurs quelconque pour tous les pt integ. tab_liQ(i) est associé au pt d'integ i
// Toutes les listes sont identiques au niveau des descripteurs (types...) ce sont uniquement les valeurs numériques
// c-a-dire les valeurs associées à TypeQuelconque::Grandeur qui sont différentes (elles sont associées à chaque pt d'integ)
// liQ_travail: est une liste de travail qui sera utilisée dans le transfert                        
void ElemThermi::TransfertAjoutAuNoeuds(const Tableau <List_io < TypeQuelconque > >& tab_liQ
                                     ,List_io < TypeQuelconque > & liQ_travail,int cas)	  
{int nb_pt_integ = lesPtIntegThermiInterne->NbPti();
// ---- modif transitoire pour la sortie des coques !!!!
 // on s'occupe uniquement de la première couche d'élément
 if ((this->PoutrePlaqueCoque() == COQUE)||(this->PoutrePlaqueCoque() == PLAQUE))
   nb_pt_integ = this->NbPtIntegSurface(FLUXD1); // SIG11 arbitraire car c'est les pt d'integ classique


//------- fin modif transitoire --------
 if (tab_liQ.Taille() == 0)
    return; // cas où on n'a rien à faire
 #ifdef MISE_AU_POINT
    if (nb_pt_integ != tab_liQ.Taille())
      { cout << "\n erreur de dimension, la taille de tab_liQ= " << tab_liQ.Taille() << " n'est pas egale "
             << " au nombre de pt_d'integ de l'element : " << nb_pt_integ ;
        cout << "\n ElemThermi::TransfertAjoutAuNoeuds(... " << endl;
        Sortie(1);
      }  
 #endif
//---- pour le debug
//cout << " \n debug ElemThermi::TransfertAjoutAuNoeuds " << tab_liQ << endl;
//--- fin pour le debug 
 // sinon on a au moins un élément, on récupère la 1ère liste qui nous servira pour les descripteurs
 List_io <TypeQuelconque > & liQ_ref = tab_liQ(1); // pour simplifier
 List_io < TypeQuelconque >::const_iterator ili_ref,ilifin_ref=liQ_ref.end();
 // la liste de travail
 List_io < TypeQuelconque >::iterator ili_travail = liQ_travail.begin();
 // on définit un tableau d'itérator de dimension = le nb de pt d'integ
 static Tableau < List_io < TypeQuelconque >::const_iterator > tab_iterator;
 // on le redimentionne si besoin est
 tab_iterator.Change_taille(nb_pt_integ);
 // on définit ses éléments
 for (int ia=1;ia<=nb_pt_integ;ia++)
   tab_iterator(ia) = tab_liQ(ia).begin();
 // on boucle sur les éléments de la liste de référence
 for (ili_ref = liQ_ref.begin();ili_ref != ilifin_ref;ili_ref++,ili_travail++)
   { // on récupère l'élément géométrique associé au ddl pur dont les valeurs sont calculées aux mêmes
     // endroits que la grandeur quelconque
     Enum_ddl enu = (*ili_ref). Enum();
     const ElemGeomC0& elemgeom = ElementGeometrie(enu);
     // on récupère le nombre de noeud de l'élément géométrique (qui peut-être différent de celui de l'élément
     // par ex: element sfe, donc on utilise les noeuds de l'élément géom. On considère que ce sont les premiers
     // du tableau des noeuds
     int nbn = elemgeom.Nbne();
     // récupération des tableaux d'indiçage pour le calcul aux noeuds
     const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas);
     // on boucle sur les noeuds, ceci est due à la technique utilisée pour accumuler dans les conteneurs du noeud
     for (int ine=1;ine<=nbn;ine++)
        {TypeQuelconque& tq = tab_noeud(ine)->ModifGrandeur_quelconque((*ili_ref).EnuTypeQuelconque());
         TypeQuelconque::Grandeur & grandeur_au_noeud = *(tq.Grandeur_pointee());
	     // on récupère une grandeur du même type que les grandeurs à manipuler, ceci pour accumuler
	     TypeQuelconque::Grandeur & stockage_inter = *((*ili_travail).Grandeur_pointee());
         // calcul des valeurs aux noeuds
         // val_au_noeud(i) = somme_(de j=indir(i)(1) à indir(i)(taille(indice(i)) )) {tab(i)(j) * val_pt_integ(j) }
         Tableau <int>& indir = contExtra.indir(ine); // pour simplifier
         int nbindir = indir.Taille();
         for (int j=1; j<= nbindir; j++)
       	  { stockage_inter *= 0.; // met à 0 la grandeur inter
       	    // tab_iterator(j) pointe sur la grandeur quelconque du point d'intégration voulu 
       	    stockage_inter = *((*(tab_iterator(indir(j)))).Const_Grandeur_pointee()); // récup de la grandeur pointée
       	    stockage_inter *= contExtra.tab(ine)(indir(j)); // * par le coeff
       	    grandeur_au_noeud += stockage_inter; // stockage dans le noeud	
       	  };
       };
     // on incrémente les itérators de points d'intégration
     for (int ib=1;ib<=nb_pt_integ;ib++)
         (tab_iterator(ib))++;
       	};
};
	     
 
// accumulation aux noeuds de grandeurs venant des éléments vers leurs noeuds (exemple la pression appliquée)
// autres que celles aux pti classiques, mais directements disponibles
// le contenu du conteneur stockées dans liQ est utilisé en variable intermédiaire
void ElemThermi::Accumul_aux_noeuds(const List_io < Ddl_enum_etendu >& lietendu
                                    ,List_io < TypeQuelconque > & liQ,int cas)
{// ... cas des ddl étendu ...
 {List_io < Ddl_enum_etendu >::const_iterator ili,ilifin = lietendu.end();
  ili = lietendu.begin();
//  for (ili = lietendu.begin();ili!=ilifin;ili++)
//   {// on traite en fonctions des cas particuliers
////debug
////cout << "\n debug ElemMeca::Accumul_aux_noeuds"
////     << " *ili = " << *ili << endl;
//// fin debug
//   
//    switch ((*ili).Position()-NbEnum_ddl())
//     { case 94 : // cas des pressions externes 
//        {if (lesChargeExtSurEle != NULL)
//          if (lesChargeExtSurEle->LesPressionsExternes() != NULL) // cas où il existe des pressions sauvegardées
//           { Tableau <Tableau <Pression_appliquee> >& lesPressionsExternes = *lesChargeExtSurEle->LesPressionsExternes();
//             int nb_face = lesPressionsExternes.Taille();
//             for (int n_face=1;n_face<=nb_face;n_face++) // on boucle sur les faces
//              if (lesPressionsExternes(n_face).Taille() != 0)
//              { Tableau <Pression_appliquee>& tab_press_appliquee = (lesPressionsExternes(n_face)); // pour simplifier
//                int t_tail = tab_press_appliquee.Taille();
//                if (t_tail != 0) // cas où on a une face chargée
//                  { // on récupère l'élément frontière associée (on considère qu'il y en a forcément 1)
//                    int num_face = n_face; // init par défaut
//                    if(ParaGlob::AxiSymetrie())  // dans le cas d'éléments axysymétriques, les faces
//                      {num_face += posi_tab_front_lin;}; // sont en faites les frontières lignes
//                    const ElemGeomC0 & elemgeom = tabb(num_face)->ElementGeometrique();
//                    int nbn = elemgeom.Nbne();
//                    const ElemGeomC0::ConteneurExtrapolation & contExtra = elemgeom.ExtrapolationNoeud(cas);
//                    Tableau <Noeud *>& tab_noe = tabb(num_face)->TabNoeud(); // récup du tableau de noeuds de la frontière
//                    for (int ine=1;ine<=nbn;ine++)
//                      { Ddl_etendu& de = tab_noe(ine)->ModifDdl_etendu(*ili);
//                        Tableau <int>& indir = contExtra.indir(ine); // pour simplifier
//                        int nbindir = indir.Taille();
//                        for (int j=1; j<= nbindir; j++)
//{                           de.Valeur() += contExtra.tab(ine)(indir(j)) * tab_press_appliquee(indir(j)).press;
////debug
////cout << "\n debug ElemMeca::Accumul_aux_noeuds"
////     << " de.Valeur() = " << de.Valeur() << endl;
//// fin debug
//}                      };
//                  };
//              };
//           };
//          break;
//        }
//       default :
//         break;
//        // sinon on ne fait rien, cela signifie que ce n'est pas un ddl géré par l'élément
//     };
//   };
 };

 // ... cas des grandeurs quelconque ...
 // on traite d'abord le cas où on n'a rien à faire
 if (liQ.size() == 0)
    return; 
//---- pour le debug
//cout << " \n debug ElemMeca::TransfertAjoutAuNoeuds " << tab_liQ << endl;
//--- fin pour le debug 
 {List_io < TypeQuelconque >::const_iterator ili,ilifin=liQ.end();
  
  // on boucle sur les grandeurs de la liste 
  for (ili = liQ.begin();ili != ilifin;ili++)
   { // on récupère l'énuméré
     TypeQuelconque_enum_etendu enutq = (*ili).EnuTypeQuelconque();
     switch (enutq.EnumTQ())
      { //        case VECT_REAC:
//         // là on ne fait rien car la grandeur est directement à construire via les noeuds
//         // et ceci est fait dans la routine:
//         // lesMaillages->PassageInterneDansNoeud_composantes_vers_vectorielles()
//         break;

       default:
     // VECT_PRESSION pour l'instant il n'y a aucune grandeur a priori qui est disponible directement
     // donc message d'erreur
        cout << "\n cas de grandeur actuellement non traité "
             << "\n pas de grandeur " << ((*ili).EnuTypeQuelconque().NomPlein()) << "  dans l'element "
             << "\n ou cas non implante pour l'instant"
             << "\n ElemMeca::Accumul_aux_noeuds(....";
      };
   };
  };
};

	     
// procedure permettant de completer l'element, en ce qui concerne les variables gérés
// par ElemThermi, apres sa creation avec les donnees du bloc transmis
// peut etre appeler plusieurs fois
Element* ElemThermi::Complete_ElemThermi(BlocGen & bloc,LesFonctions_nD*  lesFonctionsnD)
    { // cas de la masse volumique
      if (bloc.Nom(1) == "masse_volumique")
       { masse_volumique = bloc.Val(1);
         return this;
        }
      // cas de données thermique   
      else if (bloc.Nom(1) == "dilatation_thermique")
       { if (bloc.Val(1) == 1.) {dilatation=true;} else {dilatation = false;};
         return this;
        }
      // cas de la définition d'une intégrale sur le volume
      // on prévoit une intégrale via les pti, on utilise donc le ddl EPS11 pour la position
      else if (bloc.Nom(1) == "integrale_sur_volume_")
       { if (bloc.Nom(2) == "un_ddl_etendu_")
           { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3)
             Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc
             Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc
             TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant);
             if (integ_vol_typeQuel == NULL)
                {integ_vol_typeQuel = new Tableau <TypeQuelconque>(1);
                 (*integ_vol_typeQuel)(1) = typQ;
                 index_Integ_vol_typeQuel = new Tableau <int>(1);
                 (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1);
                }
             else {int taille = integ_vol_typeQuel->Taille()+1;
                   integ_vol_typeQuel->Change_taille(taille);
                   (*integ_vol_typeQuel)(taille) = typQ;
                   index_Integ_vol_typeQuel->Change_taille(taille);
                   (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1);
                  };
           }
         else if (bloc.Nom(2) == "une_fonction_nD_")
           { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3)
             // on récupère le pointeur de fonction correspondant:
             Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3));
             Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),1,fct);// par défaut une taille de 1
             TypeQuelconque typQ(INTEG_SUR_VOLUME,EPS11,grand_courant);
             if (integ_vol_typeQuel == NULL)
               { integ_vol_typeQuel = new Tableau <TypeQuelconque>(1);
                 (*integ_vol_typeQuel)(1) = typQ;
                 index_Integ_vol_typeQuel = new Tableau <int>(1);
                 (*index_Integ_vol_typeQuel)(1) = (int) bloc.Val(1);
               }
             else {int taille = integ_vol_typeQuel->Taille()+1;
                   integ_vol_typeQuel->Change_taille(taille);
                   (*integ_vol_typeQuel)(taille) = typQ;
                   index_Integ_vol_typeQuel->Change_taille(taille);
                   (*index_Integ_vol_typeQuel)(taille) = (int) bloc.Val(1);
                  };
           };
         return this;
       }
     
      // cas de la définition d'une intégrale sur le volume et le temps
      else if (bloc.Nom(1) == "integrale_sur_vol_et_temps_")
        { if (bloc.Nom(2) == "un_ddl_etendu_")
           { // il s'agit d'une intégrale d'un ddl étendu de nom: bloc.Nom(3)
             Ddl_etendu ddl(Ddl_enum_etendu(bloc.Nom(3))) ;// on crée un ddl ad hoc
             Grandeur_Ddl_etendu grand_courant(ddl,bloc.Nom(4));// le conteneur ad hoc
             TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant);
             if (integ_vol_t_typeQuel == NULL)
                {integ_vol_t_typeQuel = new Tableau <TypeQuelconque>(1);
                 (*integ_vol_t_typeQuel)(1) = typQ;
                 index_Integ_vol_t_typeQuel = new Tableau <int>(1);
                 (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1);
                }
             else {int taille = integ_vol_t_typeQuel->Taille()+1;
                   integ_vol_t_typeQuel->Change_taille(taille);
                   (*integ_vol_t_typeQuel)(taille) = typQ;
                   index_Integ_vol_t_typeQuel->Change_taille(taille);
                   (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1);
                  };
           }
         else if (bloc.Nom(2) == "une_fonction_nD_")
           { // il s'agit d'une intégrale d'une fonction nD de nom: bloc.Nom(3)
             // on récupère le pointeur de fonction correspondant:
             Fonction_nD * fct = lesFonctionsnD->Trouve(bloc.Nom(3));
             Grandeur_Vecteur_Nommer grand_courant(bloc.Nom(3),1,fct);// par défaut une taille de 1
             TypeQuelconque typQ(INTEG_SUR_VOLUME_ET_TEMPS,EPS11,grand_courant);
             if (integ_vol_t_typeQuel == NULL)
                {integ_vol_t_typeQuel = new Tableau <TypeQuelconque>(1);
                 (*integ_vol_t_typeQuel)(1) = typQ;
                 index_Integ_vol_t_typeQuel = new Tableau <int>(1);
                 (*index_Integ_vol_t_typeQuel)(1) = (int) bloc.Val(1);
                }
             else {int taille = integ_vol_t_typeQuel->Taille()+1;
                   integ_vol_t_typeQuel->Change_taille(taille);
                   (*integ_vol_t_typeQuel)(taille) = typQ;
                   index_Integ_vol_t_typeQuel->Change_taille(taille);
                   (*index_Integ_vol_t_typeQuel)(taille) = (int) bloc.Val(1);
                  };
           };
         return this;
       }
      // sinon rien
       else  
        { return NULL;};
    };       

    
// récupération de la base locales au noeud noe, pour le temps: temps 
const BaseB & ElemThermi::Gib_elemeca(Enum_dure temps, const Noeud * noe)
   { int nb_noeud = tab_noeud.Taille(); // nombre de noeud de l'élément local
     // on fait une rotation sur les noeuds de l'élément 
     int num=1;
     for (num=1;num<= nb_noeud;num++)
       { if (noe == tab_noeud(num)) break; }
     // récupération des coordonnées locales du noeud
     ElemGeomC0& elem_geom = ElementGeometrique(); // recup de l'élément géométrique correspondant
     // récup de la référence des coordonnées locales du noeud num
     const Coordonnee & coo = elem_geom.PtelemRef()(num);
     // calcul de la dérivée des fonctions au point
     const Mat_pleine& ddphi = elem_geom.Dphi_point(coo);
     const Vecteur& pphi = elem_geom.Phi_point(coo);
     // en fonction du temps on calcul la base naturelle
     switch (temps)
      { case  TEMPS_0: return (met->BaseNat_0(tab_noeud,ddphi,pphi)); break;
        case  TEMPS_t: return (met->BaseNat_t(tab_noeud,ddphi,pphi)); break;
        case  TEMPS_tdt: return (met->BaseNat_tdt(tab_noeud,ddphi,pphi)); break;
       };
     // pour faire taire le compilateur
     cout << "\n erreur, on ne devrait jamais passer ici"
          << "\n ElemThermi::Gib_elemeca(...";
     Sortie(1);
     BaseB *toto = new BaseB(0);
     return (*toto);       
   };
   
// calcul du mini du module d'young équivalent pour tous les points d'intégrations
double ElemThermi::Calcul_mini_E_qui(Enum_dure temps)
 { double mini = 0.; // init
   int ni;
   for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
     { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni));
       double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni));
       if (E_equi < mini) mini = E_equi;
      }
   return mini;   
   };    
   
// calcul du  maxi du module d'young équivalent pour tous les points d'intégrations
double  ElemThermi::Calcul_maxi_E_qui(Enum_dure temps)
 { double maxi = 0.; // init
   int ni;
   for (def->PremierPtInteg(), ni = 1;def->DernierPtInteg();def->NevezPtInteg(),ni++)
     { def->ChangeNumInteg(ni);def->Mise_a_jour_data_specif(tabSaveDefDon(ni));
       double E_equi = loiComp->Module_young_equivalent(temps,*def,tabSaveDon(ni));
       if (E_equi > maxi) maxi = E_equi;
      }
   return maxi;   
   };    

	    
        // cas d'un chargement aero-hydrodynamique, sur les frontières de l'élément 
        // Il y a trois forces: une suivant la direction de la vitesse: de type traînée aerodynamique
        // Fn = poids_volu * fn(V) * S * (normale*u) * u, u étant le vecteur directeur de V (donc unitaire)
        // une suivant la direction normale à la vitesse de type portance
        // Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire, normal à V, et dans le plan n et V
        // une suivant la vitesse tangente de type frottement visqueux
        // T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
        // retourne  le second membre résultant
        // calcul à l'instant tdt ou t en fonction de la variable atdt
        // coef_mul: est un coefficient multiplicateur global (de tout)
Vecteur& ElemThermi::SM_charge_hydrodyn_E (const double& poidvol,const Tableau <Vecteur>& taphi,int nbne
                                         ,Courbe1D* frot_fluid,const Vecteur& poids
                                         ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul
                                         ,Courbe1D* coef_aero_t,const ParaAlgoControle & ,bool atdt)
   {  
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   




    // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
    // *** sinon c'est intractable et long
    // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants
    Vecteur* SM_r;
    int dime = ParaGlob::Dimension();
    bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
                                  // donc il faut calculer tous les éléments de la métrique
    switch (dime)
     {case 3: // cas de la dimension 3
      { // définition du vecteur de retour 
        Vecteur& SM = *((*res_extS)(numfront));SM_r=&SM;
        // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit) return SM;
        int ni; // compteur globale de point d'integration
        Deformation & defS = *defSurf(numfront); // pour simplifier l'écriture
        for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
         { // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
           // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
           Met_abstraite::Expli ex;
           if (atdt) {ex = (defS.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); }
           else      {ex = defS.Cal_explicit_t(premier_calcul); };
           // détermination de la normale à la surface qui  vaut le produit vectoriel des 2 premiers vecteurs
                   // conversion explicite en coordonnées sans variance
           Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_t)(1), (*ex.giB_t)(2));
 //          cout << "\n normale avant normalisation";
 //          normale.Affiche();
           normale.Normer(); // on norme la normale
  //         cout << "\n normale après normalisation";
  //         normale.Affiche(); Sortie(1);

           // récupération de la vitesse
           const Coordonnee* Vp;
           if (atdt) {Vp = &(defS.VitesseM_tdt());} 
           else      {Vp = &(defS.VitesseM_t());};
           const Coordonnee& V = *Vp; double nV = V.Norme(); 
           // dans le cas où la vitesse est trop faible, le résidu est nul
           if (nV < ConstMath::trespetit) return SM;           
           Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente
           double nVt = Vt.Norme(); // norme de la vitesse tangente
           if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente
           Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
           double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse
           Coordonnee w(3);
           if (coef_aero_t != NULL) 
             {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale));
              // si w est non nulle on le norme
              double norme_w = w.Norme();
              if (norme_w > ConstMath::trespetit) {w /= norme_w;};              
              };
           // calcul du résidu
           int ix=1; int dimf = 3;   // ne fonctionne qu'en dim 3  
           // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
           double coef_frot_fluid=0.;
           if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t);}; 
           // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
           double coef_n=0.;
           if (coef_aero_n != NULL) 
              { coef_n += poidvol * coef_aero_n->Valeur(nV) *  poids(ni) * (*ex.jacobien_t) * cos_directeur;}; 
           // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
           double coef_t=0.;
           if (coef_aero_t != NULL) 
              { coef_t += poidvol * coef_aero_t->Valeur(nV) *  poids(ni) * (*ex.jacobien_t) * cos_directeur;};
           for (int ne =1; ne<= nbne; ne++) 
             for (int i=1;i<= dimf;i++,ix++)
               { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));};
          } // fin boucle sur les points d'intégrations
        break;   
      }; // fin du cas de la dimension 3
      case 2: // cas de la dimension 2
      { // définition du vecteur de retour 
        Vecteur& SM = *((*res_extA)(numfront));SM_r=&SM;
        // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit) return SM;
        int ni; // compteur globale de point d'integration
        Deformation & defA = *defArete(numfront); // pour simplifier l'écriture
        for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
         { // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
           // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
           Met_abstraite::Expli ex;
           if (atdt) {ex = (defA.Cal_explicit_tdt(premier_calcul)).Tdt_dans_t(); }
           else      {ex = defA.Cal_explicit_t(premier_calcul); };
           // détermination de la normale à la surface qui  vaut le vecteur perpendiculaire au g1
           // dans le sens directe 
           Coordonnee normale;  normale(1) = - (*ex.giB_t)(1)(2); normale(2) = (*ex.giB_t)(1)(1);
           normale.Normer(); // on norme la normale
           // récupération de la vitesse
           const Coordonnee* Vp;
           if (atdt) {Vp = &(defA.VitesseM_tdt());} 
           else      {Vp = &(defA.VitesseM_t());};
           const Coordonnee& V = *Vp; double nV = V.Norme();
           // dans le cas où la vitesse est trop faible, le résidu est nul
           if (nV < ConstMath::trespetit) return SM;           
           Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente
           double nVt = Vt.Norme(); // norme de la vitesse tangente
           if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente
           Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
           double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse
           Coordonnee w(dime); // comme on est en 2D w ce calcul directement avec les composantes de u
           if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);};
           // calcul du résidu
           int ix=1;      
           // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
           double coef_frot_fluid=0.;
           if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_t);}; 
           // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
           double coef_n=0.;
           if (coef_aero_n != NULL) 
              { coef_n += poidvol * coef_aero_n->Valeur(nV) *  poids(ni) * (*ex.jacobien_t) * cos_directeur;}; 
           // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
           double coef_t=0.;
           if (coef_aero_t != NULL) 
              { coef_t += poidvol * coef_aero_t->Valeur(nV) *  poids(ni) * (*ex.jacobien_t) * cos_directeur;};
           for (int ne =1; ne<= nbne; ne++) 
             for (int i=1;i<= dime;i++,ix++)
               { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));};
          } // fin boucle sur les points d'intégrations
         } // fin boucle sur les points d'intégrations
        break;   
      case 1: // cas de la dimension 1
      { // définition du vecteur de retour 
        Vecteur& SM = *((*res_extN)(numfront));SM_r=&SM;
        // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit) return SM;
        // il n'y a pas plusieurs point d'intégration
        // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1
        Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;};
        // récupération de la vitesse
        const Coordonnee* Vp;
        Noeud* noe = (tabb(numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière
        if (atdt) {Vp = &(def->VitesseM_tdt(noe));}   // on utilise la déformation générale, qui convient pour un noeud
        else      {Vp = &(def->VitesseM_t(noe));};
        const Coordonnee& V = *Vp; double nV = V.Norme();
        // dans le cas où la vitesse est trop faible, le résidu est nul
        if (nV < ConstMath::trespetit) return SM;
        // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente)           
        Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
           double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse
        // calcul du résidu
        int ix=1; int dimf = dime;     
        // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
        double coef_n=0.; 
        if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1
              { coef_n += poidvol * coef_aero_n->Valeur(nV) *  poids(1) ;}; 
        for (int ne =1; ne<= nbne; ne++)  // il n'y qu'un point d'intégration le noeud lui-même
          for (int i=1;i<= dimf;i++,ix++)
               { SM(ix) += taphi(1)(ne) * coef_mul * ( coef_n * u(i) );}; 
        break;   
      }; // fin du cas de la dimension 1 */
      
    }; //-- fin du switch sur la dimension  
    // retour du second membre  
    return *SM_r;  
  };
    
       // idem SM_charge_hydrodyn_E mais  -> implicite, 
	   // pa: permet de déterminer si oui ou non on calcul la contribution à la raideur  
	   // retourne le second membre et la matrice de raideur correspondant
        // coef_mul: est un coefficient multiplicateur global (de tout)
Element::ResRaid ElemThermi::SM_charge_hydrodyn_I (const double& poidvol,const Tableau <Vecteur>& taphi,int nbne
                                         ,Courbe1D* frot_fluid,const Vecteur& poids,DdlElement & ddls
                                         ,Courbe1D* coef_aero_n,int numfront,const double& coef_mul
                                         ,Courbe1D* coef_aero_t,const ParaAlgoControle & pa)
   { 
   
   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
//****************** attention voir w non normé pour les dimensions 2 et 1 ****************   
   
    
    // *** dans l'ensemble du sp on utilise des vecteurs et on gére directement la variance
    // *** sinon c'est intractable et long
    // remarque: l'initialisation du résidu n'est pas fait ici, mais dans les routines appelants
    Element::ResRaid el;               
    int nbddl = ddls.NbDdl();
    bool avec_raid = pa.Var_charge_externe();  // controle
    int dime = ParaGlob::Dimension();
    bool premier_calcul=true; // contrairement à la déformation, pas de sauvegarde
                                  // donc il faut calculer tous les éléments de la métrique
    switch (dime)
     {case 3: // cas de la dimension 3
      { // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit)
        {  el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront);       
           return el;
         };
        Vecteur& SM = (*((*res_extS)(numfront)));  //  pour simplifier
        Mat_pleine & KM = (*((*raid_extS)(numfront))); //  "      "       "
        el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront); // pour le retour
        int ni; // compteur globale de point d'integration
        Deformation & defS = *defSurf(numfront); // pour simplifier l'écriture
        for (defS.PremierPtInteg(), ni = 1;defS.DernierPtInteg();defS.NevezPtInteg(),ni++)
         { // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
           // que pour un calcul primaire en implicit mais pour un calcul autre que mécanique
           const Met_abstraite::Impli& ex = defS.Cal_implicit(premier_calcul); 
           // détermination de la normale à la surface qui  vaut le produit vectoriel des 2 premiers vecteurs
           Coordonnee normale = Util::ProdVec_coorBN( (*ex.giB_tdt)(1), (*ex.giB_tdt)(2));
           normale.Normer(); // on norme la normale
           // récupération de la vitesse
           const Coordonnee V = defS.VitesseM_tdt(); double nV = V.Norme(); 
           // dans le cas où la vitesse est trop faible, le résidu est nul
           if (nV < ConstMath::trespetit) return el;           
           Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente
           double nVt = Vt.Norme(); // norme de la vitesse tangente
           if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente
           Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
           double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse
           Coordonnee w(3);double norme_w=0.;
			  Coordonnee vecNul(3); // un vecteur nul pour l'initialisation
           if (coef_aero_t != NULL) 
             {w = Util::ProdVec_coor(u,Util::ProdVec_coor( u, normale));
              // si w est non nulle on le norme
              norme_w = w.Norme();
              if (norme_w > ConstMath::trespetit) {w /= norme_w;};              
              };
           // calcul éventuel des variations
           static Tableau <Coordonnee> D_Vt,D_u,D_w,D_w_non_normer;
           static Tableau <double> D_coef_frot_fluid,D_coef_n,D_coef_t;
           if (avec_raid)
            { // calcul de la variation de la normale
              // 1) variation du produit vectoriel
              Tableau <Coordonnee > D_pasnormale = 
                  Util::VarProdVect_coor((*ex.giB_tdt)(1).Coor(),(*ex.giB_tdt)(2).Coor(),(*ex.d_giB_tdt));
              // 2) de la normale        
              Tableau <Coordonnee> D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme());
              // récupération de la variation de vitesse
              bool ddl_vitesse;
              const Tableau <Coordonnee> D_V = defS.Der_VitesseM_tdt(ddl_vitesse);
              D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente
              for (int ii=1;ii<=nbddl;ii++)
               {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale
                                 - (V*normale) * D_normale(ii);};
              // variation de u
              D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV);
              // variation de la norme de V
              Tableau <double> D_nV = Util::VarNorme(D_V,V,nV);
              // variation de w s'il a une norme différente de 0
              D_w.Change_taille(nbddl,vecNul); // !! init obligatoire car peut ne pas rentrer dans les if qui suivent
              if (norme_w > ConstMath::trespetit)
               {if (coef_aero_t != NULL)
                 { D_w_non_normer.Change_taille(nbddl);
					    // tout d'abord la variation du produit vectoriel 
                   Coordonnee k = Util::ProdVec_coor( u, normale);              
                   Tableau <Coordonnee> D_k = Util::VarProdVect_coor(u,normale,D_u,D_normale);
                   D_w_non_normer=Util::VarProdVect_coor(u,k,D_u,D_k);
                   D_w = Util::VarUnVect_coor(w,D_w_non_normer,norme_w);
                  }
               };
              // variation des coefficients
              // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
              D_coef_frot_fluid.Change_taille(nbddl);
              if (frot_fluid != NULL) 
                { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt);
                  for (int i=1;i<=nbddl;i++) 
                    D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt)
                                           + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i);
                 }; 
              // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
              D_coef_n.Change_taille(nbddl);
              if (coef_aero_n != NULL) 
                { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV);
                  for (int i=1;i<=nbddl;i++) 
                    D_coef_n(i) = poidvol *  poids(ni) * (
                                  valder.derivee * D_nV(i)  * (*ex.jacobien_tdt) * cos_directeur
                                  + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur 
                                  + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i))
                                                        );
                 };                                       
              // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
              D_coef_t.Change_taille(nbddl);
              if (coef_aero_t != NULL) 
               { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV);
                 for (int i=1;i<=nbddl;i++) 
                    D_coef_t(i) = poidvol *  poids(ni) * (
                                  valder.derivee * D_nV(i)  * (*ex.jacobien_tdt) * cos_directeur
                                  + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur 
                                  + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i))
                                                      );
                };
              };  //-- fin du if (avec_raid)
           // calcul du résidu
           int ix=1; int dimf = 3;   // ne fonctionne qu'en dim 3  
           // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
           double coef_frot_fluid=0.;
           if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt);}; 
           // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
           double coef_n=0.;
           if (coef_aero_n != NULL) 
              { coef_n += poidvol * coef_aero_n->Valeur(nV) *  poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; 
           // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
           double coef_t=0.;
           if (coef_aero_t != NULL) 
              { coef_t += poidvol * coef_aero_t->Valeur(nV) *  poids(ni) * (*ex.jacobien_tdt) * cos_directeur;};
           for (int ne =1; ne<= nbne; ne++) 
             for (int i=1;i<= dimf;i++,ix++)
               { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));
                 if (avec_raid)
                  {for (int j =1; j<= nbddl; j++)  
                     { //cout << "\n taphi(ni)(ne)= " << taphi(ni)(ne) << endl;
							  //cout << "\n D_coef_frot_fluid(j) " << D_coef_frot_fluid(j) << endl;
							  //cout << "\n Vt(i) " << Vt(i) << endl;
							  //cout << "\n D_Vt(j)(i) " << D_Vt(j)(i) << endl;
							  //cout << "\n D_coef_n(j) " << D_coef_n(j) << endl;
							  //cout << "\n u(i) " << u(i) << endl;
							  //cout << "\n D_u(j)(i) " << D_u(j)(i) << endl;
							  //cout << "\n D_coef_t(j) " << D_coef_t(j) << endl;
							  //cout << "\n w(i) " << w(i) << endl;
							  //cout << "\n D_w(j)(i) " << D_w(j)(i) << endl;
							  
							  KM(ix,j) -= taphi(ni)(ne) * coef_mul *(
                                     D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i)
                                   + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) 
                                   + D_coef_t(j) * w(i) + coef_t * D_w(j)(i)
                                                   ); 
                      };
                  };
                };  
          } // fin boucle sur les points d'intégrations
        break;   
      }; // fin du cas de la dimension 3
      case 2: // cas de la dimension 2
      { // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit)
        {  el.res = (*res_extS)(numfront); el.raid = (*raid_extS)(numfront);       
           return el;
         };
        Vecteur& SM = (*((*res_extA)(numfront)));  //  pour simplifier
        Mat_pleine & KM = (*((*raid_extA)(numfront))); //  "      "       "
        el.res = (*res_extA)(numfront); el.raid = (*raid_extA)(numfront); // pour le retour
        int ni; // compteur globale de point d'integration
        Deformation & defA = *defArete(numfront); // pour simplifier l'écriture
        for (defA.PremierPtInteg(), ni = 1;defA.DernierPtInteg();defA.NevezPtInteg(),ni++)
         { // -- calcul des éléments de la métrique, entre autre le jacobien, on utilise le même calcul
           // que pour un calcul primaire en explicit mais pour un calcul autre que mécanique
           const Met_abstraite::Impli& ex = defA.Cal_implicit(premier_calcul); 
           // détermination de la normale à la surface qui  vaut le vecteur perpendiculaire au g1
           // dans le sens directe 
           Coordonnee normale;  normale(1) = -(*ex.giB_tdt)(1)(2); normale(2) = (*ex.giB_tdt)(1)(1);
           normale.Normer(); // on norme la normale
           // récupération de la vitesse
           const Coordonnee V = defA.VitesseM_tdt(); double nV = V.Norme(); 
           // dans le cas où la vitesse est trop faible, le résidu est nul
           if (nV < ConstMath::trespetit) return el;           
           Coordonnee Vt=V-(V*normale)*normale;// calcul de la vitesse tangente
           double nVt = Vt.Norme(); // norme de la vitesse tangente
           if (nVt < ConstMath::trespetit) { nVt=0.;Vt.Zero();} else {Vt /= nVt;}; // on norme la vitesse tangente
           Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
           double cos_directeur = u * normale; // permet de calculer surface normale à la vitesse
           Coordonnee w(dime); // comme on est en 2D, w ce calcul directement avec les composantes de u
           if (coef_aero_t != NULL) {w(1) = -u(2); w(2)=u(1);};
           // calcul éventuel des variations
           static Tableau <Coordonnee> D_Vt,D_u,D_w;
           static Tableau <double> D_coef_frot_fluid,D_coef_n,D_coef_t;
           if (avec_raid)
            { // calcul de la variation de la normale
              // 1) variation du produit vectoriel
              Tableau <Coordonnee > D_pasnormale(nbddl);
              for (int i=1;i<=nbddl;i++)
                {D_pasnormale(i)(1) = -(*ex.d_giB_tdt)(i)(1)(2); D_pasnormale(i)(2) = (*ex.d_giB_tdt)(i)(1)(1);};
              // 2) de la normale        
              Tableau <Coordonnee> D_normale = Util::VarUnVect_coor(normale,D_pasnormale,normale.Norme());
              // récupération de la variation de vitesse
              bool ddl_vitesse;
              const Tableau <Coordonnee> D_V = defA.Der_VitesseM_tdt(ddl_vitesse);
              D_Vt.Change_taille(nbddl); // calcul de la variation de la vitesse tangente
              for (int ii=1;ii<=nbddl;ii++)
               {D_Vt(ii)=D_V(ii) - (D_V(ii) * normale + V * D_normale(ii)) * normale
                                 - (V*normale) * D_normale(ii);};
              // variation de u
              D_u.Change_taille(nbddl); D_u = Util::VarUnVect_coor( V, D_V,nV);
              // variation de la norme de V
              Tableau <double> D_nV = Util::VarNorme(D_V,V,nV);
              // variation de w
              D_w.Change_taille(nbddl);
              if (coef_aero_t != NULL)
               { for (int i=1;i<=nbddl;i++) {D_w(i)(1)=-D_u(i)(2);D_w(i)(2)=D_u(i)(1);}; 
                } 
              // variation des coefficients
              // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
              D_coef_frot_fluid.Change_taille(nbddl);
              if (frot_fluid != NULL) 
                { Courbe1D::ValDer valder = frot_fluid->Valeur_Et_derivee(nVt);
                  for (int i=1;i<=nbddl;i++) 
                    D_coef_frot_fluid(i) = valder.derivee * D_nV(i) * poids(ni) * (*ex.jacobien_tdt)
                                           + valder.valeur * poids(ni) * (*ex.d_jacobien_tdt)(i);
                 }; 
              // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
              D_coef_n.Change_taille(nbddl);
              if (coef_aero_n != NULL) 
                { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV);
                  for (int i=1;i<=nbddl;i++) 
                    D_coef_n(i) = poidvol *  poids(ni) * (
                                  valder.derivee * D_nV(i)  * (*ex.jacobien_tdt) * cos_directeur
                                  + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur 
                                  + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i))
                                                        );
                 };                                       
              // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
              D_coef_t.Change_taille(nbddl);
              if (coef_aero_t != NULL) 
               { Courbe1D::ValDer valder = coef_aero_t->Valeur_Et_derivee(nV);
                 for (int i=1;i<=nbddl;i++) 
                    D_coef_t(i) = poidvol *  poids(ni) * (
                                  valder.derivee * D_nV(i)  * (*ex.jacobien_tdt) * cos_directeur
                                  + valder.valeur * (*ex.d_jacobien_tdt)(i) * cos_directeur 
                                  + valder.valeur * (*ex.jacobien_tdt) * (D_u(i) * normale + u * D_normale(i))
                                                      );
                };
              };  //-- fin du if (avec_raid)
           // calcul du résidu
           int ix=1;    
           // cas de T: T = to(Vt) * S * ut, Vt étant la vitesse tangentielle et ut étant le vecteur directeur de Vt
           double coef_frot_fluid=0.;
           if (frot_fluid != NULL) { coef_frot_fluid += frot_fluid->Valeur(nVt) * poids(ni) * (*ex.jacobien_tdt);}; 
           // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
           double coef_n=0.;
           if (coef_aero_n != NULL) 
              { coef_n += poidvol * coef_aero_n->Valeur(nV) *  poids(ni) * (*ex.jacobien_tdt) * cos_directeur;}; 
           // cas de Ft = poids_volu * ft(V) * S * (normale*u) * w, w unitaire suivant la normal à V
           double coef_t=0.;
           if (coef_aero_t != NULL) 
              { coef_t += poidvol * coef_aero_t->Valeur(nV) *  poids(ni) * (*ex.jacobien_tdt) * cos_directeur;};
           for (int ne =1; ne<= nbne; ne++) 
             for (int i=1;i<= dime;i++,ix++)
               { SM(ix) += taphi(ni)(ne) * coef_mul * (coef_frot_fluid * Vt(i) + coef_n * u(i) + coef_t * w(i));
                 if (avec_raid)
                  {for (int j =1; j<= nbddl; j++)  
                     {KM(ix,j) -= taphi(ni)(ne) * coef_mul * (
                                     D_coef_frot_fluid(j) * Vt(i) + coef_frot_fluid * D_Vt(j)(i)
                                   + D_coef_n(j) * u(i) + coef_n * D_u(j)(i) 
                                   + D_coef_t(j) * w(i) + coef_t * D_w(j)(i)
                                                   ); 
                      };
                  };
                };  
          } // fin boucle sur les points d'intégrations
        break; 
        };  
      case 1: // cas de la dimension 1
      { // dans le cas ou le poid volumique est nul, on retourne sans calcul
        if (poidvol < ConstMath::trespetit)
        {  Element::ResRaid el;    
           el.res = (*res_extN)(numfront); 
           el.raid = (*raid_extN)(numfront);       
           return el;
         };
        Vecteur& SM = (*((*res_extN)(numfront)));  //  pour simplifier
        Mat_pleine & KM = (*((*raid_extN)(numfront))); //  "      "       "
        el.res = (*res_extN)(numfront); el.raid = (*raid_extN)(numfront); // pour le retour
        // il n'y a pas plusieurs point d'intégration
        // en 1D il ne peut y avoir que deux extrémités, la première à une normale = -1 , la seconde 1
        Coordonnee normale(1); if (numfront == 1) {normale(1)=-1.;} else {normale(1)=1.;};
        // récupération de la vitesse
        Noeud* noe = (tabb(numfront)->TabNoeud())(1); // on récupére tout d'abord le noeud fontière
        const Coordonnee& V = def->VitesseM_tdt(noe); double nV = V.Norme();
        // dans le cas où la vitesse est trop faible, le résidu est nul
        if (nV < ConstMath::trespetit) return el;
        // dans le cas 1D il n'y a qu'un effort de trainée (car pas de vitesse tangente)           
        Coordonnee u= V / nV; // on norme la vitesse, car ensuite on n'a besoin que de la direction unitaire de la vitesse
        // u en fait = 1 ou -1 d'où variation = 0
        // calcul éventuel des variations
        static Tableau <double> D_coef_n;
        if (avec_raid)
            { // calcul de la variation de la normale
              // récupération de la variation de vitesse
              bool ddl_vitesse;
              const Tableau <Coordonnee> D_V = def->Der_VitesseM_tdt(ddl_vitesse,noe);
              // variation de la norme de V
              Tableau <double> D_nV = Util::VarNorme(D_V,V,nV);
              // variation des coefficients
              // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
              D_coef_n.Change_taille(nbddl);
              if (coef_aero_n != NULL) 
                { Courbe1D::ValDer valder = coef_aero_n->Valeur_Et_derivee(nV);
                  for (int i=1;i<=nbddl;i++) 
                    D_coef_n(i) = poidvol *  poids(1) * valder.derivee * D_nV(i);
                 };                                       
              };  //-- fin du if (avec_raid)
        // calcul du résidu
        int ix=1; int dimf = dime;     
        // cas de Fn = poids_volu * fn(V) * S * (normale*u) * u, u unitaire suivant V
        double coef_n=0.; 
        if (coef_aero_n != NULL) // le poids(1) contiend la section, et il n'y a pas de jacobien, cos directeur = 1
              { coef_n += poidvol * coef_mul * coef_aero_n->Valeur(nV) *  poids(1) ;}; 
        for (int ne =1; ne<= nbne; ne++)  // il n'y qu'un point d'intégration le noeud lui-même
          for (int i=1;i<= dimf;i++,ix++)
               { SM(ix) += taphi(1)(ne) * ( coef_n * u(i) );
                 if (avec_raid)
                  {for (int j =1; j<= nbddl; j++)  
                     {KM(ix,j) -= taphi(1)(ne) * coef_mul * (D_coef_n(j) * u(i));}; 
                  };
               }; 
        break;   
      }; // fin du cas de la dimension 1 */
      
    }; //-- fin du switch sur la dimension  
    // retour   
    return el;  
  };
    	    
