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


#include "AlgoriFlambLineaire.h"
#include "ElemMeca.h"

// CONSTRUCTEURS :
AlgoriFlambLineaire::AlgoriFlambLineaire () : // par defaut
   Algori()
  {  };
     
// constructeur en fonction du type de calcul et du sous type 
// il y a ici lecture des parametres attaches au type
AlgoriFlambLineaire::AlgoriFlambLineaire (const bool avec_typeDeCal
            ,const list <EnumSousTypeCalcul>& soustype
            ,const list <bool>& avec_soustypeDeCal
            ,UtilLecture& entreePrinc) :
         Algori(FLAMB_LINEAIRE,avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc)
         ,vglobin(),vglobex(),vglobaal()
         ,vcontact(),matglob(NULL),forces_vis_num(0)
//         ,methode(NULL),nbValPropre(NULL)
  { // lecture des paramËtres attachÈs au type de calcul 
    switch (entreePrinc.Lec_ent_info())
    { case 0 : 
       { lecture_Parametres(entreePrinc); break;}
      case -11 : // cas de la crÈation d'un fichier de commande
       { Info_commande_parametres(entreePrinc); break;}
      case -12 : // cas de la crÈation d'un schÈma XML, on ne fait rien ‡ ce niveau
       {  break;}
      default:
        Sortie(1); 
     }  
   };
      
// constructeur de copie
AlgoriFlambLineaire::AlgoriFlambLineaire (const AlgoriFlambLineaire& algo):
  Algori(algo)
  ,methode(algo.methode),nbValPropre(algo.nbValPropre)
  ,vglobin(),vglobex(),vglobaal()
  ,vcontact(),matglob(NULL),forces_vis_num(0)

    {};
   
// destructeur
AlgoriFlambLineaire::~AlgoriFlambLineaire ()
  {
   }; 

// execution de l'algorithme pour la recherche des modes de flambement
//dans le cas non dynamique, implicit, sans contact
void AlgoriFlambLineaire::Execution(ParaGlob * paraGlob,LesMaillages * lesMail,
               LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD*  lesFonctionsnD
               ,VariablesExporter* varExpor,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
           Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats*  resultats )
  { // INITIALISATION globale 
    tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
    Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(FLAMB_LINEAIRE); // transfert info
    // mise à jour au cas où
    Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp,diversStockage
                           ,charge,lesCondLim,lesContacts,resultats);
    // on dÈfini globalement que l'on a pas de  combinaison des c'est ‡ dire que le seul ddl est X   
    int cas_combi_ddl=0;          
    // cas du chargement, on verifie egalement la bonne adequation des references
    charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD);   
    // on indique que l'on ne souhaite le temps fin stricte, vrai par défaut en implicite
    charge->Change_temps_fin_non_stricte(0);
    // on dÈfinit un nouveau cas d'assemblage
    // ‡ travers la dÈfinition d'une instance de la classe assemblage
    Nb_assemb cas_a = lesMail->InitNouveauCasAssemblage(1); // rÈcup du numÈro
    Assemblage Ass(cas_a); // stockage numÈro
    // mise à jour du nombre de cas d'assemblage pour les conditions limites
    // c-a-d le nombre maxi possible (intégrant les autres pb qui sont résolu en // éventuellement)
    lesCondLim->InitNombreCasAssemblage(lesMail->Nb_total_en_cours_de_cas_Assemblage());
    // mise a zero de tous les ddl actifs et creation des tableaux a t+dt
    // les ddl de position ne sont pas mis a zero ! ils sont initialise
    // a la position courante
    lesMail->ZeroDdl(true);
    // on vérifie que les noeuds sont bien attachés à un élément sinon on met un warning si niveau > 2
    if (ParaGlob::NiveauImpression() > 2)
      lesMail->AffichageNoeudNonReferencer();
    // init des ddl actifs avec les conditions initials
    lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl);
    // activation des ddl de position
    lesMail->Active_un_type_ddl_particulier(X1);
    lesMail->MiseAJourPointeurAssemblage(Ass.Nb_cas_assemb());// mise a jour des pointeurs d'assemblage    
    //  calcul de la largeur de bande effective
    int demi,total;
    lesMail->Largeur_Bande(demi,total,Ass.Nb_cas_assemb());
    int nbddl = lesMail->NbTotalDdlActifs(); // nb total de ddl

    // choix de la matrice de raideur  du système linéaire en Xi
    Choix_matriciel(nbddl,tab_mato,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
    matglob = tab_mato(1); // par défaut c'est la première matrice
    // $$$ essai newton modifié $$$
    //   bool newton_modifie=true;Mat_abstraite matsauv(matglob);
    //  if (newton_modifie) matsauv=new Mat_abstraite(matglob);
   
    // choix de la résolution
    matglob->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
    // vérification d'une singularité éventuelle de la matrice de raideur
    VerifSingulariteRaideurMeca(nbddl,*lesMail);
    vglobin.Change_taille(nbddl); // puissance interne
    vglobex.Change_taille(nbddl); // puissance externe
    vglobaal.Change_taille(nbddl,0.); // puissance totale
    // même si le contact n'est pas encore actif, il faut prévoir qu'il le deviendra peut-être !
    if (lesMail->NbEsclave() != 0)
       vcontact.Change_taille(nbddl); // puissance de contact
    //  6 vecteur pour une manipulation globale des positions vitesses et accélérations
    // vecteur qui globalise toutes les positions de l'ensemble des noeuds
    X_t.Change_taille(nbddl);X_tdt.Change_taille(nbddl); delta_X.Change_taille(nbddl);
    var_delta_X.Change_taille(nbddl);
    // vecteur qui globalise toutes les vitesses de l'ensemble des noeuds
    vitesse_t.Change_taille(nbddl);vitesse_tdt.Change_taille(nbddl);
    // vecteur qui globalise toutes les accélérations
    acceleration_t.Change_taille(nbddl);acceleration_tdt.Change_taille(nbddl) ;
    // vecteur de travail pour la viscosité artificielle
    if (pa.Amort_visco_artificielle())
     { forces_vis_num.Change_taille(nbddl);
       if (Arret_A_Equilibre_Statique())  // si on veut un équilibre statique, on sauvegarde les forces statiques
         { if (vglob_stat != NULL)
             {vglob_stat->Change_taille(vglobaal.Taille());}
           else
             {vglob_stat  = new Vecteur(vglobaal.Taille());}
         };
     };

    // dÈfinition d'un pointeur de fonction d'assemblage ici symÈtrique
    // utilisÈ dans la prise en compte des efforts extÈrieurs 
    void (Assemblage::* assembMat)   // le pointeur
                    (Mat_abstraite & matglob,const Mat_abstraite & matloc,
                    const DdlElement& tab_ddl,const Tableau<Noeud *>&tab_noeud)
                                  = & Assemblage::AssembMatSym;
    
    // un premier increment pour demmarer le processus
    charge->Avance(); // premier increment de charge    
    //  boucle sur les increments de charge
    icharge = 1;
   
    // definition des elements de frontiere, ces elements sont utilises pour le contact
    lesMail->CreeElemFront();
    //  calcul éventuel des normales aux noeuds -> init des normales pour t=0
    lesMail->InitNormaleAuxNoeuds(); //utilisé pour la stabilisation des membranes par ex
    // --- init du contact ---
    // doit-être avant la lecture d'un restart, car il y a une initialisation de conteneurs qui est faites
    // qui ensuite est utilisée en restart
    // par exemple il faut initialiser les frontières et la répartition esclave et maître
    // pour préparer la lecture de restart éventuel
    if (lesMail->NbEsclave() != 0)
     { // definition des elements de frontiere, ces elements sont utilises pour le contact
       lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
       // initialisation des zones de contacts éventuelles
       lesContacts->Init_contact(*lesMail,*lesRef,lesFonctionsnD);
       // verification qu'il n'y a pas de contact avant le premier increment de charge
       lesContacts->Verification();
       // definition des elements de contact eventuels
       lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
     };
    //--cas de restart et/ou de sauvegarde------------
    // tout d'abord rÈcup du restart si nÈcessaire
      // dans le cas ou un incrÈment diffÈrent de 0 est demandÈ -> seconde lecture ‡ l'incrÈment
    if (this->Num_restart() != 0)
        { int cas = 2;
          // ouverture de base info
          entreePrinc->Ouverture_base_info("lecture"); 
          this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
                         ,charge,lesCondLim,lesContacts,resultats,(this->Num_restart()));
          icharge = this->Num_restart();//+1;
          // comme les conditions limites cinématiques peuvent être différentes en restart
          // par rapport à celles sauvegardées, on commence par libérer toutes les CL imposées éventuelles
          lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
          lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
          // dans le cas d'un calcul axisymétrique on bloque le ddl 3
          if (ParaGlob::AxiSymetrie())
             lesMail->Inactive_un_ddl_particulier(X3);
          // on valide l'activité des conditions limites et condition linéaires, pour le temps initial
          // en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
          lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
          // mise à jour pour le contact s'il y du contact présumé
          if (pa.ContactType())
             lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
         }
    // vérif de cohérence pour le contact
    if ((pa.ContactType()) && (lesMail->NbEsclave() == 0)) // là pb
      {cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact "
            << " la definition d'un type contact possible est donc incoherente "
            << " revoir la mise en donnees !! "<< flush;
       Sortie(1);
      };
    // on regarde s'il y a besoin de sauvegarde
    if (this->Active_sauvegarde()) 
     { // si le fichier base_info n'est pas en service on l'ouvre
       entreePrinc->Ouverture_base_info("ecriture");
       // dans le cas ou se n'est pas un restart on sauvegarde l'incrÈment actuel
       // c'est-‡-dire le premier incrÈment
       // aprËs s'Ítre positionnÈ au dÈbut du fichier
       if (this->Num_restart() == 0)
        { entreePrinc->Sort_BI_Positionnement_offset(entreePrinc->position_debut_fichier);
          int cas = 1;
          paraGlob->Ecriture_base_info(*(entreePrinc->Sort_BI()),cas);
          this->Ecriture_base_info
             (cas,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
              ,charge,lesCondLim,lesContacts,resultats,OrdreVisu::INCRE_0);
         } 
       else
        { // sinon on se place dans le fichier ‡ la position du restart
          // debut_increment a ÈtÈ dÈfinit dans algori (classe mËre)
          entreePrinc->Sort_BI_Positionnement_offset(debut_increment);
        };
      }                           
    //--fin cas de restart et/ou de sauvegarde--------
    
    // ajout d'un conteneur pour les coordonnées à l'itération 0
    {Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
     Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
     // def d'un type quelconque représentatif  à chaque noeud
     TypeQuelconque typQ_gene_int(XI_ITER_0,X1,gt);
     lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
    };

    tempsInitialisation.Arret_du_comptage(); // temps cpu
    tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
    //----------------------------------------------------------------------
    //      calcul prÈliminaire pour prÈcharger Èventuellement la structure 
    //----------------------------------------------------------------------
    OrdreVisu::EnumTypeIncre type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
    // tant que la fin du chargement n'est pas atteinte 
    // dans le cas du premier chargement on calcul de toute maniËre, ce qui permet
    // de calculer meme si l'utilisateur indique un increment de charge supÈrieur
    // au temps final
    bool arret=false; // pour arrÍt du calcul au niveau du pilotage
    while (((!charge->Fin(icharge))||(icharge == 1))
           && (charge->Fin(icharge,true)!=2) // si on a dépassé le nombre d'incrément permis on s'arrête dans tous les cas
           && (charge->Fin(icharge,false)!=3) // idem si on a dépassé le nombre d'essai d'incrément permis
                                               // 1er appel avec true: pour affichage et second avec false car c'est déjà affiché
           )
    { double maxPuissExt;   // maxi de la puissance des efforts externes
      double maxPuissInt;   // maxi de la puissance des efforts internes 
      double maxReaction;   // maxi des reactions 
      int inReaction = 0;   // pointeur d'assemblage pour le maxi de reaction
      int inSol =0 ;        // pointeur d'assemblage du maxi de variation de ddl      
      double maxDeltaDdl=0; // // maxi de variation de ddl
      double last_var_ddl_max=0;  // maxi var ddl juste aprËs rÈsolutuion, que l'on sauvegarde d'une it ‡ l'autre
      Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
      
      // mise à jour du calcul éventuel des normales aux noeuds -> mise à jour des normales à t
      // mais ici, on calcule les normales à tdt, et on transfert à t
      // comme on est au début de l'incrément, la géométrie à tdt est identique à celle à t
      // sauf "au premier incrément", si l'algo est un sous algo d'un algo combiné
      // et que l'on suit un précédent algo sur un même pas de temps
      // qui a aboutit à une géométrie à tdt différente de celle de t
      // du coup cela permet d'utiliser la nouvelle géométrie pour ce premier incrément
      lesMail->MiseAjourNormaleAuxNoeuds_de_tdt_vers_T();
      // passage aux noeuds  des vecteurs globaux:  F_INT, F_EXT
      Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(lesMail);

      Pilotage_du_temps(charge,arret); // appel du Pilotage
      if (arret) break; // pilotage -> arret du calcul 
      // affichage de l'increment de charge
      bool aff_incr = pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
      if ( aff_incr)
        {cout << "\n======================================================================"
              << "\nINCREMENT DE CHARGE : " << icharge 
              << "  intensite " << charge->IntensiteCharge() 
              << "  t= " << charge->Temps_courant()
              << " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
              << "\n======================================================================";
          };    
      lesLoisDeComp->MiseAJour_umat_nbincr(icharge); // init pour les lois Umat Èventuelles
      // initialisation des coordonnees et des ddl a tdt en fonctions des 
      // ddl imposes et de l'increment du chargement
      bool change_statut = false;  // init des changements de statut, ne sert pas ici         
      lesCondLim->MiseAJour_tdt
          (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
          ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
      lesCondLim->MiseAJour_condilineaire_tdt      
           (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
            ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
      // mise en place du chargement impose sur le second membre
      // et Èventuellement sur la raideur en fonction de sur_raideur
      vglobex.Zero();
      int compteur=0; // dÈclarÈ ‡ l'extÈrieur de la boucle car utilisÈ aprËs la boucle
      // utilisation d'un comportement tangent simplifiÈ si nÈcessaire
      if (compteur <= pa.Init_comp_tangent_simple() )
           lesLoisDeComp->Loi_simplifie(true);
      else 
           lesLoisDeComp->Loi_simplifie(false);
//      bool sur_raideur = false; // pour l'instant pas de prise en compte sur la raideur
//      bool sur_raideur = true; // essai
      // mise en place du chargement impose, c-a-d calcul de la puissance externe
      // si pb on sort de la boucle
      if (!(charge->ChargeSMembreRaideur_Im_mecaSolid
        (Ass,lesMail,lesRef,vglobex,*matglob,assembMat,pa,lesCourbes1D,lesFonctionsnD)))
        { Change_PhaseDeConvergence(-10);break;};
      maxPuissExt = vglobex.Max_val_abs();
      F_ext_tdt = vglobex; // sauvegarde des forces généralisées extérieures
      //  boucle de convergence sur un increment
      Vecteur * sol; // pointeur du vecteur solution
   //   bool ifresol = false;// drapeau pour le cas d'une charge sans resolution
      for (compteur = 0; compteur<= pa.Iterations();compteur++) 
        {// initialisation de la matrice et du second membre
         matglob->Initialise (0.);
         vglobin.Zero();
         if (pa.ContactType())
            vcontact.Zero();
         vglobaal.Zero(); // puissance totale
         // renseigne les variables définies par l'utilisateur via les valeurs déjà calculées par Herezh
         Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(lesMail,varExpor,Ass.Nb_cas_assemb(),*lesRef);
         varExpor->RenseigneVarUtilisateur(*lesMail,*lesRef);
         lesMail->CalStatistique(); // calcul éventuel de statistiques
         Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(compteur);
         lesMail->Force_Ddl_aux_noeuds_a_une_valeur(R_X1,0.0,TEMPS_tdt,true); // mise à 0 des ddl de réactions, qui sont uniquement des sorties
         lesMail->Force_Ddl_etendu_aux_noeuds_a_zero(Ddl_enum_etendu::Tab_FN_FT()); // idem pour les composantes normales et tangentielles
         // affichage ou non de l'itÈration
			      bool aff_iteration = (pa.freq_affich_iter() > 0) ?
			             (aff_incr && (compteur % pa.freq_affich_iter()==0) &&(compteur!=0)) : false ; 
         lesLoisDeComp->MiseAJour_umat_nbiter(compteur); // init pour les lois Umat Èventuelles
         // boucle sur les elements
         for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
          for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
            { 
              //calcul de la raideur local et du residu local
              Element & el = lesMail->Element_LesMaille(nbMail,ne); // l'element
              Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
              Element::ResRaid resu = el.Calcul_implicit(pa);
          //    (resu.res)->Affiche();
          //    (resu.raid)->Affiche();
              // assemblage
              Ass.AssemSM (vglobin,*(resu.res),el.TableauDdl(),taN); // du second membre
              Ass.AssembMatSym (*matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
            }      
         
         // calcul des maxi des puissances internes
         maxPuissInt = vglobin.Max_val_abs();
         F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures
         
         // second membre total
         vglobaal += vglobex ;vglobaal += vglobin ;

         // initialisation des sauvegardes sur matrice et second membre
         lesCondLim->InitSauve(Ass.Nb_cas_assemb());
			
         // on récupère les réactions avant changement de repère et calcul des torseurs de réaction
         lesCondLim->ReacAvantCHrepere(vglobaal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl);

		// sauvegarde des reactions pour les  ddl bloques (simplement)
// ***dans le cas statique il semble (cf. commentaire dans l'algo) que ce soit inutile donc a voir
// ***donc pour l'instant du a un bug je commente
         // sauvegarde des reactions aux ddl bloque
//         lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom          

         // mise en place des conditions limites
         lesCondLim->ImposeConLimtdt(lesMail,lesRef,*matglob,vglobaal,Ass.Nb_cas_assemb()
			                            ,cas_combi_ddl,vglob_stat);
         // calcul du maxi des reactions
         maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
         // resolution 
    //     matglob.Affiche(1,6,1,1,6,1);
  //       matglob.Affiche(1,8,1,7,8,1);
    //     matglob.Affiche(1,18,1,13,18,1);
 //        vglobal.Affiche();
      //   matglob.Affiche(1,12,1,1,6,1);
      //  matglob.Affiche(1,12,1,7,12,1);
     //    matglob.Affiche(1,12,1,9,12,1);
     //    matglob.Affiche(1,18,1,13,18,1);
     //    vglobal.Affiche();
         // sortie d'info sur l'increment concernant les rÈactions 
         if (compteur != 0) 
          if (aff_iteration) InfoIncrementReac(lesMail,compteur,inReaction,maxReaction,Ass.Nb_cas_assemb());
         // test de convergence sur un increment
         if (Convergence(aff_iteration,last_var_ddl_max,vglobaal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret)) 
          { // sortie des itÈrations sauf si l'on est en loi simplifiÈe
            if (lesLoisDeComp->Test_loi_simplife() )
              // cas d'une loi simplifiÈ on remet normal
              lesLoisDeComp->Loi_simplifie(false);
            else 
              // cas normal, 
              break;
           }
         else if (arret) {break;} // cas ou la mÈthode Convergence() demande l'arret
         // sinon on continue    
         // ici sol en fait = vecglob qui est ecrase par la resolution
         // ---- resolution ----
         bool erreur_resolution_syst_lineaire = false; // init
         try
          {// ici sol en fait = vecglob qui est ecrase par la resolution
           sol = &(matglob->Resol_systID
              (vglobaal,pa.Tolerance(),pa.Nb_iter_nondirecte(),pa.Nb_vect_restart()));
           // affichage éventuelle du vecteur solution : deltat_ddl     
           if (ParaGlob::NiveauImpression() >= 10) 
             { string entete = " affichage du vecteur solution (delta_ddl) ";
               sol->Affichage_ecran(entete); };
           // retour des ddl dans les reperes generaux, dans le cas où ils ont ete modifie
           // par des conditions linéaires
           lesCondLim->RepInitiaux( *sol,Ass.Nb_cas_assemb());
//---debug
//cout << "\ndelta ddl "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";for (int j=1;j<=3;j++)  cout << (*sol)((i-1)*3+j)<<" ";};
////--fin-debug
//      cout << "\n résolution "; sol->Affiche();  // --- pour le debug
          }
         catch (ErrResolve_system_lineaire excep)
              // cas d'une d'une erreur survenue pendant la résolution
            { erreur_resolution_syst_lineaire = true; // on prépare l'arrêt
            } // car il faut néanmoins effacer les marques avant l'arrêt
         catch (ErrSortieFinale)
              // cas d'une direction voulue vers la sortie
              // on relance l'interuption pour le niveau supérieur
            { ErrSortieFinale toto;
              throw (toto);
            }
         catch ( ... )  
            { erreur_resolution_syst_lineaire = true; // on prépare l'arrêt
            }

         // effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
         lesCondLim->EffMarque();
         
         if (erreur_resolution_syst_lineaire)
           {Change_PhaseDeConvergence(-9); // on signale une divergence due à la résolution
            break; // arrêt si on avait détecté une erreur à la résolution
           };

         // affichage Èventuelle du vecteur solution : deltat_ddl     
         if (ParaGlob::NiveauImpression() >= 10) 
           { string entete = " affichage du vecteur solution (delta_ddl) ";
             sol->Affichage_ecran(entete); };
         // calcul du maxi de variation de ddl 
         maxDeltaDdl = sol->Max_val_abs(inSol);
         double maxDeltatDdl_signe=(*sol)(inSol); // rÈcupÈration de la grandeur signÈe      
         // pilotage ‡ chaque itÈration:  ramËne: maxDeltaDdl,csol modifiÈs Èventuellement et insol
         Pilotage_chaque_iteration(sol,maxDeltaDdl,compteur,lesMail);
         // sortie d'info sur l'increment concernant les variations de ddl
         if ((aff_iteration)&&(ParaGlob::NiveauImpression() > 1))
            InfoIncrementDdl(lesMail,inSol,maxDeltatDdl_signe,Ass.Nb_cas_assemb());
       //  sol->Affiche();
         // actualisation des ddl actifs a t+dt
         lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb());
         // indication qu'un calcul a ete effectue
  //       ifresol = true;
        } 
      // gestion de la fin des itÈrations
      if (!Pilotage_fin_iteration_implicite(compteur))
       { // cas d'une non convergence 
            // comme on incrÈmente pas les ddl on remet cependant les ddl 
            //  et les grandeurs actives de tdt aux valeurs de ceux de t
            lesMail->TversTdt();   
          }
      else   
        {// sinon calcul correcte
         // actualisation des ddl et des grandeurs actives de t+dt vers t      
         lesMail->TdtversT();
         // on valide l'activitÈ des conditions limites et condition linÈaires 
         lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());      
         // sauvegarde de l'incrÈment si nÈcessaire
         Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
             ,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
             ,resultats,type_incre,icharge);
         // enregistrement du num d'incrÈment et du temps correspondant                 
         list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));                 
         // visualisation Èventuelle au fil du calcul 
         VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
                          ,lesCondLim,lesContacts,resultats,type_incre,icharge);
         // test de fin de calcul effectue dans charge via : charge->Fin()
         icharge++;
         Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
         }  
     }         
    // on remet à jour le nombre d'incréments qui ont convergés:
    icharge--;
    Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
    // passage finale dans le cas d'une visualisation  au fil du calcul
    type_incre = OrdreVisu::DERNIER_INCRE;  
    VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
                          ,lesCondLim,lesContacts,resultats,type_incre,icharge);
    // sauvegarde de l'incrÈment si nÈcessaire
    Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
             ,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
             ,resultats,type_incre,icharge);
    // enregistrement du num d'incrÈment et du temps correspondant                 
    list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));                 
    //--------------------------------------------------------------------
    //  calcul particulier ‡ la recherche de valeurs et vecteurs propres 
    //--------------------------------------------------------------------
      // affichage 
    cout << "\n================================================================="
         << "\n    calcul des valeurs et vecteurs propres  " 
         << "\n=================================================================";
    //  def de la matrice bande gÈomÈtrique
    // a priori matrice symetrique 
    // initialisation a zero
    MatBand matgeom(BANDE_SYMETRIQUE,demi,nbddl,0); 
    // initialisation de la matrice de raideur 
    matglob->Initialise (0.);
    // boucle sur les elements
    for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
      for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
        { 
          ElemMeca * el = (ElemMeca *) &(lesMail->Element_LesMaille(nbMail,ne)); // l'element
          Tableau<Noeud *>& taN = el->Tab_noeud(); // tableau de noeuds de l'elÈment
          //calcul de la raideur local et de la matrice gÈomÈtrique locale
          ElemMeca::MatGeomInit resu = el->MatricesGeometrique_Et_Initiale (pa);
          //    (resu.matInit)->Affiche();
          //    (resu.matGeom)->Affiche();
            // assemblage
          Ass.AssembMatSym(*matglob,*(resu.matInit),el->TableauDdl(),taN); // de la raideur
          Ass.AssembMatSym(matgeom,*(resu.matGeom),el->TableauDdl(),taN); // de la raideur
         }      
    // pour mettre les conditions limites on se sert des informations sauvegardÈes dans 
    // lesCondLim
    // mise en place des conditions limites
    lesCondLim->ImpConLimtdt2Mat(lesMail,lesRef,*matglob,matgeom,Ass.Nb_cas_assemb(),cas_combi_ddl);
    //     matglob.Affiche(1,6,1,1,6,1);
  //       matglob.Affiche(1,8,1,7,8,1);
    //     matglob.Affiche(1,18,1,13,18,1);
 //        vglobal.Affiche();
      //   matglob.Affiche(1,12,1,1,6,1);
      //  matglob.Affiche(1,12,1,7,12,1);
     //    matglob.Affiche(1,12,1,9,12,1);
     //    matglob.Affiche(1,18,1,13,18,1);
     //    vglobal.Affiche();
    // calcul des valeurs et vecteurs propres
    Tableau <VeurPropre> VP((int)*nbValPropre);
//    matglob.Affiche1(1,6,1,1,6,1);
//    matgeom.Affiche1(1,6,1,1,6,1);
     
    matglob->V_Propres(matgeom,VP);
    // sauvegarde dans Resultat 
    resultats->VeaPropre() = LesValVecPropres(VP);     
    // fin des calculs
    tempsCalEquilibre.Arret_du_comptage(); // temps cpu
  };

// lecture des paramËtres du calcul
void AlgoriFlambLineaire::lecture_Parametres(UtilLecture& entreePrinc)
 { // dimensionnement
   paraTypeCalcul.Change_taille(2);
   Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(FLAMB_LINEAIRE); // transfert info
   MotCle motCle; // ref aux mots cle
   deja_lue_entete_parametre = 1; // a priori pas de lecture d'entÍte
   // on se positionne sur le prochain mot clÈ
   do 
     { entreePrinc.NouvelleDonnee();
       }
     while ( !motCle.SimotCle(entreePrinc.tablcar)) ;
   // si le mot clÈ est "PARA_TYPE_DE_CALCUL" cela signifie 
   // qu'il y a un paramËtre ‡ lire
   bool lecture_effective = false;
   if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL)
    { //cas de la dÈfinition de paramËtres  
      // on signale ‡ Algori qu'il y a eu dÈj‡ une lecture de paramËtre
      deja_lue_entete_parametre=2; 
      // lecture du premier paramËtres de l'algorithme
      entreePrinc.NouvelleDonnee(); // ligne suivante
      // lecture du nom du paramËtre et vÈrification
      string st1;
      *(entreePrinc.entree) >> st1 ;
      if (st1 != "methode_et_nbDeValeurPropre=")
        { cout << "\n erreur en lecture du paramËtre de l'algorithme de flambement lineaire"
               << "\n on attendait le mot : methode_et_nbDeValeurPropre= , au lieu de " 
               << st1
               << "\n AlgoriFlambLineaire::lecture_Parametres( ... ";
          Sortie(1);
         }     
      // lecture du parametre      
      *(entreePrinc.entree) >> paraTypeCalcul(1) >> paraTypeCalcul(2);
      lecture_effective = true;
      }
    else // sinon on met une valeur par dÈfaut 
      {  paraTypeCalcul(1) = 1; paraTypeCalcul(2) = 0;
       } 
    // on relie les paramËtres ‡ bÈta et gamma
    methode = & paraTypeCalcul(1);
    nbValPropre =  & paraTypeCalcul(2);   
   // on prÈpare la prochaine lecture si la lecture a ÈtÈ effective et que l'on n'est pas
   // sur un mot clÈ
   if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar)))
      entreePrinc.NouvelleDonnee(); // ligne suivante
   // puis appel de la mÈthode de la classe mËre 
   Algori::lecture_Parametres(entreePrinc);  
             
  };     

// Ècriture des paramËtres dans la base info
// = 1 : on Ècrit tout
// = 2 : on Ècrot uniquement les donnÈes variables (supposÈes comme telles)
void AlgoriFlambLineaire::Ecrit_Base_info_Parametre(ostream& sort,const int& cas)
 {
  if (cas == 1)
   {
    // ecriture du parametre      
    sort << "methode_et_nbDeValeurPropre= " << paraTypeCalcul(1) << " "
         <<  paraTypeCalcul(2) << " ";
    };
//  (*sort) << "\n fin_parametres_algo_specifiques_ ";

 };

    // lecture des paramËtres dans la base info
    // = 1 : on rÈcupËre tout
    // = 2 : on rÈcupËre uniquement les donnÈes variables (supposÈes comme telles)
    // choix = true  : fonctionnememt normal
    // choix = false : la mÈthode ne doit pas lire mais initialiser les donnÈes ‡ leurs valeurs par dÈfaut
    //                 car la lecture est impossible
void AlgoriFlambLineaire::Lecture_Base_info_Parametre(istream& ent,const int& cas,bool choix)
{if (cas == 1)
 {// dimensionnement
  paraTypeCalcul.Change_taille(2);
  if (choix)
   {string toto;
    // lecture du premier parametre      
    ent >> toto ;
    if (toto != "methode_et_nbDeValeurPropre=")
      { cout << "\n erreur en lecture du paramËtre de l'algorithme explicite "
             << "\n on attendait le mot : methode_et_nbDeValeurPropre= , au lieu de " 
             << toto
             << "\n AlgoriFlambLineaire::Lecture_Base_info_Parametre( ... ";
        Sortie(1);
       }     
    ent >> paraTypeCalcul(1) >> paraTypeCalcul(2);
    }
  else
   {// cas o˘ la lecture n'est pas possible, attribution des valeurs par dÈfaut
    paraTypeCalcul(1) = 1; paraTypeCalcul(2) = 0;
    }  
  // on relie les paramËtres ‡ bÈta et gamma
  methode = & paraTypeCalcul(1);
  nbValPropre =  & paraTypeCalcul(2);
  }    
};

// crÈation d'un fichier de commande: cas des paramËtres spÈcifiques
void AlgoriFlambLineaire::Info_commande_parametres(UtilLecture& entreePrinc)
 {  // Ècriture dans le fichier de commande
    ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
    sort << "\n#----------------------------------------------------------------------"
         << "\n|  parametres (falcultatifs) associe au calcul de flambement lineaire |"
         << "\n#----------------------------------------------------------------------"
         << "\n"
         << "\n    PARA_TYPE_DE_CALCUL"
         << "\n  #   ................................................................................."
         << "\n  #  / seule la methode 1 est valide actuellement pour des matrices carres uniquement/"
         << "\n  # / le second chiffre = nb de valeur propre                                       /"
         << "\n  #................................................................................" 
         << "\n        methode_et_nbDeValeurPropre= 1  1 ";
	  // appel de la classe mère
	  Algori::Info_com_parametres(entreePrinc);
   sort << "\n" << endl;
 };





