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

#include "I_O_Condilineaire.h"
#include "CharUtil.h"
#include <fstream>
#include <sstream>
#include <cstring>
#include <limits>


# include <iostream>
using namespace std;  //introduces namespace std

// par défaut
I_O_Condilineaire::I_O_Condilineaire():
  Condilineaire()
  ,nom_maillage(NULL),refe("")
  ,t_min(0.),t_max(ConstMath::tresgrand),echelle(1.)
  ,precedent(false),valeur_precedente_t(0.)
  ,tab_co_charge(),refs_associe(),enu(NU_DDL)
  ,nom_mail_associe()
  ,condition_relative(false)
  ,fctch(),delta_fctch(),nbddlfamille(0)
  ,def_auto_par_rotation(false),stricte_egalite(false)
  ,type_centre(1),mailEtNumCentreNoeud(),centre_noeud(NULL)
  ,pl(),dr()
    {};
    

// de copie
I_O_Condilineaire::I_O_Condilineaire(const I_O_Condilineaire& nd):
  Condilineaire(nd)
  ,nom_maillage(NULL),refe(nd.refe)
  ,t_min(nd.t_min),t_max(nd.t_max),echelle(nd.echelle)
  ,precedent(nd.precedent),valeur_precedente_t(nd.valeur_precedente_t)
  ,tab_co_charge(nd.tab_co_charge),refs_associe(nd.refs_associe)
  ,nom_mail_associe(nd.nom_mail_associe),enu(nd.enu)
  ,condition_relative(nd.condition_relative)
  ,fctch(nd.fctch),delta_fctch(nd.delta_fctch),nbddlfamille(nd.nbddlfamille)
  ,def_auto_par_rotation(nd.def_auto_par_rotation),stricte_egalite(nd.stricte_egalite)
  ,type_centre(nd.type_centre),centre_rotation(nd.centre_rotation)
  ,mailEtNumCentreNoeud(nd.mailEtNumCentreNoeud),centre_noeud(nd.centre_noeud)
  ,pl(nd.pl),dr(nd.dr)
    {if (nd.nom_maillage != NULL)
         nom_maillage = new string (*(nd.nom_maillage));
     };

// DESTRUCTEUR : 
I_O_Condilineaire::~I_O_Condilineaire()
	{ if (nom_maillage != NULL) 
  	   delete nom_maillage;
	};
				        
// examine si la condition passée en argument possède les mêmes cibles que this
// mais que les data associés sont différents
// ramène true si c'est vrai, false sinon
// en fait cette fonction est définit par conformité avec le programme de lecture 
// LectBloc<T>::Lecture(.. mais ici on peut avoir plusieurs conditions linéaire
// sur la même référence, donc on ramène toujours false
bool I_O_Condilineaire::MemeCibleMaisDataDifferents(I_O_Condilineaire& )        
	{ return false;  
	};
    
    
// Affiche les donnees 
void I_O_Condilineaire::Affiche () const 
   { // affichage éventuelle du nom de maillage
     if (nom_maillage != NULL)
       { cout << "\n nom_mail= " << *nom_maillage;} else cout << "\n";	
	    // puis le reste
     cout << " ref_princ= " << refe ;
     if (refs_associe.Taille() != 0)
     	{int tai = refs_associe.Taille();
       cout << " ref_associe= ";
       for (int i=1;i<=tai;i++)
         if (nom_maillage != NULL) 
            {cout << nom_mail_associe(i) << " " << refs_associe(i) << " ";}
         else   
            {cout  << refs_associe(i) << " ";}
     	};
     cout << "\n type_ddl= " << Nom_ddl(enu) ;
     cout <<  " def_auto_par_rotation= " << def_auto_par_rotation;
     cout <<  " stricte_egalite= " << stricte_egalite;
//     if (!def_auto_par_rotation)
//      { cout << " val_condi= " << this->beta << " coefficients= " << val;}
//     else
//      {if (type_centre == 1)
//        { cout << " centre_fixe= " ;
//          if (ParaGlob::Dimension() == 2) {cout << dr.PointDroite() << " " ;}
//          else {cout << pl.PointPlan() << " " ;};
//        }
//       else if  (type_centre == 2) 
//        { cout << " centre_noeud_t0= " << mailEtNumCentreNoeud << " ";} 
//       else if  (type_centre == 3) 
//        { cout << " centre_noeud_t= " << mailEtNumCentreNoeud << " ";};
//       if (ParaGlob::Dimension() == 2)
//         {cout << " dir_droite_now= " << dr.VecDroite() <<  " dir_droite0= " << val;}
//       else // cas dimension 3
//         {cout << " normal_plan_now= " << pl.Vecplan() << " normal_plan0= " << val;}
//      };

     int dima = ParaGlob::Dimension();
     if(ParaGlob::AxiSymetrie())
       // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
       // dimension-1 coordonnées donc on décrémente
       dima--;
    
     if (def_auto_par_rotation)
      {if (type_centre == 1)
        { cout << " centre_fixe= " ;
          if (dima == 2) {cout << dr.PointDroite() << " " ;}
          else {cout << pl.PointPlan() << " " ;};
        }
       else if  (type_centre == 2) 
        { cout << " centre_noeud_t0= " << mailEtNumCentreNoeud << " ";} 
       else if  (type_centre == 3) 
        { cout << " centre_noeud_t= " << mailEtNumCentreNoeud << " ";};
       if (dima == 2)
         {cout << " dir_droite_now= " << dr.VecDroite() <<  " dir_droite0= " << val;}
       else // cas dimension 3
         {cout << " normal_plan_now= " << pl.Vecplan() << " normal_plan0= " << val;}
      }
     else if (stricte_egalite)
      {   }
     else
      { cout << " val_condi= " << this->beta << " coefficients= " << val;};
    
    
    
     cout << " temps_mini= " << t_min << " temps_maxi= " << t_max
          << " echelle= " << echelle
          << " activite_actuelle: " << precedent      
	         << "  condition_relative= " << condition_relative << " ";
     cout << " courbe_charge= " << tab_co_charge;
     cout << endl;            
   };
		
		 
// Realise l'egalite 		
I_O_Condilineaire& I_O_Condilineaire::operator= (const I_O_Condilineaire& d)
  {// traitement du nom de maillage éventuel  
   if (d.nom_maillage == NULL)
    {if (nom_maillage != NULL)
       {delete nom_maillage;nom_maillage=NULL; nom_mail_associe.Change_taille(0);}
    }
   else
   	{if (nom_maillage == NULL)
   		{nom_maillage = new string (*(d.nom_maillage));
   	     nom_mail_associe = d.nom_mail_associe;
   	     }
     else 
     	{*nom_maillage = *(d.nom_maillage);
         nom_mail_associe = d.nom_mail_associe;
         };
   	};
   // nom de la référence
   refe = d.refe;
   // tableau de références associé
   refs_associe = d.refs_associe;
   // les temps
   t_min = d.t_min; t_max = d.t_max;
   echelle = d.echelle;
   precedent = d.precedent;
	  valeur_precedente_t = d.valeur_precedente_t;
   // l'énuméré
   enu = d.enu;
	  nbddlfamille = d.nbddlfamille;
   // la relativité de la condition
   condition_relative = d.condition_relative;
   // les courbes de charge
   tab_co_charge = d.tab_co_charge;
   def_auto_par_rotation = d.def_auto_par_rotation;
   stricte_egalite = d.stricte_egalite;
   type_centre = d.type_centre;
	  centre_rotation = d.centre_rotation;
   mailEtNumCentreNoeud = d.mailEtNumCentreNoeud;
   centre_noeud = d.centre_noeud;
   pl = d.pl;
   dr = d.dr;
   
   // la condition linéaire
   this->Condilineaire::operator=(d);	
   // retour
   return *this;  
  };
	
//Surcharge d'operateur logique
bool I_O_Condilineaire::operator == ( I_O_Condilineaire& a) const
{  // traitement du nom de maillage éventuel  
   if (nom_maillage == NULL)
      { if (a.nom_maillage != NULL) return false;        
       }
   else
      { if (a.nom_maillage == NULL) return false;
        // sinon les deux sont non null: on test leur égalité
        if (*nom_maillage != *(a.nom_maillage)) return false;         
       }; 
   int dima = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   // cas des centres de rotation éventuelles, il peut y avoir des données qui ne servent pas
   // qui soient différentes, alors que celles qui servent sont identiques !
   if (def_auto_par_rotation != a.def_auto_par_rotation) return false;
   if (stricte_egalite != a.stricte_egalite) return false;
   if (def_auto_par_rotation)
    { if (type_centre != a.type_centre)   return false;
      switch (type_centre)
   	   { case 1: switch (dima)
   	              { case 2: if (dr.PointDroite() != a.dr.PointDroite()) return false; break;
   	                case 3: if (pl.PointPlan() != a.pl.PointPlan()) return false; break;
   	              };
   	     case 2: case 3: if (centre_noeud != a.centre_noeud) return false; break;
   	   };
   	  switch (dima)
   	   { case 2: if (dr.VecDroite() != a.dr.VecDroite()) return false; break;
   	     case 3: if (pl.Vecplan() != a.pl.Vecplan()) return false; break;
   	   };
    }
   else if (stricte_egalite)
    { }
   else
    {if (this->beta != a.beta) return false;
     if (val != a.val) return false;
     };
       
   // les autres données    
   if ( (refe==a.refe) && (refs_associe==a.refs_associe) 
         && (nom_mail_associe == a.nom_mail_associe)
         && (t_min == a.t_min) && (t_max == a.t_max)
         && (echelle == a.echelle)
         && (precedent ==a.precedent) 
         && (enu == a.enu) && (tab_co_charge == a.tab_co_charge)
         && (condition_relative == a.condition_relative) 
       )
     {return true;}
   else 
     {return false; };    
 } ;
	 
         		
// lecture de la condition linéaire sur le fichier d'entree
void I_O_Condilineaire::Lecture(UtilLecture & entreePrinc) 
{ // on regarde tout d'abord si il y a un nom de maillage, qui doit être le premier nom
  int dima = ParaGlob::Dimension();
  if(ParaGlob::AxiSymetrie())
    // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les 
    // dimension-1 coordonnées donc on décrémente
    dima--;
  string nom;
  *(entreePrinc.entree) >> nom;
  if (nom == "nom_mail=")
      { // cas où il y a un nom de maillage
        *(entreePrinc.entree) >> nom; // lecture du nom
        if (nom_maillage == NULL) { nom_maillage = new string(nom);}
        else                      { *nom_maillage = nom;};  	
        // puis on prépare la suite en lisant la référence principale
        *(entreePrinc.entree) >> nom;
      };
  // lecture de la reference
  refe = nom;          
  if (refe.length() == 0)
      { // pas de  reference
        cout << "\n erreur de lecture d'une reference de condition limite lineaire "
             << " le nom de la reference a une longueur nulle \n";
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
      };
   // maintenant on lit les autres informations
   // on lit l'énuméré
   *(entreePrinc.entree) >> nom;
   if (nom != "enu=")    
      { // pas d'énuméré
        cout << "\n erreur de lecture d'une reference de condition limite lineaire "
             << " on attendait enu= , et on a lue: " << nom << " ";
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
      }
   else
      { *(entreePrinc.entree) >> nom;
        if (!ExisteEnum_ddl(nom))
         { // énuméré incorrecte
           cout << "\n erreur de lecture de l'enumere de condition limite lineaire, il n'existe pas "
                << " dans la liste des enumeres correctes: on a lue: " << nom << " ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          }
         else // on sauvegarde le premier ddl de la famille
          {enu = PremierDdlFamille(Id_nom_ddl(nom));};
      };
   // on passe une ligne
   entreePrinc.NouvelleDonnee(); // on passe un enregistrement
   bool passer_une_ligne = false;
   // lecture des références associées éventuellement
   if (strstr(entreePrinc.tablcar,"refs_associe=")!=NULL)
   	{ *(entreePrinc.entree) >> nom;
      if (nom != "refs_associe=")    
         { // pas de mot clé
           cout << "\n erreur de lecture des references associees pour un  condition limite lineaire "
                << " on attendait refs_associe= , et on a lue: " << nom << " ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          }
      else
      	{  // lecture de la liste demandée
           int compteur=0; // pour éviter une boucle infinie
           // il y a deux types de lecture suivant qu'il doit y avoir un nom de maillage ou pas
           if (nom_maillage == NULL)
            {list <string> list_inter;
             while (compteur < 1000)
              {(*entreePrinc.entree) >> nom; compteur++;
               // gestion d'erreur
               if (nom == "nom_mail=")
                { // cas où il y a un nom de maillage
                  cout << "\n erreur en lecture : on a lue: " << nom << " or la ref "
                       << " principal ne comporte pas de nom de maillage, dans ce cas les ref"
                       << " secondaires ne doivent pas comporter de nom de maillage !! ";
                  entreePrinc.MessageBuffer("*** lecture des  references secondaire d'une condition lineaire ****" );
                  throw (UtilLecture::ErrNouvelleDonnee(-1));
                  Sortie(1);     
                };
               // suite normale
               if (nom != "fin_list_refs_associe_")
                  {list_inter.push_back(nom);}
               else break;
              };
             // recopie dans le tableau
             int taille = list_inter.size();
             refs_associe.Change_taille(taille);
             list <string>::iterator it,itfin=list_inter.end();
             int i=1;
             for (it = list_inter.begin();it!=itfin;it++,i++) 
                refs_associe(i)=*it;
            }
           else
            // cas où il est possible qu'on lise nom de maillage 
            // de plus il faut attribuer un nom de maillage à chaque ref associé
            {list <Deux_String> list_inter;
             string nom_mail;
             while (compteur < 1000)
              {(*entreePrinc.entree) >> nom; 
               if (nom == "nom_mail=")
                 // cas où il y a un nom de maillage
                 {*(entreePrinc.entree) >> nom_mail; // lecture du nom
                  *(entreePrinc.entree) >> nom; // lecture de la référence
                 }
               else   
                 {nom_mail=*nom_maillage;}; // attribution du nom de maillage générique
              compteur++;
               if (nom != "fin_list_refs_associe_")
                  {list_inter.push_back(Deux_String(nom_mail,nom));}
               else break;
              };
             // recopie dans le tableau
             int taille = list_inter.size();
             refs_associe.Change_taille(taille);nom_mail_associe.Change_taille(taille);
             list <Deux_String>::iterator it,itfin=list_inter.end();
             int i=1;
             for (it = list_inter.begin();it!=itfin;it++,i++) 
                {nom_mail_associe(i)=(*it).nom1;refs_associe(i)=(*it).nom2;}
            };
           passer_une_ligne = true;    
      	};    
   	};
   // on récupère l'échelle globale éventuellement
   if(strstr(entreePrinc.tablcar,"ECHELLE:")!=0)
     { // cas où il y a un facteur d'échelle
       *(entreePrinc.entree)  >> nom;
       if (nom != "ECHELLE:")
         {cout << "\n erreur de syntaxe en lecture du facteur d'echelle "
               << " on attendait le mot cle  ECHELLE: et on a lue " << nom << " ";
          entreePrinc.MessageBuffer("**erreur lecture d'une reference de condition lineaire **");
          throw (UtilLecture::ErrNouvelleDonnee(-1));
          Sortie(1);          
          }
        // lecture du facteur
        *(entreePrinc.entree)  >> echelle; 
     }
   else
     // sinon on met l'échelle à 1
     { echelle = 1. ;}; //-- fin récup de l'échelle

   // lecture d'un tmin et/ou tmax éventuel
   if (strstr(entreePrinc.tablcar,"TEMPS_MINI=")!=NULL)
     { *(entreePrinc.entree) >> nom;
       if (nom != "TEMPS_MINI=")    
          { // pas d'énuméré
            cout << "\n erreur de lecture: position du TEMPS_MINI=  pour un  condition limite lineaire "
                 << " on attendait TEMPS_MINI= , et on a lue: " << nom << " ";
            entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);     
           }
       else
           {(*entreePrinc.entree) >> t_min;passer_une_ligne = true;};    
     };
   if (strstr(entreePrinc.tablcar,"TEMPS_MAXI=")!=NULL)
     { *(entreePrinc.entree) >> nom;
       if (nom != "TEMPS_MAXI=")    
          { // pas d'énuméré
            cout << "\n erreur de lecture: position du TEMPS_MAXI=  pour un  condition limite lineaire "
                 << " on attendait TEMPS_MAXI= , et on a lue: " << nom << " ";
            entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);     
           }
       else
           {(*entreePrinc.entree) >> t_max;passer_une_ligne = true;};
     };
   // lecture éventuel de l'indicateur de condition relative
   condition_relative = false; // faux par défaut
   if (strstr(entreePrinc.tablcar,"CONDITION_RELATIVE=")!=NULL)
     {*(entreePrinc.entree) >> nom;
      if (nom != "CONDITION_RELATIVE=")    
         { cout << "\n erreur de lecture: position de  CONDITION_RELATIVE= erronee, pour un  condition "
                << " limite lineaire,  on attendait CONDITION_RELATIVE= , et on a lue: " << nom << " ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          }
      else
      	   {(*entreePrinc.entree) >> condition_relative; passer_une_ligne = true;};
      // il y a une vérification concernant la présence de courbe de charge après la lecture de ces dernières
     };
       
   // on passe une ligne pour lire les coefficients de la condition linéaire     	
   if (passer_une_ligne) entreePrinc.NouvelleDonnee(); // on passe éventuellement un enregistrement
   passer_une_ligne = false;
   
   // --- on regarde s'il s'agit d'une définition de linéarité / à une droit ou un plan
   if (strstr(entreePrinc.tablcar,"def_auto_coef_planOuDroite_")!=NULL)
   	{ if (dima == 1)
         { cout << "\n erreur de lecture: on ne peut pas faire de definition automatique avec la dimension 1 ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
   	  def_auto_par_rotation = true; // on signale une condition automatique
   	  *(entreePrinc.entree) >> nom; // on passe le mot clé
      if (nom != "def_auto_coef_planOuDroite_")    
         { cout << "\n erreur de lecture: position de  def_auto_coef_planOuDroite_ erronee, pour un  condition "
                << " limite lineaire,  on attendait def_auto_coef_planOuDroite_ , et on a lue: " << nom << " ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
      // on vérifie qu'il n'y a pas de référence associée car ce cas n'est pas prévu (ni possible a priori)
      if (refs_associe.Taille() != 0)    
         { cout << "\n erreur de lecture: dans le cas du condition lineaire automatique avec ligne ou plan "
                << " on ne peut pas avoir de reference associe ";
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
       // dans le cas où on a lue un enum UX pb, car la projection concerne les positions et non les déplacements
       // sinon il faut utiliser une condition générale
      if (enu != X1)    
       { cout << "\n erreur de coherence: dans le cas du condition lineaire automatique avec ligne ou plan "
        << " on ne peut pas utiliser comme enumere: " << Nom_ddl(enu) ;
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
       };
      // ici l'échelle doit être égale à 1, on vérifie, pour des pb de projection et d'algo d'ensemble
      if (echelle != 1.)    
       { cout << "\n erreur de coherence: dans le cas du condition lineaire automatique avec ligne ou plan "
              << " on ne peut pas utiliser une echelle (ici= " << echelle << " ) differente de 1. !! " ;
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
       };
      // ici on ne doit pas avoir de condition relative car ça ne signifie rien pour la projection, on vérifie, 
      if (condition_relative)    
       { cout << "\n erreur de coherence: dans le cas du condition lineaire automatique avec ligne ou plan "
        << " on ne peut pas utiliser une condition relative (cela ne signifie rien dans le cas d'une projection ) !! " ;
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);     
       };
		
		
      // maintenant on lit le centre
      *(entreePrinc.entree) >> nom; 
      // on met à jour la dimension des plan droite
      switch (dima)
           	{ case 2: dr.Change_dim(dima);break;
           	  case 3: pl.Change_dim(dima);break;
           	};

      if (nom == "centre_fixe_") 
         { type_centre = 1; 
           Coordonnee centre_rotation(dima);
           centre_rotation.Lecture(entreePrinc);
           switch (dima)
           	{ case 2: dr.Change_ptref(centre_rotation); break;
           	  case 3: pl.Change_ptref(centre_rotation); break;
           	}
         }
       else if ((nom == "centre_noeud_a_t0_") || (nom == "centre_noeud_a_t_"))   
         { if (nom == "centre_noeud_a_t0_")     {type_centre = 2;} 
           else if (nom == "centre_noeud_a_t_") {type_centre = 3;}; 
           // cas d'un centre donné par un numero de noeud
           string nom_mail;
           *(entreePrinc.entree) >> nom_mail;
           if (nom_mail == "nom_mail=")
                { // cas où il y a un nom de maillage
                  *(entreePrinc.entree) >> mailEtNumCentreNoeud.nom; // lecture du nom
                  *(entreePrinc.entree) >> mailEtNumCentreNoeud.n; // lecture du numero de noeud
                }
           else 
            	{ // sinon cela veut dire que l'on vient de lire un numéro de noeud du premier maillage
            	  mailEtNumCentreNoeud.nom = "";
            	  mailEtNumCentreNoeud.n = ChangeEntier(nom_mail); 	
            	}; 
         }
       else   
         { cout << "\n erreur de lecture: on attendait : centre_fixe_ ou centre_noeud_a_t0_ "
                << " ou centre_noeud_a_t_ et on a lue: " << nom ;
           entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
           throw (UtilLecture::ErrNouvelleDonnee(-1));
           Sortie(1);     
          };
       // puis on lit la normale ou la direction de la droite qui correspond aux composantes de val ici
   	}
   else {def_auto_par_rotation = false;	};
 
   // -- on regarde s'il s'agit d'une condition de stricte egalité entre noeud pour le type enu
   if (strstr(entreePrinc.tablcar,"stricte_egalite_")!= NULL)
    {   }
   else {stricte_egalite = false;};
   
   // dans un cas normal on lit une valeur de la condition linéaire 
   if ((!def_auto_par_rotation)&&(!stricte_egalite))
     {// lecture de la valeur de la condition limite
      *(entreePrinc.entree) >> nom;
      if (nom != "val_condi_lineaire=")    
        { cout << "\n erreur de lecture: val_condi_lineaire  pour un  condition limite lineaire "
               << " on attendait val_condi_lineaire= , et on a lue: " << nom << " ";
          entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
          throw (UtilLecture::ErrNouvelleDonnee(-1));
          Sortie(1);     
        }
      else
    	   { (*entreePrinc.entree) >> beta;};
     };
 
   if (!stricte_egalite) // dans le cas stricte_egalité, la lecture est finie
    { // lecture des coefficients de la condition linéaire
      *(entreePrinc.entree) >> nom;
      if (nom != "coefficients=")    
       { // pas d'énuméré
         cout << "\n erreur de lecture des coefficients de la  condition limite lineaire "
              << " on attendait coefficients= , et on a lue: " << nom << " ";
         entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
         throw (UtilLecture::ErrNouvelleDonnee(-1));
         Sortie(1);     
       }
      else
       { // lecture de la liste demandée
         int compteur=0; // pour éviter une boucle infinie
         list <double> list_inter; 
         while (compteur < 1000)
           { (*entreePrinc.entree) >> nom; compteur++;
            if (nom != "fin_list_coefficients_")
              { list_inter.push_back(ChangeReel(nom));}
            else break;                           
           };
         // recopie dans le tableau
         int taille = list_inter.size();
         val.Change_taille(taille);
         list <double>::iterator it,itfin=list_inter.end();
         int i=1;
         for (it = list_inter.begin();it!=itfin;it++,i++) 
            val(i)=*it;
         // on vérifie que le nombre de coefficients est correcte
         Tableau<Enum_ddl> tab_enu = TableauTypeDdlmobileAvecAxi(enu);
         nbddlfamille = tab_enu.Taille();
         if (taille != nbddlfamille * (1+refs_associe.Taille()))
          { cout << "\n erreur de lecture des coefficients de la condition lineaire, leur nombre  " << taille
                 << " est differente de (1 + le nombre de reference associe)*le nombre de ddl de la famille = " 
                 << nbddlfamille * (1+refs_associe.Taille()) << " ";
            if(ParaGlob::AxiSymetrie()) cout << "(ici en axi) ";
            entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
            throw (UtilLecture::ErrNouvelleDonnee(-1));
            Sortie(1);     
          };
         if (def_auto_par_rotation)
          {// on met à jour la direction ou la normale droite plan 
           switch (dima)
             { case 2: dr.Change_vect(val.Coordo()); break;
               case 3: pl.Change_normal(val.Coordo()); break;
             }
          };
       };
      // on regarde s'il faut considérer des fonctions de charge
      tab_co_charge.Libere(); // par défaut on initialise le tableau à 0	
      if (strstr(entreePrinc.tablcar,"AvecFonctionsDeCharges_")!=NULL)
        {entreePrinc.NouvelleDonnee(); // on passe un enregistrement
         // lecture du mot clé de début
         (*entreePrinc.entree) >> nom;
         if (nom != "deb_fonction_de_charge=")    
            { cout << "\n erreur de lecture d'une liste de fonctions de charge  "
                   << " pour un  condition limite lineaire "
                   << " on attendait deb_fonction_de_charge= , et on a lue: " << nom << " ";
              entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);     
            }
         else
          {  // lecture de la liste demandée
              int compteur=0; // pour éviter une boucle infinie
              list <string> list_inter;
              while (compteur < 1000)
               { (*entreePrinc.entree) >> nom; compteur++;
                 if (nom != "fin_list_fonctions_de_charges_")
                   { list_inter.push_back(nom);}
                 else break;                           
               };
              // recopie dans le tableau
              int taille = list_inter.size();
              int i=1;
              // dans le cas plan ou droite, par analogie au cas générale on considère une taille 
              // telle que c'est seulement à partir du  second élément que l'on travaille
              // on double le premier élément, pour permettre aux boucles de fonctionner, mais le premier
              // élément ne sert pas dans le calcul de la condition !!
              if (def_auto_par_rotation) {taille++;i=2;};
              
              tab_co_charge.Change_taille(taille);
                    list <string>::iterator it,itfin=list_inter.end();
                    for (it = list_inter.begin();it!=itfin;it++,i++) 
                       tab_co_charge(i)=*it; 
              if (def_auto_par_rotation)  tab_co_charge(1) = tab_co_charge(2);  // doublage du premier élément
          };
         // il doit y avoir autant de nom de fonction de charge que de coef + 1 pour la valeur
         if (tab_co_charge.Taille() != (val.Taille() + 1))  	
            { cout << "\n erreur de lecture d'une liste de fonctions de charge  "
                   << " pour un  condition limite lineaire "
                   << " le nombre de fonctions de charge lue (ici: " << tab_co_charge.Taille();
              if (def_auto_par_rotation)
                { cout << " ) doit etre egal au nombre de coefficient  pour la valeur de condition lineaire de projection "
                       << " ce qui devrait faire : " <<  (val.Taille()) << " ";
                }
              else
                { cout << " ) doit etre egal au nombre de coefficient + 1 pour la valeur de condition lineaire "
                       << " ce qui devrait faire : " <<  (val.Taille() + 1) << " ";
                };
              entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
              throw (UtilLecture::ErrNouvelleDonnee(-1));
              Sortie(1);
            };
        }
      else if (condition_relative)
        {// cas où il n'y a pas de fonction de charge, mais que l'on a indiqué une condition relative
         cout << "\n **** Warning !!! les conditions lineaires relatives ne fonctionnent que avec des courbes de charge "
              << " dans le cas de conditions simples (fixes) on se refere toujours a la situation a t=0 " << endl;
         condition_relative = false;                  		
        };
    }
   else
    {// quelques vérifs au cas où
     if (echelle != 1.)
      { cout << "\n erreur de coherence: dans le cas d'une condition stricte_egalite_ "
             << " on ne peut pas utiliser une echelle (ici= " << echelle << " ) differente de 1. !! " ;
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
      };
    if (  (strstr(entreePrinc.tablcar,"coefficients=")!= NULL)
        ||(strstr(entreePrinc.tablcar,"CONDITION_RELATIVE=")!= NULL)
       )
      { cout << "\n erreur de coherence: dans le cas d'une condition stricte_egalite_ "
             << " on ne peut pas utiliser les mots cles coefficients= , CONDITION_RELATIVE= !! " ;
        entreePrinc.MessageBuffer("*** lecture d'une reference de condition lineaire ****" );
        throw (UtilLecture::ErrNouvelleDonnee(-1));
        Sortie(1);
      };
    condition_relative = false;
    tab_co_charge.Libere();
    };
   // initialisation des grandeurs de travail
   Initialisation_condil();  
 };
 
// affichage des commandes particulières à la définition d'une condition linéaire
void I_O_Condilineaire::Info_commande_conditionLineaire(ofstream & sort,bool plusieurs_maillages)
 {
   //On va proposer un menu pour choisir entre différents types de conditions linéaires
   int type_CLL=0; // =0 non défini, =1 -> projection sur un plan ou une droite
                   // =2 -> condition générale
   {string rep=" ";
    // tableau des choix possibles
    Tableau <string> tab_choix(6);
    tab_choix(1) =  "\n (0 ou f)  (fin)        ";
    tab_choix(2) =  "\n (1)  info detaillees dans le fichier .info";
    tab_choix(3) =  "\n (2 ou ?)  informations succinctes a l ecran";
    tab_choix(4) =  "\n (3) CLL: proj sur plan en 3D (droite en 2D) ";
    tab_choix(5) =  "\n (4) CLL: generale     ";
    tab_choix(6) =  "\n (5) CLL: stricte_egalite     ";
  
    while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
       {
        try 
         { for (int i=1;i<=tab_choix.Taille();i++)
              cout << tab_choix(i);
           cout << "\n rep : ";
           rep = lect_return_defaut(false,"f"); cout << " grandeur lue " << rep;
           int num = 0; // par défaut
           if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie
            // on ne fait rien
            {num = 0;}
           else
            { num = ChangeEntier(rep);
              if (Minuscules(rep) == "?")
                num = 2;
              bool choix_valide=false;
              if ((num >= 0)&&(num<=5))
                { choix_valide=true; }
              else { cout << "\n Erreur on attendait un entier entre 0 et 5 !!, "
                          << "\n redonnez une bonne valeur"
                          << "\n ou taper f ou 0 pour arreter le programme";
                     choix_valide=false;
                   };
              switch (num)
               { case 0:  // sortie
                   { break;}
                 case 1:  // sortie documentation détaillée sur le fichier .info
                   {
 sort << "\n# .............................. condition lineaire: mode d'emploi ................................................."
      << "\n# |  NB: de nombreuse grandeurs sont optionelles, par contre l'ordre d'apparition est impose!!                     |"
      << "\n# |  constituee : d'une reference principal de noeud qui peut etre precedee (eventuellement) d'un nom de maillage, |"
      << "\n# |  ex1: N_avant , ex2: nom_mail= solide1  N_avant                                                                |" 
      << "\n# |  suivi sur la meme ligne du type de la famille de ddl sur laquelle s'applique la condition lineaire            |"
      << "\n# |  ex1: enu= UX , ex2: enu=  X1 , ex3 enu= TEMP                                                                  |" 
      << "\n# |  puis sur la ligne qui suit une suite eventuelle de references secondaires, (s'il n'y en a pas, on met rien )  |"
      << "\n# |  sinon on utilise deux mots cle pour encadrer la liste                                                         |"
      << "\n# |  ex1: refs_associe= N_arriere N_milieu  fin_list_refs_associe_                                                 |" 
      << "\n# |  Dans le cas ou la reference principal comporte un nom de maillage, il est possible d'indiquer ou non avant    |" 
      << "\n# |  chaque reference secondaire, un nom de maillage. Si ce nom de maillage est absent, c'est celui de la reference|" 
      << "\n# |  principale qui est retenue a la place. Ainsi, on peut definir une CLL entre des noeuds de maillages           |" 
      << "\n# |  differents. Par contre, si la reference principale ne contient pas de nom de maillage, les references         |" 
      << "\n# |  secondaires ne doivent pas en comporer, sinon cela genere une erreur !                                        |" 
      << "\n# |  les references secondaires doivent avoir exactement le meme nombre de noeud que la reference principal        |"
      << "\n# |  la condition linaire s'appliquera sur chaque noeud de la reference principal, associe aux noeuds de           |"
      << "\n# |  du meme rang des references secondaires: par exemple pour les ex1, la condition lineaire s'applique           |"
      << "\n# |  successivement pour tous noeud i de N_avant, sur le groupe (noeud i de N_avant + noeud i de N_arriere         |"
      << "\n# |  + noeud i de N_milieu). Comme il s'agit de la famille de  ddl de type UX, donc deplacement, en 3D             |"
      << "\n# |  on doit donc avoir 3*3 coef + 1 pour la valeur de la condition = 10 coef pour la condition qui s'ecrit        |"
      << "\n# |  donc : a1 UX(1) + a2 UY(1) + a3 UZ(1) + a4 UX(2) +..... + a9 UZ(3) = a10                                      |"
      << "\n# |  UX(1) correspond au deplacement du noeud de la reference de N_avant, UX(2) pour N_arriere, UX(3)  pour        |"
      << "\n# |  N_milieu, a10 est la condition imposee                                                                        |"
      << "\n# |  Ensuite toujours sur la meme ligne on peut eventuellement indiquer un temps mini et un temps maxi             |"
      << "\n# |  ex1  TEMPS_MINI= 0.1   TEMPS_MAXI=  5.                                                                        |"
      << "\n# |  Puis toujours sur la meme ligne, on peut eventuellement indiquer que la condition est relative ou non         |"
      << "\n# |  par defaut la condition est absolue, cela signifie que l'on se refere a la situation a t=0                    |"
      << "\n# |  dans le cas d'une condition relative, on se refere a la situation precedente: cependant, ce mecanisme         |"
      << "\n# |  ne fonctionne que si dans le cas de l'utilisation de fonction de charge (cf. suite des infos)                 |"
      << "\n# |  ex1 CONDITION_RELATIVE= 1  # =0 absolue, =1 relative                                                          |"
      << "\n# |  NB: tous la ligne: ref secondaire, temps mini maxi, condition realtive, est optionnelle, cela signifie        |"
      << "\n# |  quelle peut ne pas exister du tout, ou comporter quelques elements seulement.                                 |"
      << "\n# |                                                                                                                |"
      << "\n# |  Ensuite sur la ligne suivante et on indique tout d'abord la valeur de la condition lineaire, (correspond à a10|"
      << "\n# |  dans l'exemple 1 ) puis la la liste des coefficients de la conditions lineaire  encadre par 2 mots cle        |"
      << "\n# |  ex1    val_condi_lineaire=  10   coefficients= 1 2 3 4 5 6 7 8 9 10  fin_list_coefficients_                   |"
      << "\n# |  ensuite on indique eventuellement s'il y a des fonctions de charges pour les coefficients avec la presence    |"
      << "\n# |  ou non du mot cle  AvecFonctionsDeCharges_                                                                    |"
      << "\n# | ex1 val_condi_lineaire= 10 coefficients= 1 2 3 4 5 6 7 8 9 10 fin_list_coefficients_ AvecFonctionsDeCharges_   |"
      << "\n# | s'il y a des fonctions de charge, il doit y en avoir exactement le meme nombre que de coefficient+1 (pour      |"
      << "\n# | la valeur de la condition limite )  on a donc une liste de nom de fonction de charge encadree par 2 mots cle   |"
      << "\n# | la premiere fonction de charge s'applique sur la condition, la deuxieme sur le coefficient 1, la ieme sur le   |"
      << "\n# | coefficient i-1. La liste des  noms des fct de charge s'indique sur la ligne qui suit                          |"
      << "\n# | ex1 deb_fonction_de_charge= chc ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch9 fin_list_fonctions_de_charges_             |"
      << "\n#........................................................................................................................."
      << "\n# exemple complet"
      << "\n   nom_mail= solide1  N_avant  enu= UX  "
      << "\n      refs_associe= nom_mail= solide2 N_arriere N_milieu  fin_list_refs_associe_   TEMPS_MINI= 0.1   TEMPS_MAXI=  5.    "  
      << "\n      val_condi_lineaire=  10   coefficients= 1 2 3 4 5 6 7 8 9   fin_list_coefficients_  AvecFonctionsDeCharges_ "
      << "\n      deb_fonction_de_charge= chc ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch9 fin_list_fonctions_de_charges_  "
      << "\n#........................................................................................................................."
     << endl;
                   }
                 case 2:  // informations succinctes a l'écran
                   { cout << "\n cas particulier 1 : CLL: proj sur plan en 3D (droite en 2D) "
                          << " --> permet de construire les parametres d'une CLL a partir de la "
                          << " def d'un plan de projection en 3D (ou d'une droite de projection pour le 2D)"
                          << "\n ** warning ** un noeud qui supporte une CLL de projection ne peut pas supporter une autre"
                          << " condition : CL ou CLL !!! ";
                     cout << "\n cas particulier 2 : stricte_egalite_ : c-a-d stricte egalite entre ddl de type enu  "
                          << " --> aucune donnee supplementaire n'est necessaire apres le mot cle stricte_egalite_ "
                          << "\n ** warning ** contrairement aux autres cas : un noeud qui supporte une CLL stricte "
                          << "\n egalite peut egalement supporter une autre condition : CL ou CLL !!! ";
                     cout << "\n CLL: generale --> permet de construire une relation lineaire quelconque entre "
                          << " les ddl d'un ou plusieurs noeuds. Contrairement aux CLL de projection, un noeud peut"
                          << " supporter autant de CL et/ou de CLL qu'il a de ddl libres (mais pas plus sinon une "
                          << " erreur est generee ) "
                          << endl;
                     break;
                   }
                 case 3:  // CLL: proj sur plan en 3D (droite en 2D)
                   { type_CLL = 1; rep = "f"; break;}
                 case 4:  // CLL: generale
                   { type_CLL = 2; rep = "f";break;}
                 case 5:  // CLL: stricte_egalite_
                   { type_CLL = 3; rep = "f";break;}
                 default:
                   cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
               };
            };
         }
        catch (ErrSortieFinale)
             // cas d'une direction voulue vers la sortie
             // on relance l'interuption pour le niveau supérieur
           { ErrSortieFinale toto;
             throw (toto);
           }
        catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
         {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                 << "\n redonnez une bonne valeur"
                 << "\n ou taper f ou 0 pour sortir "; 
         };
       }; //-- fin du while
     sort << flush;
   };
  
   //maintenant on va renseigner les CLL en fonction du choix effectué
   int dim = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dim--;
   if ((type_CLL == 1) && ( dim != 1))
    {//On va proposer un menu
     string rep=" ";
     string nom_courbe="_";
     double temps_mini = - ConstMath::trespetit;
     double temps_maxi =  ConstMath::tresgrand;
     Coordonnee M(dim); // coordonnées d'un point fixe du plan ou droite
     string nom_mail_centre=" "; // éventuellement
     int numNoeud_0=0; // ou numéro du noeud du plan a t= 0
     int numNoeud_t=0; // ou numéro du noeud du plan a t
     int type_point=0; // =1 pt fixe, =2 noeud initial, =3 noeud final
     Coordonnee N(0); // coordonnées de la normale du plan ou droite
     Tableau <string> tab_Co_charges; // tableau des noms de fonctions de charges
     // tableau des choix possibles
     Tableau <string> tab_choix(9);
     tab_choix(1) =  "\n (0 ou f)  (fin)               ";
     tab_choix(2) =  "\n (1) reference des noeuds ";
     tab_choix(3) =  "\n (2) def d'1 pt fixe du plan via coordonnees ";
     tab_choix(4) =  "\n (3) ou def d'1 pt fixe du plan = noeud a t=0 ";
     tab_choix(5) =  "\n (4) ou def d'1 pt mobile du plan = noeud a tdt ";
     tab_choix(6) =  "\n (5) normale au plan  ";
     tab_choix(7) =  "\n (6) temps mini ";
     tab_choix(8) =  "\n (7) temps maxi ";
     tab_choix(9) =  "\n (8) def fonctions de charge ";
     string nom_ref="";
     ostringstream  flux;
 
     while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
      {
       try 
        { for (int i=1;i<=tab_choix.Taille();i++)
             cout << tab_choix(i);
          cout << "\n >>>  il faut obligatoirement definir (1)+{(2)ou(3)ou(4)}+(5) <<< ";
          cout << "\n rep : ";
          rep = lect_return_defaut(false,"f"); cout << " grandeur lue " << rep;
          if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie
            // c'est à la sortie que ce fait l'écriture donc ici
            {sort << "\n";
             if ((nom_ref == " ")||(type_point==0)||(N.Dimension()==0))
               {cout <<"\n ** CLL incomplete, pas d'ecriture ";
                break;
               };
             if (plusieurs_maillages)
               { cout << "\n nom du maillage ? ";
                 string nom_mail;
                 nom_mail= lect_chaine(); cout << " nom lu = "<< nom_mail;
                 sort << "nom_mail= "<< nom_mail << " ";
               };
             sort << nom_ref <<" enu= X1 ";
             // temps mini et maxi éventuel
             if ((temps_mini != - ConstMath::trespetit)||(temps_maxi != ConstMath::tresgrand))
              {sort << "\n";
               if (temps_mini != (- ConstMath::trespetit))
                sort << " TEMPS_MINI= "<< temps_mini<<" ";
               if (temps_maxi != ConstMath::tresgrand)
                sort << " TEMPS_MAXI= "<< temps_maxi<<" ";
              };
             // la condition
             sort << "\n  def_auto_coef_planOuDroite_ ";
             switch (type_point)
              { case 1: sort << " centre_fixe_  "; M.Affiche_1(sort);break;
                case 2: sort << " centre_noeud_a_t0_ " << nom_mail_centre << numNoeud_0; break;
                case 3: sort << " centre_noeud_a_t_ " << nom_mail_centre << numNoeud_t; break;
              };
             // les coefficients
             sort << " coefficients= "; N.Affiche_1(sort);
             sort << " fin_list_coefficients_ ";
             // fonctions de charge éventuelles
             if (tab_Co_charges.Taille() != 0)
              {sort << "  AvecFonctionsDeCharges_ \n deb_fonction_de_charge=  ";
               for (int i=1;i<=tab_Co_charges.Taille();i++)
                 sort << tab_Co_charges(i) << " ";
               sort << " fin_list_fonctions_de_charges_ "<< endl;
              };
             break;
            };
          int num = ChangeEntier(rep);
          bool choix_valide=false;
          if ((num >= 0)&&(num<=8))
               { choix_valide=true; }
          else { cout << "\n Erreur on attendait un entier entre 0 et 8 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper f ou 0 pour arreter le programme";
                 choix_valide=false;
               }
          switch (num)
           { case 0:  // sortie
               { break;}
             case 1:  // reference des noeuds
               { cout << "\n nom de la ref de noeud pour l'application de la condition ? ";
                 nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
                 if (nom_ref.at(0) != 'N')
                  {cout << "\n *** erreur, la premiere lettre de la ref de noeuds "
                        << " doit etre N et non "<< nom_ref.at(0)<< " !! *** "
                        << " \n ** cette ref n'est pas valide !! ** \n ";
                   nom_ref = " "; // on re init
                   break;
                  };
                 break;
               }
             case 2:  // def d'1 pt fixe du plan via coordonnees
               { if (type_point != 0)
                   cout << "\n ** warning vous definissez un nouveau point du plan  "
                        << " qui va donc remplasser votre precedent point  ";
               
                 switch (dim)
                   {case 3:
                      {cout << "\n def d'un pt du plan via la def de ses coordonnees:  ";
                       // comme on a plusieurs entrée on va utiliser un cin
                       cout << "\n donner 3 reels "; for (int i=1;i<4;i++) cin >> M(i);
                       type_point=1; cout << " valeurs lue =";M.Affiche();
                       std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// vide cin
                       break;
                      }
                    case 2:
                       // comme on a plusieurs entrée on va utiliser un cin
                      {cout << "\n donner 2 reels "; for (int i=1;i<3;i++) cin >> M(i);
                       type_point=1; cout << " valeurs lue =";M.Affiche();
                       std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// vide cin
                       break;
                      }
                    default: choix_valide=false; break;
                   };
                 break;
                }
             case 3:  // ou def d'1 pt fixe du plan = noeud a t=0
               { if (type_point != 0)
                   cout << "\n (** warning vous definissez un nouveau point du plan  "
                        << " qui va donc remplasser votre precedent point)  ";
               
                 cout << "\n def numero du noeud dont la position initiale sera un point du plan"
                      << "\n numero ? : ";
                 numNoeud_0 = (int) lect_double();cout << " valeur lue ="<< numNoeud_0;
                 if (plusieurs_maillages)
                   { cout << "\n nom du maillage associe ? ";
                     string nom_mail_centre;
                     nom_mail_centre= lect_chaine(); cout << " nom lu = "<< nom_mail_centre;
                   };
                 type_point=2;
                 break;
                }
             case 4:  //ou def d'1 pt mobile du plan = noeud a tdt
               { if (type_point != 0)
                   cout << "\n (** warning vous definissez un nouveau point du plan  "
                        << " qui va donc remplasser votre precedent point) ";
               
                 cout << "\n def numero du noeud dont la position finale sera un point du plan "
                      << "\n numero ? : ";
                 numNoeud_t=(int)lect_double();cout << " valeur lue ="<< numNoeud_t;
                 if (plusieurs_maillages)
                   { cout << "\n nom du maillage associe ? ";
                     string nom_mail_centre;
                     nom_mail_centre= lect_chaine(); cout << " nom lu = "<< nom_mail_centre;
                   };
                 type_point=3;
                 break;
                }
             case 5:  // def normale au plan
               { cout << "\n normale au plan (ou droite) ? ";
                 N.Change_dim(dim);
                 switch (dim)
                   {case 3:
                      {cout << "\n donner 3 reels "; for (int i=1;i<4;i++) cin >> N(i);
                       cout << " valeurs lue =";N.Affiche();
                       std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );//on vide cin
                       break;
                      }
                    case 2:
                      {cout << "\n donner 2 reels "; for (int i=1;i<3;i++) cin >> N(i);
                       cout << " valeurs lue =";N.Affiche();
                       std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );//on vide cin
                       break;
                      }
                    default:
                      cout << "\n en 1D les CLL de projection ne sont pas possible ";
                      choix_valide=false; break;
                   };
                 break;
               }
             case 6:  // temps mini
                { cout << "\n valeur du temps mini (un reel)  ? ";
                 temps_mini=lect_double();cout << " valeur lue ="<< temps_mini;
                 break;
                }
             case 7:  // temps maxi
                { cout << "\n valeur du temps maxi (un reel)  ? ";
                  temps_maxi=lect_double();cout << " valeur lue ="<< temps_maxi;
                  break;
                }
             case 8:  // def des courbes de charges
               { tab_Co_charges.Change_taille(dim);
                 cout << "\n il faut definir "<<dim<<"courbes de charge";
                 for (int i=1;i<=dim;i++)
                   {cout << "\n nom de la "<<i<<" ieme courbe de charge  ? ";
                    tab_Co_charges(i)= lect_chaine();cout << " nom lu = "<< tab_Co_charges(i);
                   };
                 break;
                }
             default:
               cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
            };
        }
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
      }; //-- fin du while
 
    }
   else if (type_CLL == 2)
    {//On va proposer un menu
     string rep=" ";
     string nom_courbe="_";
     double temps_mini = - ConstMath::trespetit;
     double temps_maxi =  ConstMath::tresgrand;
     Coordonnee M(dim); // coordonnées d'un point fixe du plan ou droite
     string nom_mail_centre=" "; // éventuellement
     Coordonnee N(0); // coordonnées de la normale du plan ou droite
     
     Enum_ddl enu=NU_DDL; // enuméré des ddl de la cll
     double val_condi=0.; // valeur par défaut de la condition linéaire
     list <string> list_ref_secondaires; // liste des références secondaires
     list <string> list_mail_secondaires; // la liste des maillages associées à list_ref_secondaires
     Tableau <double> tab_coef_CLL; // tableau des coef de la CLL
     Tableau <string> tab_Co_charges; // tableau des noms de fonctions de charges
     bool condition_relative = false; // par défaut
     // tableau des choix possibles
     Tableau <string> tab_choix(11);
     tab_choix(1) =  "\n (0 ou f)  (fin)               ";
     tab_choix(2) =  "\n (1) reference principale de noeuds ";
     tab_choix(3) =  "\n (2) references secondaires de noeuds ";
     tab_choix(4) =  "\n (3) type de degre de liberte ";
     tab_choix(5) =  "\n (4) valeur de la CLL ";
     tab_choix(6) =  "\n (5) coefficients de la CLL ";
     tab_choix(7) =  "\n (6) condition relative  ";
     tab_choix(8) =  "\n (7) temps mini ";
     tab_choix(9) =  "\n (8) temps maxi ";
     tab_choix(10) =  "\n (9) def fonctions de charge ";
     tab_choix(11) =  "\n (10) test si la CLL est recevable ";
     string nom_ref="";
     ostringstream  flux;
 
     while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
      {
       try 
        { for (int i=1;i<=tab_choix.Taille();i++)
             cout << tab_choix(i);
          cout << "\n >>>  il faut obligatoirement definir a minima (1)+(3)+(4)+(5) <<< "
               << "\n      et de preference dans l'ordre indique ";
          cout << "\n rep : ";
          rep = lect_return_defaut(false,"f"); cout << " grandeur lue " << rep;
          if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie
            // c'est à la sortie que ce fait l'écriture donc ici
            {sort << "\n";
             int nb_val = (dim*(list_ref_secondaires.size()+1));
             if ((nom_ref == " ")||(tab_coef_CLL.Taille()!=nb_val)
                 ||((tab_Co_charges.Taille()!=0)&&(tab_Co_charges.Taille()!=nb_val))
                )
               {cout <<"\n ** CLL incomplete, pas d'ecriture ";
                break;
               };
             if (plusieurs_maillages)
               { cout << "\n nom du maillage pour la ref principale ? ";
                 string nom_mail;
                 nom_mail= lect_chaine(); cout << " nom lu = "<< nom_mail;
                 sort << "nom_mail= "<< nom_mail << " ";
               };
             sort << nom_ref <<" enu= " << Nom_ddl(enu);
             // références secondaires éventuelles et / ou
             // temps mini et maxi éventuel
             if ( ((temps_mini != - ConstMath::trespetit)||(temps_maxi != ConstMath::tresgrand))
                 || (list_ref_secondaires.size() != 0))
              {sort << "\n";
               // les ref secondaires
               if (list_ref_secondaires.size() != 0)
                {list <string>::iterator ideb = list_ref_secondaires.begin();
                 list <string>::iterator idfin = list_ref_secondaires.end();
                 list <string>::iterator ill = list_mail_secondaires.begin();
                 sort << " refs_associe= ";
                 if (plusieurs_maillages)
                  {for (;ideb != idfin;ideb++, ill++)
                     sort << "nom_mail= "<< (*ill) << "  " << (*ideb) << " ";
                  }
                 else
                  {for (;ideb != idfin;ideb++, ill++)
                     sort << (*ideb) << " ";
                  };
                 sort << " fin_list_refs_associe_ ";
                };
               // encadrement en temps
               if (temps_mini != (- ConstMath::trespetit))
                sort << " TEMPS_MINI= "<< temps_mini<<" ";
               if (temps_maxi != ConstMath::tresgrand)
                sort << " TEMPS_MAXI= "<< temps_maxi<<" ";
               // le cas d'une condition relative ou pas
               if (condition_relative)
                 sort << " CONDITION_RELATIVE= 1 ";
              };
             // la condition
             sort << "\n  val_condi_lineaire=  " << val_condi << " coefficients= ";
             // les coefficients
             for (int i=1;i<=nb_val;i++)
               sort << tab_coef_CLL(i) << " ";
             sort << " fin_list_coefficients_ ";
             // fonctions de charge éventuelles
             if (tab_Co_charges.Taille() != 0)
              {sort << "  AvecFonctionsDeCharges_ \n deb_fonction_de_charge=  ";
               for (int i=1;i<=tab_Co_charges.Taille();i++)
                 sort << tab_Co_charges(i) << " ";
               sort << " fin_list_fonctions_de_charges_ ";
              };
             sort << endl << std::flush;
             break;
            };
          int num = ChangeEntier(rep);
          bool choix_valide=false;
          if ((num >= 0)&&(num<=10))
               { choix_valide=true; }
          else { cout << "\n Erreur on attendait un entier entre 0 et 8 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper f ou 0 pour arreter le programme";
                 choix_valide=false;
               }
          switch (num)
           { case 0:  // sortie
               { break;}
             case 1:  // reference principale de noeuds
               { cout << "\n nom de la ref de noeud pour l'application de la condition ? ";
                 nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
                 if (nom_ref.at(0) != 'N')
                  {cout << "\n *** erreur, la premiere lettre de la ref de noeuds "
                        << " doit etre N et non "<< nom_ref.at(0)<< " !! *** "
                        << " \n ** cette ref n'est pas valide !! ** \n ";
                   nom_ref = " "; // on re init
                   break;
                  };
                 break;
               }
             case 2:  // references secondaires de noeuds
               {  bool fin = false;
                  string nom_ref_inter=" ";
                  while (!fin)
                    { cout << "\n nom d'une ref de noeud secondaire ou f (ou 0 ou o) pour finir ? ";
                      nom_ref_inter= lect_chaine();cout << " nom lu = "<< nom_ref_inter;
                      if ((Minuscules(nom_ref_inter) == "f")||(Minuscules(nom_ref_inter)=="o") ||(Minuscules(nom_ref_inter)=="0"))
                         {break;}
                      else if (nom_ref_inter.at(0) != 'N')
                        {cout << "\n *** erreur, la premiere lettre de la ref de noeuds "
                              << " doit etre N et non "<< nom_ref_inter.at(0)<< " !! *** "
                              << " \n ** cette ref n'est pas valide !! ** \n ";
                         nom_ref_inter = " "; // on re init
                        }
                      else
                        { if (plusieurs_maillages)
                            { cout << "\n nom du maillage associe ? ";
                              string nom_mail_associe;
                              nom_mail_associe= lect_chaine(); cout << " nom lu = "<< nom_mail_associe;
                              list_mail_secondaires.push_back(nom_mail_associe);
                            };
                          list_ref_secondaires.push_back(nom_ref_inter);
                        };
                    };
                   break;
               }
             case 3:  // type de degre de liberte
               { cout << "\n type d'un ddl de la condition lineaire: (ex: UX ou UY ou X1 ou V1 ...): ";
                 string enu_essai;
                 enu_essai= lect_chaine();cout << " valeur lue ="<<enu_essai;
                 if (ExisteEnum_ddl(enu_essai))
                  { if (Id_nom_ddl(enu_essai) != NU_DDL)
                      {enu = PremierDdlFamille(Id_nom_ddl(enu_essai));}
                    else {cout << "*** type de ddl non valide !! " << endl;};
                  }
                 else {cout << "*** type de ddl non valide !! " << endl;};
                 break;
               }
             case 4:  // valeur de la CLL
               { cout << "\n valeur de condition lineaire: (un reel): ";
                 val_condi=lect_double();cout << " valeur lue ="<< val_condi;
                 break;
                }
             case 5:  // coefficients de la CLL
               { cout << "\n avertissement: le nombre de coefficient doit etre identique a la dimension "
                      << " * (le nombre de ref secondaire + 1) , ici cf. vos precedentes reponses, il faut donc "
                      << "\n "<<dim<<" * ("<<list_ref_secondaires.size()<<"+ 1) = "
                      << (dim*(list_ref_secondaires.size()+1)) ;
                 int nb_val = (dim*(list_ref_secondaires.size()+1));
                 tab_coef_CLL.Change_taille(nb_val);
                 for (int i=1;i<= nb_val;i++)
                   { cout << "\n coefficient ("<<i<<")= ? ";cin >> tab_coef_CLL(i);
                     cout << " ( valeur lue : "<<tab_coef_CLL(i) << ") "<< endl;
                   };
                 std::cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );// on vide cin
                 break;
               }
             case 6:  // condition relative
               { string reponse;
                 cout << "\n condition relative (rep: o ou n ) ? ";
                 reponse = lect_o_n(false);
                 cout << " (valeurs lue = "<<reponse<<") "<<endl;
                 if (Minuscules(reponse) == "o") { condition_relative=true;}
                 else {condition_relative = false;};
                 break;
               }
             case 7:  // temps mini
                { cout << "\n valeur du temps mini (un reel)  ? ";
                  temps_mini=lect_double();cout << " valeur lue ="<< temps_mini;
                  break;
                }
             case 8:  // temps maxi
                { cout << "\n valeur du temps maxi (un reel)  ? ";
                  temps_maxi=lect_double();cout << " valeur lue ="<< temps_maxi;
                  break;
                }
             case 9:  // def des courbes de charges
               { int nb_val = tab_coef_CLL.Taille();
                 tab_Co_charges.Change_taille(nb_val);
                 cout << "\n compte tenu de vos precedentes reponses il faut definir "<<nb_val<<" courbes de charge";
                 for (int i=1;i<=nb_val;i++)
                   {cout << "\n nom de la "<<i<<" ieme courbe de charge  ? ";
                    tab_Co_charges(i)= lect_chaine();cout << " nom lu = "<< tab_Co_charges(i);
                   };
                 break;
                }
             case 10:  // test si la CLL est recevable
               { int nb_val = (dim*(list_ref_secondaires.size()+1));
                 if (nom_ref == " ")
                   {cout <<"\n ** CLL incomplete, il manque le nom de la reference principale " << endl;}
                 else if (tab_coef_CLL.Taille()!=nb_val)
                   {cout <<"\n ** CLL incomplete, le nombre de coef n'est pas coherent avec le nb de "
                        <<"ref et la dimension " << endl;}
                 else if ((tab_Co_charges.Taille()!=0)&&(tab_Co_charges.Taille()!=nb_val))
                   {cout <<"\n ** CLL incomplete, le nombre de courbe de charge n'est pas coherent avec le nb de "
                        <<"ref et la dimension " << endl;}
                 else if (temps_mini > temps_maxi)
                   {cout <<"\n ** CLL complete mais inchoerente car le temps mini ("<<temps_mini<<") est "
                         << "superieur au temps maxi ("<<temps_maxi<<") "<< endl;}
                 else {cout << "\n a priori la condition est coherente et recevable "<<endl;};
                 break;
                }
             default:
               cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
            };
        }
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
      }; //-- fin du while
 
    }
   else if (type_CLL == 3)
    {//On va proposer un menu
     string rep=" ";
     double temps_mini = - ConstMath::trespetit;
     double temps_maxi =  ConstMath::tresgrand;
     Enum_ddl enu=NU_DDL; // enuméré des ddl de la cll
     list <string> list_ref_secondaires; // liste des références secondaires
     list <string> list_mail_secondaires; // la liste des maillages associées à list_ref_secondaires
     bool condition_relative = false; // par défaut
     // tableau des choix possibles
     Tableau <string> tab_choix(7);
     tab_choix(1) =  "\n (0 ou f)  (fin)               ";
     tab_choix(2) =  "\n (1) reference principale de noeuds ";
     tab_choix(3) =  "\n (2) references secondaires de noeuds ";
     tab_choix(4) =  "\n (3) type de degre de liberte ";
     tab_choix(5) =  "\n (4) temps mini ";
     tab_choix(6) =  "\n (5) temps maxi ";
     tab_choix(7) =  "\n (6) test si la CLL est recevable ";
     string nom_ref="";
     ostringstream  flux;
 
     while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
      {
       try 
        { for (int i=1;i<=tab_choix.Taille();i++)
             cout << tab_choix(i);
          cout << "\n >>>  il faut obligatoirement definir a minima (1)+(2) <<< "
               << "\n      et de preference dans l'ordre indique ";
          cout << "\n rep : ";
          rep = lect_return_defaut(false,"f"); cout << " grandeur lue " << rep;
          if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie
            // c'est à la sortie que ce fait l'écriture donc ici
            {sort << "\n";
             if ((nom_ref == " ")||(list_ref_secondaires.size()==0)
                )
               {cout <<"\n ** CLL incomplete, pas d'ecriture ";
                break;
               };
             if (plusieurs_maillages)
               { cout << "\n nom du maillage pour la ref principale ? ";
                 string nom_mail;
                 nom_mail= lect_chaine(); cout << " nom lu = "<< nom_mail;
                 sort << "nom_mail= "<< nom_mail << " ";
               };
             sort << nom_ref <<" enu= " << Nom_ddl(enu);
             // références secondaires éventuelles et / ou
             // temps mini et maxi éventuel
             if ( ((temps_mini != - ConstMath::trespetit)||(temps_maxi != ConstMath::tresgrand))
                 || (list_ref_secondaires.size() != 0))
              {sort << "\n";
               // les ref secondaires
               if (list_ref_secondaires.size() != 0)
                {list <string>::iterator ideb = list_ref_secondaires.begin();
                 list <string>::iterator idfin = list_ref_secondaires.end();
                 list <string>::iterator ill = list_mail_secondaires.begin();
                 sort << " refs_associe= ";
                 if (plusieurs_maillages)
                  {for (;ideb != idfin;ideb++, ill++)
                     sort << "nom_mail= "<< (*ill) << "  " << (*ideb) << " ";
                  }
                 else
                  {for (;ideb != idfin;ideb++, ill++)
                     sort << (*ideb) << " ";
                  };
                 sort << " fin_list_refs_associe_ ";
                };
               // encadrement en temps
               if (temps_mini != (- ConstMath::trespetit))
                sort << " TEMPS_MINI= "<< temps_mini<<" ";
               if (temps_maxi != ConstMath::tresgrand)
                sort << " TEMPS_MAXI= "<< temps_maxi<<" ";
               // le cas d'une condition relative ou pas
               if (condition_relative)
                 sort << " CONDITION_RELATIVE= 1 ";
              };
             // la condition
             sort << "\n  stricte_egalite_  " ;
             sort << endl << std::flush;
             break;
            };
          int num = ChangeEntier(rep);
          bool choix_valide=false;
          if ((num >= 0)&&(num<=6))
               { choix_valide=true; }
          else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
                      << "\n redonnez une bonne valeur"
                      << "\n ou taper f ou 0 pour arreter le programme";
                 choix_valide=false;
               }
          switch (num)
           { case 0:  // sortie
               { break;}
             case 1:  // reference principale de noeuds
               { cout << "\n nom de la ref de noeud pour l'application de la condition ? ";
                 nom_ref= lect_chaine();cout << " nom lu = "<< nom_ref;
                 if (nom_ref.at(0) != 'N')
                  {cout << "\n *** erreur, la premiere lettre de la ref de noeuds "
                        << " doit etre N et non "<< nom_ref.at(0)<< " !! *** "
                        << " \n ** cette ref n'est pas valide !! ** \n ";
                   nom_ref = " "; // on re init
                   break;
                  };
                 break;
               }
             case 2:  // references secondaires de noeuds
               {  bool fin = false;
                  string nom_ref_inter=" ";
                  while (!fin)
                    { cout << "\n nom d'une ref de noeud secondaire ou f (ou 0 ou o) pour finir ? ";
                      nom_ref_inter= lect_chaine();cout << " nom lu = "<< nom_ref_inter;
                      if ((Minuscules(nom_ref_inter) == "f")||(Minuscules(nom_ref_inter)=="o") ||(Minuscules(nom_ref_inter)=="0"))
                         {break;}
                      else if (nom_ref_inter.at(0) != 'N')
                        {cout << "\n *** erreur, la premiere lettre de la ref de noeuds "
                              << " doit etre N et non "<< nom_ref_inter.at(0)<< " !! *** "
                              << " \n ** cette ref n'est pas valide !! ** \n ";
                         nom_ref_inter = " "; // on re init
                        }
                      else
                        { if (plusieurs_maillages)
                            { cout << "\n nom du maillage associe ? ";
                              string nom_mail_associe;
                              nom_mail_associe= lect_chaine(); cout << " nom lu = "<< nom_mail_associe;
                              list_mail_secondaires.push_back(nom_mail_associe);
                            };
                          list_ref_secondaires.push_back(nom_ref_inter);
                        };
                    };
                   break;
               }
             case 3:  // type de degre de liberte
               { cout << "\n type d'un ddl de la condition lineaire: (ex: UX ou UY ou X1 ou V1 ...): ";
                 string enu_essai;
                 enu_essai= lect_chaine();cout << " valeur lue ="<<enu_essai;
                 if (ExisteEnum_ddl(enu_essai))
                  { if (Id_nom_ddl(enu_essai) != NU_DDL)
                      {enu = PremierDdlFamille(Id_nom_ddl(enu_essai));}
                    else {cout << "*** type de ddl non valide !! " << endl;};
                  }
                 else {cout << "*** type de ddl non valide !! " << endl;};
                 break;
               }
             case 4:  // temps mini
                { cout << "\n valeur du temps mini (un reel)  ? ";
                  temps_mini=lect_double();cout << " valeur lue ="<< temps_mini;
                  break;
                }
             case 5:  // temps maxi
                { cout << "\n valeur du temps maxi (un reel)  ? ";
                  temps_maxi=lect_double();cout << " valeur lue ="<< temps_maxi;
                  break;
                }
             case 6:  // test si la CLL est recevable
               { if (nom_ref == " ")
                   {cout <<"\n ** CLL incomplete, il manque le nom de la reference principale " << endl;}
                 else if (list_ref_secondaires.size()==0)
                   {cout <<"\n ** CLL incomplete, il n'y a pas de liste secondaire "
                        <<"ref et la dimension " << endl;}
                 else if (temps_mini > temps_maxi)
                   {cout <<"\n ** CLL complete mais inchoerente car le temps mini ("<<temps_mini<<") est "
                         << "superieur au temps maxi ("<<temps_maxi<<") "<< endl;}
                 else {cout << "\n a priori la condition est coherente et recevable "<<endl;};
                 break;
                }
             default:
               cout << "\n le cas "<<rep<<" n'est pas  traite !!, bizarre, il faut se plaindre !! ";
            };
        }
       catch (ErrSortieFinale)
            // cas d'une direction voulue vers la sortie
            // on relance l'interuption pour le niveau supérieur
          { ErrSortieFinale toto;
            throw (toto);
          }
       catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
        {  cout << "\n Erreur on attendait un des mots cles proposes !!, "
                << "\n redonnez une bonne valeur"
                << "\n ou taper f ou 0 pour sortir "; 
        };
      }; //-- fin du while
 
    }
   else if ((type_CLL == 1) && (dim == 1))
    { // cas particulier du 1D
      cout << "\n *** en 1D les CLL de projection ne sont pas possibles ";
    };
  };

    
// Construction de la condition : 1) mise en place d'une valeur imposée due à la condition linéaire 
// def des coefficients en fonction éventuellement des fonctions de charges et du  paramètre condition_relative
// NB: pour les conditions correspondant à une projection sur un plan ou une droite, il faut que la direction du plan
//     ou de la droite ait déjà été affecté auparavant
// !! la condition sur le ddl n'est pas imposée à ce niveau, par contre elle est stockée dans Condilineaire

Condilineaire& I_O_Condilineaire::ConstructionCondition
               (Tableau <Noeud *> & t_noe,Condilineaire& condi_actuelle)
{ // tout d'abord on évacue le cas de l'égalité stricte qui implique : rien n'a faire !
  if (stricte_egalite)
    return condi_actuelle; // condi_actuelle inchangée et ne doit servir à rien

  // on renseigne la condition
  Noeud * noe = t_noe(1); // le premier noeud est celui où on met la condition
  condi_actuelle.ChangeTabNoeud(t_noe); // on renseigne la condition
 
  // dimensionnement de la condition de retour, car val peut avoir été changé indépendamment
  condi_actuelle.Change_taille(val.Taille()); 
  Vecteur val_inter(val); // le vecteur qui contient les coeffs, est utiliser car dans le cas
                          // d'une def auto droite plan,  les coeffs sont récupéré donc modifié
  
  if (def_auto_par_rotation)
  	{ // cas d'une définition par rapport à une droite ou un plan
  	  // on récupère les valeurs qui ont été calculées au moment des projections
	    int dima = ParaGlob::Dimension();
     if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
	    // la valeur de la condition a déjà été calculée au moment de la projection
	    switch (dima)
        {case 2: // on tourne autour de z
           { val_inter(1) = -dr.VecDroite()(2);
             val_inter(2) = dr.VecDroite()(1);
             break;
           }
         case 3: 
           { val_inter = (pl.Vecplan()).Vect(); // pour simplifier
       	        break;
           }
        };
  	};
   
  // --- on met la condition ----- 
  if ((tab_co_charge.Taille() == 0) || def_auto_par_rotation)
     // cas sans fonction de charge, on applique la valeur complète
	 // dans le cas d'une projection plan ou droite, l'échelle est systématiquement = 1. (vérif à la lecture) 
	 // et on ne tient pas compte de la première fonction de charge 
  	 { condi_actuelle.BetaChange() = echelle * beta  ;}
  else
     // cas avec fonction de charge, que ce soit en relatif ou pas, on applique la valeur à t
     // (le coté relatif est a appliqué au niveau des ddl des noeuds, qui sont des valeurs issues
     //  du calcul d'équilibre, et non au niveau des valeurs fixés qui elles peuvent être déterminées
     // à l'avance, donc pour ces dernières aucun intérêts de faire du relatif, par contre pour les ddl
     // des noeuds, là le coté relatif est important car il permet d'ajouter à un ddl dont la valeur
     // est issue du précédent calcul, donc pas connue à l'avance)
  	  { condi_actuelle.BetaChange() = echelle * beta  *  fctch(1) ;};

  // --- maintenant on s'occupe des pointeurs et des coefficients
  double valfinalSurddlAbloquer = 0; // on calcul en même temps la valeur à imposer 
  Tableau <Enum_ddl > t_enu(val.Taille()); // tableau des identificateur de ddl de la CLL
  
  // $-$ NB:  on traite différemment selon qu'il s'agisse de conditions linéaires entre position ou déplacement,
  // $-$  ou sur des autres ddl, because, le cas déplacement-position est un peu particulier mais cependant
  // $-$  globalement c'est très ressemblant
  
  if (Meme_famille(enu,X1) || Meme_famille(enu,UX))
    { // le premier indice correspondra a la direction bloquee, il faut s'assurer qu'il ne 
      // soit pas nul et qu'il ne correspond pas a une direction deja bloquee par les conditions
      // limites de depart
      // on boucle sur la dim pour trouver le coef le plus grand correspondant a une direction
      // non bloquee
      int dima = ParaGlob::Dimension();
      if(ParaGlob::AxiSymetrie())
        // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
        // dimension-1 coordonnées donc on décrémente
        dima--;
      int iti=0;int indi = 0; double maxi = ConstMath::petit;
      int posi = Id_nom_ddl("X1") -1; // position du ddl X1
      // on cherche le numero de ddl libre qui est associé à la valeur maxi différente de 0
      if ((!def_auto_par_rotation)&&(tab_co_charge.Taille() != 0))
        // dans le cas normal, avec fonction de charge, on tiens compte de ces fonctions
        {for (iti=1; iti<= dima; iti++)
          { if (!noe->Ddl_fixe(Enum_ddl(posi+iti))) // cas d'un ddl libre
             {double coef_reel = Dabs(val_inter(iti) * fctch(iti+1));
              if (coef_reel > maxi) // cas d'une valeur de coefficient non nul
                { maxi = coef_reel;
                  indi = iti;
                 };
             }
          };
        }
      else
        // autres cas: cas des projections ou cas sans fonction de charge
        {for (iti=1; iti<= dima; iti++)
          { if (!noe->Ddl_fixe(Enum_ddl(posi+iti))) // cas d'un ddl libre
              if (Dabs(val_inter(iti)) > maxi) // cas d'une valeur de coefficient non nul
                { maxi = Dabs(val_inter(iti)); 
                  indi = iti;
                 };
          };
        };
      if (indi ==0)
         { // cas ou soit les dima ddl sont bloque, soit le vecteur normal = 0
           cout << "\n erreur dans une condition limite lineaire , on ne peut pas imposer de condition lineaire" 
                << " car soit les  ddl de deplacement du noeud principal de la condition sont deja tous bloque, "
                << " soit le vecteur condition (les coeffs) est nul \n";
           noe->Affiche();
           cout << "\n les coeff : " ; val_inter.Affiche();
           cout << "Condilineaire& I_O_Condilineaire::ConstructionCondition(.." << endl;
           Sortie (1);
          };
      // on indique que la nouvelle direction "indi" est bloque, ceci permet
      // pour une autre condition, de ne pas reprendre cette direction
      // --> ce marquage est effacer apres resolution, par la fonction efface blocage
      Enum_ddl leEnuAChanger = Enum_ddl(posi+indi);  // le enu du ddl_k de la condition
      noe->Change_fixe(leEnuAChanger,true);
      condi_actuelle.ChangeIddl() = indi; // on enregistre la position 
      // on avance dans la constitution de  valfinalSurddlAbloquer
      double unsurcoef1 = 1./val_inter(condi_actuelle.Iddl()); // correspond à 1/alph_k de la condition 
      if ((!def_auto_par_rotation)&&(tab_co_charge.Taille() != 0))
         // dans le cas normal, avec fonction de charge, on tiens compte de ces fonctions
         unsurcoef1 = 1./fctch(indi+1);
      // constitution de la condition lineaire
      int itab = 0.; // définit à l'extérieur car va continuer à s'incrémenter sur la deuxième boucle qui suit
      for (itab=1;itab<= dima;itab++)
        { // condi_actuelle.val_inter(1) correspond à coef(indi), puis les autres suivent
          double coefindi =0.;
          if (!def_auto_par_rotation)
    	     { if (tab_co_charge.Taille() == 0)
    	    	         { coefindi = val(indi) ; }
    	       else   { coefindi = val(indi) * fctch(indi+1) ;};
    	     }
    	    else // dans le cas plan droite les coef sont déjà intégrés
    	     {coefindi = val_inter(indi);};
         t_enu(itab)= Enum_ddl(posi+indi); // sauvegarde de l'enum associé
         condi_actuelle.Valchange()(itab) = echelle * coefindi;  // pour le coefficient
//--------------
         // suite constitution de  valfinalSurddlAbloquer :
         if (itab == 1) 
           // correspond à beta/alpha_k 	  
           { valfinalSurddlAbloquer = condi_actuelle.Beta() * unsurcoef1; }
         else 
           // correspond à -alph_i/alph_k * U_i	  
           // il faut distinguer les  cas suivant que c'est une condition linéaire entre Xi ou entre Ui
           // et que l'on est en relatif ou pas 
           { if (condition_relative)
                // dans le cas d'une projection, par construction (vérif à la lecture), la condition  n'est pas relative !!
              { // que ce soit en Xi ou en Ui, comme on est en relatif il  faut considérer l'accroissement
                valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 
// **** a priori une erreur :  23 sep 2014  * (noe->Valeur_tdt(Enum_ddl(posi+itab)) -  noe->Valeur_t(Enum_ddl(posi+itab)) ) ;
                                 * (noe->Valeur_tdt(Enum_ddl(posi+indi)) -  noe->Valeur_t(Enum_ddl(posi+indi)) ) ;
              }
             else 
                   // donc ici il s'agit d'une condition absolue
              { if (Meme_famille(enu,X1))
                  // cas d'une CLL entre Xi on y accède directement
// **** a priori une erreur :  23 sep 2014      { valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 * noe->Valeur_tdt(Enum_ddl(posi+itab)) ;}
                    { valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 * noe->Valeur_tdt(Enum_ddl(posi+indi)) ;
////--debug
//cout << "\n debug I_O_Condilineaire::ConstructionCondition noe_val= " << noe->Valeur_tdt(Enum_ddl(posi+indi))
//     << " valfinalSurddlAbloquer= " << valfinalSurddlAbloquer << " coefindi= " << coefindi << " unsurcoef1= " << unsurcoef1
//     << "Enum_ddl(posi+indi)= " << Enum_ddl(posi+indi) << endl ;
////--fin debug
                    }
                  else
                  // cas d'une CLL entre Ui, il faut donc prendre en compte le delta Xi entre 0 et tdt
                    { valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 
// **** a priori une erreur :  23 sep 2014     * (noe->Valeur_tdt(Enum_ddl(posi+itab)) -  noe->Valeur_0(Enum_ddl(posi+itab)) ) ;
                                      * (noe->Valeur_tdt(Enum_ddl(posi+indi)) -  noe->Valeur_0(Enum_ddl(posi+indi)) ) ;
                    };
              };
           };
//-------------------
         indi ++;
         if (indi > dima) indi = 1;  // on fait une rotation circulaire
		      };
      // cas des noeuds des références secondaires
      int nbnsecondaire = refs_associe.Taille(); 
      for (int nn=2; nn<=nbnsecondaire+1; nn++) // le premier noeud secondaire est pour nn=2
        { Noeud & noese = *(t_noe(nn));
          // récup du pointeur d'assemblage  -1
          #ifdef MISE_AU_POINT	 	 
          if (def_auto_par_rotation)
            { cout << "\nErreur : on ne doit pas avoir de ref secondaire avec la def auto "
                   <<  '\n'
                   << "Condilineaire& I_O_Condilineaire::ConstructionCondition(.. 3\n";
              Sortie(1);
            };
          #endif
          for (int ia=1;ia<= dima;ia++,itab++)
            { double coefitab =0.;
              if (tab_co_charge.Taille() == 0)
    	    	           { coefitab = val_inter(itab) ; }
    	         else   { coefitab = val_inter(itab) * fctch(itab+1) ;};
              t_enu(itab)= Enum_ddl(posi+ia); // sauvegarde de l'enum associé 
    	         condi_actuelle.Valchange()(itab) = echelle * coefitab;  // pour le coefficient
              // suite constitution de  valfinalSurddlAbloquer : correspond à -alph_i/alph_k * U_i 
              // il faut distinguer les  cas suivant que c'est une condition linéaire entre Xi ou entre Ui
              // et que l'on est en relatif ou pas 
              if (condition_relative)
				          // dans le cas d'une projection, par construction (vérif à la lecture), la condition  n'est pas relative !!
              	 { // que ce soit en Xi ou en Ui, comme on est en relatif il  faut considérer l'accroissement
              	   valfinalSurddlAbloquer -=  echelle * coefitab * unsurcoef1 
              	             * (noese.Valeur_tdt(Enum_ddl(posi+ia)) -  noese.Valeur_t(Enum_ddl(posi+ia)) ) ;
                }
              else 
                // donc ici il s'agit d'une condition absolue
                { if (Meme_famille(enu,X1))
                    // cas d'une CLL entre Xi on y accède directement
              	     { valfinalSurddlAbloquer -=  echelle * coefitab * unsurcoef1 * noese.Valeur_tdt(Enum_ddl(posi+ia)) ;}
                  else
                    // cas d'une CLL entre Ui, il faut donc prendre en compte le delta Xi entre 0 et tdt
              	     { valfinalSurddlAbloquer -=  echelle * coefitab * unsurcoef1 
              	                * (noese.Valeur_tdt(Enum_ddl(posi+ia)) -  noese.Valeur_0(Enum_ddl(posi+ia)) ) ;
              		
              	     };
                };
		        		};
        };
      // on met à jour le tableau d'enum de la condition
      condi_actuelle.Change_tab_enum(t_enu);
      
      // on finit le calcul de la valeur du ddl imposé
      if (condition_relative)
      	{ // que ce soit en Xi ou en Ui, comme on est en relatif 
          // comme le ddl au niveau du noeud est Xi, il faut le rajouter
      	  valfinalSurddlAbloquer +=  noe->Valeur_t(leEnuAChanger); 
      	}
      else 
        // donc ici il s'agit d'une condition absolue
        { if (Meme_famille(enu,X1))
            // cas d'une CLL entre Xi on a rien à faire, valfinalSurddlAbloquer est directement = à 
            // la valeur a imposer
      	    { }
          else
            // cas d'une CLL entre Ui, il faut donc prendre en compte le delta Xi entre 0 et tdt
            // comme le ddl au niveau du noeud est Xi, il faut le rajouter
      	    { valfinalSurddlAbloquer +=  noe->Valeur_0(leEnuAChanger);};
        };
       
      // et maintenant on sauvegarde la valeur a bloquer sur le noeud dans la condition linéaire
      // cette condition correspondra au ddl_i' dans le nouveau repèrere qui recevra  la condition bloqué
      // en fait ddl_i sera la seule modification de ddl due à la mise en place de la CLL
      // !!! par contre ce changement de valeur n'est pas à effectuer dans le cas des projections,
      // car dans ce cas, d'une part valfinalSurddlAbloquer doit toujours être à 0 et  d'autre part
      // la valeur des coordonnées est fixées lors de la projection et non ici 	  
      if (!def_auto_par_rotation)
       { condi_actuelle.ChangeUk_impose(valfinalSurddlAbloquer);}
      else 
       { condi_actuelle.ChangeUk_impose(ConstMath::tresgrand);};
/*
		on met en place la condition limite sur le ddl ddl_i du noeud principal
      // qui correspond au ddl_i' dans le nouveau repèrere qui recevra  la condition bloqué
      // en fait ddl_i sera la seule modification de ddl due à la mise en place de la CLL
	  // !!! par contre ce changement de valeur n'est pas à effectuer dans le cas des projections,
	  // car dans ce cas, d'une part valfinalSurddlAbloquer doit toujours être à 0 et  d'autre part
	  // la valeur des coordonnées est fixées lors de la projection et non ici 
      noe->Change_val_tdt(leEnuAChanger,valfinalSurddlAbloquer);  
*/		
		
		
    } // -- fin du cas d'une condition linéaire sur un déplacement ou position
  else  
    { // -- cas d'une famille autre que déplacement ou position
      // (en fait pas de diff mais je préfère pour l'instant séparer les deux )
      // le premier indice correspondra a la direction bloquee, il faut s'assurer qu'il ne 
      // soit pas nul et qu'il ne correspond pas a une direction deja bloquee par les conditions
      // limites de depart
      // on boucle pour trouver le coef le plus grand correspondant a une direction non bloquee
      int iti=0;int indi = 0; double maxi = ConstMath::petit;
      int posi = enu -1; // position du premier ddl de la famille
      // on cherche le nb de ddl libre qui est associé à la valeur maxi différente de 0 
      for (iti=1; iti<= nbddlfamille; iti++)
        { if (!noe->Ddl_noeud_tdt(Enum_ddl(posi+iti)).Fixe()) // cas d'un ddl libre
            if (Dabs(val(iti)) > maxi) // cas d'une valeur de coefficient non nul
              { maxi = Dabs(val(iti)); 
                indi = iti;
               };
        };
      if (indi ==0)
         { // cas ou soit les dima ddl sont bloque, soit le vecteur normal = 0
           cout << "\n erreur dans une condition limite lineaire , " 
                << " soit les ddl de la famille " << Nom_ddl(enu) << " du noeud principal  sont deja tous bloque, "
                << " soit le vecteur condition (les coeffs) est entierement nul \n";
           noe->Affiche();
           cout << "\n les coeff : " ; condi_actuelle.Valchange().Affiche();
           cout << "Condilineaire& I_O_Condilineaire::ConstructionCondition(.." << endl;
           Sortie (1);
         };
      // on indique que la nouvelle direction "indi" est bloque, ceci permet
      // pour une autre condition, de ne pas reprendre cette direction
      // --> ce marquage est effacer apres resolution, par la fonction efface blocage
      Enum_ddl leEnuAChanger = Enum_ddl(posi+indi);  // le enu du ddl_k de la condition  
      noe->Change_fixe(leEnuAChanger,true);
      condi_actuelle.ChangeIddl() = indi; // on enregistre la position 
      // on avance dans la constitution de  valfinalSurddlAbloquer
      double unsurcoef1 = 1./val_inter(condi_actuelle.Iddl()); // correspond à 1/alph_k de la condition 
      // constitution de la condition lineaire
      int itab = 0.; // définit à l'extérieur car va continuer à s'incrémenter sur deuxième boucle qui suit
      for (itab=1;itab<= nbddlfamille;itab++)
        { // condi_actuelle.val(1) correspond à coeff(indi), puis les autres suivent
          double coefindi =0.;
    	    if (tab_co_charge.Taille() == 0)
    	    	   { coefindi = val(indi) ; }
    	    else { coefindi = val(indi) * fctch(indi+1) ;};
         t_enu(itab)= Enum_ddl(posi+indi); // sauvegarde de l'enum associé
    	    condi_actuelle.Valchange()(itab) = echelle * coefindi;  // pour le coefficient
         //--------------
         // suite constitution de  valfinalSurddlAbloquer : 
         if (itab == 1) 
         // correspond à beta/alpha_k 	  
           { valfinalSurddlAbloquer = condi_actuelle.Beta() * unsurcoef1;}
         else 
         // correspond à -alph_i/alph_k * U_i	  
         // il faut distinguer les  cas suivant que c'est une condition linéaire entre Xi ou entre Ui
         // et que l'on est en relatif ou pas 
           { if (condition_relative)
                  // dans le cas d'une projection, par construction (vérif à la lecture), la condition  n'est pas relative !!  
               { // que ce soit en Xi ou en Ui, comme on est en relatif il  faut considérer l'accroissement
                 valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 
// **** a priori une erreur :  23 sep 2014       * (noe->Valeur_tdt(Enum_ddl(posi+itab)) -  noe->Valeur_t(Enum_ddl(posi+itab)) ) ;
                        * (noe->Valeur_tdt(Enum_ddl(posi+indi)) -  noe->Valeur_t(Enum_ddl(posi+indi)) ) ;
               }
             else
               // donc ici il s'agit d'une condition absolue on y accède directement
// **** a priori une erreur :  23 sep 2014   { valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 * noe->Valeur_tdt(Enum_ddl(posi+itab)) ;
               { valfinalSurddlAbloquer -=  echelle * coefindi * unsurcoef1 * noe->Valeur_tdt(Enum_ddl(posi+indi)) ;
               };
           }
         //-------------------
         indi ++;      
         if (indi > nbddlfamille) indi = 1;  // on fait une rotation circulaire
		      };
      // cas des noeuds des références secondaires
      int nbnsecondaire = refs_associe.Taille(); 
      for (int nn=2; nn<=nbnsecondaire+1; nn++) // le premier noeud secondaire est pour nn=2
        { Noeud & noese = *(t_noe(nn));
          for (int ia=1;ia<= nbddlfamille;ia++,itab++)
            {double coefitab =0.;
    	        if (tab_co_charge.Taille() == 0)
							             { coefitab = val(itab) ; }
    	        else   { coefitab = val(itab) * fctch(itab+1) ;};
    	        condi_actuelle.Valchange()(itab) = echelle * coefitab;  // pour le coefficient
             t_enu(itab)= Enum_ddl(posi+ia); // sauvegarde de l'enum associé
             // suite constitution de  valfinalSurddlAbloquer : correspond à -alph_i/alph_k * U_i  
             // il faut distinguer les  cas suivant que c'est une condition linéaire entre Xi ou entre Ui
             // et que l'on est en relatif ou pas 
             if (condition_relative)
              	{ // comme on est en relatif il  faut considérer l'accroissement
              	  valfinalSurddlAbloquer -=  echelle * coefitab * unsurcoef1 
              	             * (noese.Valeur_tdt(Enum_ddl(posi+ia)) -  noese.Valeur_t(Enum_ddl(posi+ia)) ) ;
              	}
             else
               // donc ici il s'agit d'une condition absolue on y accède directement
               { valfinalSurddlAbloquer -=  echelle * coefitab * unsurcoef1 * noese.Valeur_tdt(Enum_ddl(posi+ia)) ;
               };
            };
        };
      // on met à jour le tableau d'enum de la condition
      condi_actuelle.Change_tab_enum(t_enu);  
      
      // on finit le calcul de la valeur du ddl imposé
      if (condition_relative)
      	{ // comme on est en relatif il faut rajouter la valeur à t
      	  valfinalSurddlAbloquer +=  noe->Valeur_t(leEnuAChanger); 
      	};
      // sinon il n'y a rien à faire,  valfinalSurddlAbloquer est directement = à 
      // la valeur a imposer
       
      // et maintenant on sauvegarde la valeur a bloquer sur le noeud dans la condition linéaire
      // qui correspond au ddl_i' dans le nouveau repèrere qui recevra  la condition bloqué
      // en fait ddl_i sera la seul modification de ddl due à la mise en place de la CLL
		    condi_actuelle.ChangeUk_impose(valfinalSurddlAbloquer);

/*
      // et maintenant on met en place la condition limite sur le ddl ddl_i du noeud principal
      // qui correspond au ddl_i' dans le nouveau repèrere qui recevra  la condition bloqué
      // en fait ddl_i sera la seul modification de ddl due à la mise en place de la CLL
      noe->Change_val_tdt(leEnuAChanger,valfinalSurddlAbloquer);  
*/		
		
    };  // -- fin du cas d'une condition linéaire une famille quelconque autre que position et déplacement
      
  // retour
//  //--- debug
//  cout << "\n la condition lineaire : I_O_Condli ";
//  this->Affiche();
//  cout << "\n la condition resultat ";
//  condi_actuelle.Affiche();
//  // fin debug --- 
 
  return condi_actuelle;	
};

// initialisation des grandeurs de travail
void I_O_Condilineaire::Initialisation_condil()
	{Tableau<Enum_ddl> tab_enu = TableauTypeDdlmobileAvecAxi(enu);
  nbddlfamille = tab_enu.Taille();
  if (!stricte_egalite) // dans le cas stricte_egalité il n'y a pas de coef
    {// on vérifie l'adéquation des dimensions
     int ndimvec = nbddlfamille * (1+ refs_associe.Taille()); // nombre total de ddl concerné
     if (ndimvec != val.Taille())
     	{ cout << "\n erreur de dimension: le nombre de coefficient de la condition limite = " << val.Taille()
     	       << " est different du nombre de ddl de la famille concernee " << nbddlfamille << " fois le nombre de noeud "
     	       << " c'est-a-dire (1 + le nombre de ref secondaire) = " << (1+ refs_associe.Taille()) << " ce qui fait: " 
     	       << ndimvec << endl;
     	  Sortie(1);     
     	};
    };
	};  

// definition du noeud: centre rotation
void I_O_Condilineaire::ChangeCentreNoeudRotation( Noeud* noe) 
  {centre_noeud = noe;
   int dima = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;

   switch (dima)
   	{ case 2: switch(type_centre)
   	          	{case 2 : dr.Change_ptref(noe->Coord0()); break;
   	          	 case 3 : dr.Change_ptref(noe->Coord2()); break;
   	          	}
   	          break; 
   	  case 3: switch(type_centre)
   	          	{case 2 : pl.Change_ptref(noe->Coord0()); break;
   	          	 case 3 : pl.Change_ptref(noe->Coord2()); break;
   	          	}
   	          break; 
   	};
   // dans le cas ou type_centre = 1, on ne fait rien, donc le centre actuellement enregistré est maintenu	
   };

// indique si le blocage qui existe déjà sur les noeuds à projeter, est cohérent
// avec la projection:
// typiquement si la direction de blocage est normale au plan de rotation
// ramène true si on peut concerver la condition de projection
// en entrée: indi qui donne la direction déjà bloquée
bool I_O_Condilineaire::Coherence_condi_PlanDroite(int indi)const
 { bool retour = false;
   int dima = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   switch (dima)
      { case 2:
          { const Coordonnee& dro = dr.VecDroite();
            if (Dabs(dro(indi)) < ConstMath::pasmalpetit)
                retour = true;
            break;
          }
        case 3:
          { const Coordonnee& N = pl.Vecplan();
            if (Dabs(N(indi)) < ConstMath::pasmalpetit)
                retour = true;
            break;
          }
        default:
        break; // pour les autres dimensions on ne fait rien
      };
   // retour
   return retour;
  };

// définition de la direction actuelle ou normale pour plan droite
void I_O_Condilineaire::ActualiseDirectionPlanDroite()
  {// exécution en fonction de la présence de fonction de charge ou non
   Coordonnee dir(val.Coordo()); // val doit avoir la dimension du pb
   int dima = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   if (tab_co_charge.Taille() != 0)
    	{ for (int i=1;i<=dima;i++)
    	    dir(i) *= fctch(i+1) ;
    	 };
   switch (dima)
   	{ case 2:  dr.Change_vect(dir); break; // on met à jour la direction
   	  case 3: pl.Change_normal(dir); break; // on met à jour la direction
   	};
  };

// projection (normale) du point M sur le plan ou droite, ramène le point M à la place du
// projeté,  et calcul de la condition linéaire correspondant à la projection
Coordonnee& I_O_Condilineaire::ProjectionSurPlanDroite_et_calValCondiLin(Coordonnee& M )
  {int dima = ParaGlob::Dimension();
   if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   switch (dima)
     { case 2:{ M = dr.Projete(M);
                beta  = -dr.VecDroite()(2)*M(1)+dr.VecDroite()(1)*M(2);
                break;
              }
       case 3:{ M = pl.Projete(M);
                beta = pl.Vecplan() * M ;
                break;
              }
       default: break; // pour les autres dimensions on ne fait rien
     };
   // retour
   return M;	
  };

		 
// surcharge de l'operateur de lecture typée
istream & operator >> (istream & entree, I_O_Condilineaire & cLL)
  { // vérification du type
    string type;
    entree >> type;
    if (type != "I_O_Condilineaire___ref_princ=") 
      {cout << "\n erreur en lecture d'une condition lineaire "
            << "\n operator >> (istream & entree, I_O_Condilineaire & cLL) "; 
       Sortie (1);
       return entree;
      }
    // lecture d'un nom de maillage éventuel
    bool existe_nom_maillage; entree >> existe_nom_maillage;
    string nom;
    if (existe_nom_maillage) 
       { entree >> nom; 
         if (cLL.nom_maillage == NULL) 
            {cLL.nom_maillage = new string(nom);}
         else 
            {*(cLL.nom_maillage) = nom;};
       };
    // maintenant la référence principale
    entree  >> cLL.refe ;
    // les références associés
    int tai=0;
    entree >> nom >> tai;
    if (tai != 0)
      {cLL.refs_associe.Change_taille(tai);
       if (cLL.nom_maillage != NULL)
       	{cLL.nom_mail_associe.Change_taille(tai);
         for (int i=1;i<=tai;i++)
             {entree >> cLL.nom_mail_associe(i) >> cLL.refs_associe(i); };
       	}
       else   
       	{for (int i=1;i<=tai;i++)
             {entree >> cLL.refs_associe(i); };
       	};
      };
    entree >> nom >> cLL.enu ;
    entree >> nom >> cLL.def_auto_par_rotation;
    entree >> nom >> cLL.stricte_egalite;
    int dima = ParaGlob::Dimension();
    if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   
    if (cLL.stricte_egalite)
     {   }
    else
     {if (cLL.def_auto_par_rotation)
        {entree >> nom >> cLL.type_centre;
         if (cLL.type_centre == 1)
          { entree >> nom;
            Coordonnee B; 
            entree >> nom >> B; 
            if (dima == 2)
              {cLL.dr.Change_ptref(B) ;}
            else 
              {cLL.pl.Change_ptref(B) ;};
           }
         else if  ((cLL.type_centre == 2) || (cLL.type_centre == 3)) 
          { entree >> nom >> cLL.mailEtNumCentreNoeud ;} 
         Coordonnee V; 
         entree >> nom >> V >> nom >> cLL.val;  
         if (dima == 2)
           {cLL.dr.Change_vect(V);}
         else // cas dimension 3
           {cLL.pl.Change_normal(V);};
        }
      else
        { entree >> nom >> cLL.beta  >> nom >> cLL.val;};
      entree >> nom >> cLL.condition_relative
             >> nom >> cLL.echelle;
      entree >> nom >> cLL.tab_co_charge;
     };
   
//    if (!cLL.def_auto_par_rotation)
//      { entree >> nom >> cLL.beta  >> nom >> cLL.val;}
//    else
//      {entree >> nom >> cLL.type_centre;
//       if (cLL.type_centre == 1)
//        { entree >> nom;
//          Coordonnee B; 
//          entree >> nom >> B; 
//          if (ParaGlob::Dimension() == 2) 
//            {cLL.dr.Change_ptref(B) ;}
//          else 
//            {cLL.pl.Change_ptref(B) ;};
//         }
//       else if  ((cLL.type_centre == 2) || (cLL.type_centre == 3)) 
//        { entree >> nom >> cLL.mailEtNumCentreNoeud ;} 
//       Coordonnee V; 
//       entree >> nom >> V >> nom >> cLL.val;  
//       if (ParaGlob::Dimension() == 2)
//         {cLL.dr.Change_vect(V);}
//       else // cas dimension 3
//         {cLL.pl.Change_normal(V);};
//      };
   
    entree >> nom >> cLL.t_min >> nom >>  cLL.t_max
           >> nom >> cLL.precedent;
   
    return entree;
  };
  
// surcharge de l'operateur d'ecriture typée
ostream & operator << ( ostream & sort,const  I_O_Condilineaire & cLL)
  { // tout d'abord un indicateur donnant le type 
    sort << " I_O_Condilineaire___ref_princ= " ;
    // puis le maillage éventuelle
    if (cLL.nom_maillage == NULL) 
       {sort << false << " ";} 
    else 
       {sort << true << " " << *(cLL.nom_maillage) << " ";};
    // maintenant la référence principale
    sort  << cLL.refe << " ";
    // les références associés
    if (cLL.refs_associe.Taille() != 0)
       {int tai = cLL.refs_associe.Taille();
        sort << " ref_associe___taille= " << tai << " ";
        for (int i=1;i<=tai;i++)
          if (cLL.nom_maillage != NULL) 
             {sort << cLL.nom_mail_associe(i) << " " << cLL.refs_associe(i) << " ";}
          else   
             {sort  << cLL.refs_associe(i) << " ";}
       };
    sort << "\n type_ddl= " << Nom_ddl(cLL.enu) ;
    sort <<  " def_auto_par_rotation= " << cLL.def_auto_par_rotation;
    sort <<  " stricte_egalite= " << cLL.stricte_egalite;
    int dima = ParaGlob::Dimension();
    if(ParaGlob::AxiSymetrie())
      // cas d'élément axisymétrique, dans ce cas on ne prend en compte que les
      // dimension-1 coordonnées donc on décrémente
      dima--;
   
    if (cLL.stricte_egalite)
     {   }
    else
     {if (cLL.def_auto_par_rotation)
        {sort << " type_centre= " << cLL.type_centre;
         if (cLL.type_centre == 1)
          { sort << " centre_fixe= " ;
            if (dima == 2) {sort << cLL.dr.PointDroite() << " " ;}
            else {sort << cLL.pl.PointPlan() << " " ;};
           }
         else if  (cLL.type_centre == 2) 
          { sort << " centre_noeud_t0= " << cLL.mailEtNumCentreNoeud << " ";} 
         else if  (cLL.type_centre == 3) 
          { sort << " centre_noeud_t= " << cLL.mailEtNumCentreNoeud << " ";};
         if (dima == 2)
           {sort << " dir_droite_now= " << cLL.dr.VecDroite() <<  " dir_droite0= " << cLL.val;}
         else // cas dimension 3
           {sort << " normal_plan_now= " << cLL.pl.Vecplan() << " normal_plan0= " << cLL.val;}
        }
      else
        { sort << " val_condi= " << cLL.beta << " coefficients= " << cLL.val;};
      sort << "  condition_relative= " << cLL.condition_relative << " "
           << " echelle= " << cLL.echelle;
      sort << "\n courbe_charge= " << cLL.tab_co_charge;
     };
   
   
//    if (!cLL.def_auto_par_rotation)
//      { sort << " val_condi= " << cLL.beta << " coefficients= " << cLL.val;}
//    else
//      {sort << " type_centre= " << cLL.type_centre;
//       if (cLL.type_centre == 1)
//        { sort << " centre_fixe= " ;
//          if (ParaGlob::Dimension() == 2) {sort << cLL.dr.PointDroite() << " " ;}
//          else {sort << cLL.pl.PointPlan() << " " ;};
//         }
//       else if  (cLL.type_centre == 2) 
//        { sort << " centre_noeud_t0= " << cLL.mailEtNumCentreNoeud << " ";} 
//       else if  (cLL.type_centre == 3) 
//        { sort << " centre_noeud_t= " << cLL.mailEtNumCentreNoeud << " ";};
//       if (ParaGlob::Dimension() == 2)
//         {sort << " dir_droite_now= " << cLL.dr.VecDroite() <<  " dir_droite0= " << cLL.val;}
//       else // cas dimension 3
//         {sort << " normal_plan_now= " << cLL.pl.Vecplan() << " normal_plan0= " << cLL.val;}
//      };
   
    sort << "\n tmin= " << cLL.t_min << " tmax= " << cLL.t_max
         << " prec " << cLL.precedent;

    return sort;      
  };
    


