// 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 "AlgoriNonDyna.h"
#include "MatBand.h"
#include <cmath>

    //------- décomposition en 3 du calcul d'équilibre -------------
    // a priori   : InitAlgorithme  et FinCalcul ne s'appellent qu'une fois, 
    // par contre : CalEquilibre peut s'appeler plusieurs fois, le résultat sera différent si entre deux calcul
    //              certaines variables ont-été changés    


    // initialisation
void AlgoriNonDyna::InitAlgorithme(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(NON_DYNA); // transfert info
    
  #ifdef UTILISATION_MPI
    // calcul de l'équilibrage initiale par le cpu 0
    if (distribution_CPU_algo.Tableau_element_CPU_en_cours()->Taille() == 0 )
       {distribution_CPU_algo.Calcul_Equilibrage_initiale(lesMail);
        temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
        distribution_CPU_algo.Passage_Equilibrage_aux_CPU();
        temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
        paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
       };
  #endif


////------- debug
//cout << "\n debug AlgoriNonDyna::InitAlgorithme ";
//lesMail->Noeud_LesMaille(1,120).Affiche(9);
//cout << endl;
////-------- fin debug



    // avant toute chose, au cas où l'algo interviendrait après un autre algo
    // on inactive tous les ddl existants
    lesMail->Inactive_ddl();
    // on regarde s'il s'agit d'un pb purement non méca, dans ce cas il faut cependant initialiser les positions
    // à t et tdt pour le calcul de la métrique associée
    { const list <EnumElemTypeProblem >& type_pb = lesMail->Types_de_problemes();
      bool purement_non_meca = true;
      list <EnumElemTypeProblem >::const_iterator il,ilfin=type_pb.end();
      for (il=type_pb.begin();il != ilfin; il++)
        {switch (*il)
          { case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE:
                 purement_non_meca=false; break;
            default: break; // sinon on ne fait rien
          };
        };
      if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0
        {lesMail->Init_Xi_t_et_tdt_de_0();}
      else // dans le cas où il y a de la mécanique, on active X1
       { lesMail->Active_un_type_ddl_particulier(X1);
       };
    };

    // on défini globalement que l'on a pas de  combinaison des ddl c'est à dire que le seul ddl est X
    // ou TEMP pour la température ...
    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);
    // dans le cas où l'on calcul des contraintes et/ou déformation et/ou un estimateur d'erreur
    // à chaque incrément, initialisation
    prepa_avec_remont =
        Algori::InitRemont(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);      
    if ( prepa_avec_remont)// remise enservice des ddl du pab 
          {lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);};      
    // on définit un nouveau cas d'assemblage
    // à travers la définition d'une instance de la classe assemblage
    if (Ass_ == NULL) Ass_ = new Assemblage(lesMail->InitNouveauCasAssemblage(1));
    Assemblage& Ass = *Ass_;
    // 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 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 avec les conditions initials
    lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl);
   

    // L'algorithme peut s'appliquer à plusieurs types de problème: création des types de ddl du pb en fonction
    // des physiques
    lesMail->Active_un_type_ddl_particulier(lesMail->Ddl_representatifs_des_physiques());
//    lesMail->Active_un_type_ddl_particulier(X1);
    lesMail->MiseAJourPointeurAssemblage(Ass.Nb_cas_assemb());// mise a jour des pointeurs d'assemblage

    // mise en place éventuelle du bulk viscosity: pas prévue au départ donc exploratoire !!
    lesMail->Init_bulk_viscosity(pa.BulkViscosity(),pa.CoefsBulk());

//---- arrêt intro thermique --- la suite à suivre !!!!!!!!!
    int nbddl_X = lesMail->NbTotalDdlActifs(); // nb total de ddl
   
    // choix de la matrice de raideur  du système linéaire (calcul éventuellement d'une largeur de bande ad oc)
    Choix_matriciel(nbddl_X,tab_mato,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
    matglob = tab_mato(1); // par défaut c'est la première matrice
    // dans le cas où l'on veut également utiliser du Newton modifié, on definit la matrice de sauvegarde
    if (deb_newton_modifie >= 0)
       Choix_matriciel(nbddl_X,tab_matsauve,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
    matsauve = tab_matsauve(1); // par défaut c'est la première matrice
    // dans le cas où l'on veut utiliser une raideur moyenne on définit les sous-matrices
    // pour chaque niveau secondaire
    if (deb_raideur_moyenne >= 0)
      // on boucle sur les groupes de matrices
      {
       // comme il s'agit du premier dimensionnement on commence par tout supprimer
       // au cas où quelque chose existait déjà
       {int taille = tab_tab_matmoysauve.Taille();
        for (int i=1;i<=taille;i++)
          if (tab_tab_matmoysauve(i)!= NULL)
            {Tableau <Mat_abstraite*> * tab_matmoysauve_i = tab_tab_matmoysauve(i); // par simplicité
             int tail = tab_matmoysauve_i->Taille();
             for (int j=1; j<= tail;j++)
               if ((*tab_matmoysauve_i)(j) != NULL)
                 delete (*tab_matmoysauve_i)(j);
            };
       };
       // puis on redimensionne le tableau maître de pointeurs
       // nb_mat_secondaire = le nb de table secondaire + 1
       int nb_mat_secondaire = tab_mato.Taille();
       tab_tab_matmoysauve.Change_taille(nb_raideur_moyenne,NULL);
       // maintenant on crée les sous tableaux de pointeurs nulles
       for (int i=1;i<=nb_raideur_moyenne;i++)
         {tab_tab_matmoysauve(i) = new Tableau<Mat_abstraite*>;
          tab_tab_matmoysauve(i)->Change_taille(nb_mat_secondaire,NULL);
         };
       // maintenant on peu créer les matrices
       for (int i=1;i<=nb_raideur_moyenne;i++)
          { Tableau <Mat_abstraite*>& tab_matmoysauve_i = *tab_tab_matmoysauve(i);
            Choix_matriciel(nbddl_X,tab_matmoysauve_i,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
          };
      };
   
    // on refait une passe dans le cas où l'utilisateur veut une renumérotation des pointeurs
    // d'assemblage, globalement
    {bool premier_calcul=true;bool nouvelle_situation_CLL=false;
     int niveau_substitution = 0; // on intervient sur toutes les matrices
     Gestion_stockage_et_renumerotation_sans_contact
                          (lesContacts,premier_calcul,lesMail,nouvelle_situation_CLL
                          ,lesCondLim,lesRef,tab_mato,Ass.Nb_cas_assemb()
                          ,niveau_substitution);
    };
   
    // choix de la résolution pour la première matrice
    matglob->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
    // vérification d'une singularité éventuelle de la matrice de raideur
    // à cause d'un trop faible nombre de pti
    VerifSingulariteRaideurMeca(nbddl_X,*lesMail);
    // def vecteurs globaux
    vglobin.Change_taille(nbddl_X); // puissance interne
    vglobex.Change_taille(nbddl_X); // puissance externe
    vglobaal.Change_taille(nbddl_X,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_X); // puissance de contact
    // dans le cas où on initialise les ddl_tdt(n) avec les ddl_t(n)+delta_ddl(n-1), def de grandeurs
    X_t.Change_taille(nbddl_X);X_tdt.Change_taille(nbddl_X); delta_X.Change_taille(nbddl_X);
    delta_prec_X.Change_taille(nbddl_X);var_delta_X.Change_taille(nbddl_X);
    // calcul des énergies
    if (pa.Amort_visco_artificielle()) // dans le cas d'un amortissement artificiel
       forces_vis_num.Change_taille(nbddl_X,0.);
    E_int_t = 0.; E_int_tdt = 0.; // init des différentes énergies
    E_ext_t = 0.; E_ext_tdt = 0.; bilan_E = 0.;   //       "       et du bilan
    F_int_t.Change_taille(nbddl_X); F_ext_t.Change_taille(nbddl_X); // forces généralisées int et ext au pas précédent
    F_int_tdt.Change_taille(nbddl_X); F_ext_tdt.Change_taille(nbddl_X); // forces généralisées int et ext au pas actuel
    residu_final.Change_taille(nbddl_X); // pour la sauvegarde du résidu pour le post-traitement

    // définition d'un pointeur de fonction d'assemblage en fonction du type voulu
    // (symetrique ou non), utilisé dans la prise en compte des efforts extérieurs     
    if (pa.Symetrie_matrice())
      // cas d'un assemblage symétrique
      assembMat = & Assemblage::AssembMatSym;
    else // cas d'un assemblage non symétrique
      assembMat = & Assemblage::AssembMatnonSym;
                                  
    // dans le cas où l'on fait du line search on dimensionne des vecteurs
    // globaux supplémentaires
    if (pa.Line_search())
      { sauve_deltadept = new Vecteur(nbddl_X);
        Vres = new Vecteur(nbddl_X);
        sauve_dept_a_tdt = new Vecteur(nbddl_X);
        v_travail = new Vecteur(nbddl_X);        
       }
    else if (acceleration_convergence) 
      // idem pour l'accélération de convergence, pour la sauvegarde du résidu   
      { Vres = new Vecteur(nbddl_X); 
        for (int ni =1;ni<= nb_vec_cycle+2;ni++)
              { if (cas_acceleration_convergence < 4)
           {Vi(ni).Change_taille(nbddl_X);}
        else if (cas_acceleration_convergence == 4)
         {Vi(ni).Change_taille(1);};
                Yi(ni).Change_taille(nbddl_X);
         };	
       };
      
    //  initi boucle sur les increments de charge
    icharge = 0;
   
    // 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)
     { 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
//       //  et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
//       lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
       if (pa.ContactType() == 4) // cas particulier du type 4 de contact où on utilise les forces internes
        {// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
         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  pour un vecteur force à chaque noeud
         TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
         lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
        };
       // definition des elements de contact eventuels
       //  et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
//		 double diam_mini = lesMail->Min_dist2Noeud_des_elements(TEMPS_0);
//       lesContacts->DefElemCont(2. * diam_mini);
       try {
            // definition des elements de contact eventuels
            //  et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
            bool nevez_contact = lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
            int niveau_substitution = 0; // on intervient sur toutes les matrices
            bool premier_calcul = true;
            // mise à jour éventuelle de la matrice de raideur en fonction du contact
            //bool changement_sur_matrice =
            Gestion_stockage_et_renumerotation_avec_contact
                             (premier_calcul,lesMail,nevez_contact,lesCondLim
                             ,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
            matglob=tab_mato(1);
           }
       // sortie anormale de l'initialisation du contact  
       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 inconnue
          {  cout << "\n **** >>>>   ERREUR inconnuee en  en initialisant le contact *****  ";
             if (ParaGlob::NiveauImpression() >= 4)     
               cout  << "\n AlgoriNonDyna::InitAlgorithme(..";
             cout << endl;
          };
     };



    //--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
    brestart=false;   // booleen qui indique si l'on est en restart ou pas
    if (this->Num_restart() != 0)
     { int cas = 2;
////---debug
//{cout << "\n debug1: AlgoriNonDyna::InitAlgorithme(...";
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
// noe.Affiche();
//}
////--fin-debug       // 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()));
       // on ferme tout de suite le baseinfo en lecture de manière à éviter des pb de switch
       // lecture -> écriture, si le fichier est très gros
       entreePrinc->Fermeture_base_info();
       icharge = this->Num_restart();//+1;
       brestart = true;
////---debug
//{cout << "\n debug2: AlgoriNonDyna::InitAlgorithme(...";
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
// noe.Affiche();
//}
////--fin-debug       // ouverture de base info

       // 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);
////---debug
//{cout << "\n debug3: AlgoriNonDyna::InitAlgorithme(...";
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
// noe.Affiche();
//}
//--fin-debug       // ouverture de base info
       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());
////---debug
//{cout << "\n debug4: AlgoriNonDyna::InitAlgorithme(...";
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
// noe.Affiche();
//}
////--fin-debug       // ouverture de base info
       // on remet à jour les éléments pour le contact s'il y du contact présumé
       if (pa.ContactType())
       { // mise à jour pour le contact s'il y du contact présumé
         if (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);
               };
         // sinon ok, et on met à jour la boite d'encombrement compte tenue des nouvelles coordonnées
         lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
         bool nevez_contact = lesContacts->Actualisation(0);
         // *** test
         bool nevez_bis_contact = lesContacts->Nouveau(0.);
         nevez_contact = (nevez_contact || nevez_bis_contact); //double dep_max)
         int niveau_substitution = 0; // on intervient sur toutes les matrices
         bool premier_calcul = true;
         // mise à jour éventuelle de la matrice de raideur en fonction du contact
         //bool changement_sur_matrice =
         Gestion_stockage_et_renumerotation_avec_contact
                          (premier_calcul,lesMail,nevez_contact,lesCondLim
                          ,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
         matglob=tab_mato(1);
         if (deb_newton_modifie >= 0)
           (*matsauve) = (*matglob);
         // dans le cas où l'on veut utiliser une raideur moyenne on redéfinit les matrices
         if (deb_raideur_moyenne >= 0)
          { Tableau <Mat_abstraite*>& tab_matmoysauve = *tab_tab_matmoysauve(1);
            tab_matmoysauve.Change_taille(nb_raideur_moyenne);
            for (int i=1;i<= nb_raideur_moyenne;i++)
              (*tab_matmoysauve(i)) = (*matglob);
          };
       };
     };
    // 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() && (ParaGlob::param->TypeCalcul_maitre() == this->typeCalcul) )
     { // 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())->seekp(0);
          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())->seekp(debut_increment);
        };
     };
     
    // init de var glob
    Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
    //--fin cas de restart et/ou de sauvegarde--------
    type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
   
    // 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);
    };

    // mise à jour au cas où
    Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp,diversStockage
                           ,charge,lesCondLim,lesContacts,resultats);
    tempsInitialisation.Arret_du_comptage(); // temps cpu
   
  };
    // mise à jour
void AlgoriNonDyna::MiseAJourAlgo(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 
    tempsMiseAjourAlgo.Mise_en_route_du_comptage(); // temps cpu
    Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info

    // on regarde le type de calcul: tout n'est pas possible pour l'instant !!
    const list <EnumElemTypeProblem >& type_pb = lesMail->Types_de_problemes();
    bool purement_non_meca = true;
    list <EnumElemTypeProblem >::const_iterator il,ilfin=type_pb.end();
    for (il=type_pb.begin();il != ilfin; il++)
      {switch (*il)
        { case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE:
               purement_non_meca=false; break;
          case THERMIQUE:
            {cout << "\n *** cas non operationnel: pour l'instant MiseAjourAlgo "
                  << " n'est prevu que pour de la meca ... "
                  << "\n AlgoriNonDyna::MiseAJourAlgo(...)" ;
             Sortie(1);
             break;
            }
          default: break; // sinon on ne fait rien
        };
      };
    if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0
      {lesMail->Init_Xi_t_et_tdt_de_0();
       // il faut sans doute faire plus de chose, par exemple activer les ddl particuliers
       cout << "\n *** cas non operationnel: pour l'instant MiseAjourAlgo "
            << " n'est prevu que pour de la meca ... "
            << "\n AlgoriNonDyna::MiseAJourAlgo(...)" ;
       Sortie(1);
      }
    else // dans le cas où il y a de la mécanique, et que l'on a récupéré des ddl de vitesse et d'accélération
     { // on les inactives
       lesMail->Inactive_un_type_ddl_particulier(V1);
       lesMail->Inactive_un_type_ddl_particulier(GAMMA1);
       lesMail->Active_un_type_ddl_particulier(X1);
     };
    // mise à jour au cas où
    Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
                              ,diversStockage,charge,lesCondLim,lesContacts,resultats);
    tempsMiseAjourAlgo.Arret_du_comptage(); // temps cpu
  };

// calcul de l'équilibre                
    // calcul
// si tb_combiner est non null -> un tableau de 2 fonctions
//  - la première fct dit si on doit valider ou non le calcul à convergence ok,
//  - la seconde dit si on doit sortir de la boucle ou non à convergence ok
//
// si la validation est effectuée, la sauvegarde pour le post-traitement est également effectuée
//                                 en fonction de la demande de sauvegard,
// sinon pas de sauvegarde pour le post-traitement à moins que l'on a demandé un mode debug
//   qui lui fonctionne indépendamment
void AlgoriNonDyna::CalEquilibre(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,Tableau < Fonction_nD* > * tb_combiner)

   {
    tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
    Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
    
    // préparation pour les aspects validation du calcul et sortie contrôlée des incréments
    int validation_calcul = 1; // init : par défaut la validation est effective si le calcul converge
    int sortie_boucle_controler_par_fctnD = 0; // init : par défaut la sortie n'est pas contrôler
    
    // on vérifie que le pas de temps est correcte: on propose le deltat actuel qui sera modifié s'il n'est pas bon
    double deltat_actuel = pa.Deltat();
    pa.Modif_Detat_dans_borne(deltat_actuel);
    
    // def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
    int dim = ParaGlob::Dimension();if (ParaGlob::AxiSymetrie()) dim--;
    Coordonnee coor(dim); // un type coordonnee typique
    Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
    // def d'un type quelconque représentatif  pour un vecteur force à chaque noeud
    TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
    
    // on définit un type générique qui sert pour passer aux noeuds les positions à l'itération 0
    TypeQuelconque typQ_XI_ITER_0(XI_ITER_0,X1,gt);

    // on met à jour des variables de travail
    Assemblage& Ass = *Ass_;
    Vecteur vglobal_sauv; // vecteur de sauvegarde éventuel, dans le cas de l'utilisation de matrices de raideur secondaire
    double max_delta_X=0.; //  le maxi du delta X
    double max_var_delta_X=0.; // idem d'une itération à l'autre

    // 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_pilotage=false; // pour arrêt du calcul au niveau du pilotage
    bool premier_calcul = true; // utilisé pour l'initialisation de l'incrément avec le pas précédent 
    int indicCycleContact = 0; // def d'un indicateur donnant la situation dans le  cycle de contact
    // un booléen pour uniquement gérer le fait que dans la boucle globale on fait le test après le test du while
    // d'où pour le temps final, on peut sortir de la boucle globale sans avoir convergé, ce qui n'est pas bon
    bool pas_de_convergence_pour_l_instant=1;
    icharge++; // on incrémente le chargement -> donne le num d'incr du prochain incr chargé
    while (   ((!charge->Fin(icharge,!pas_de_convergence_pour_l_instant)) // on n'affiche la situation
                    // que si on a eu convergence
               || pas_de_convergence_pour_l_instant ||(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é
           && (!pa.EtatSortieEquilibreGlobal())
        )
    { 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
      // initialisation de la variable puissance_précédente d'une itération à l'autre
      double puis_precedente = 0.; 
      Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
      // affichage de l'increment de charge
      bool aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
      bool change_statut = false;  // init des changements de statut, ne sert pas ici
      
      // 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);

////--- debug
//if (premier_calcul)
//  cout << "\toto "<<flush;
////--- fin debug
      // premier contact de l'incrément
      if (!indicCycleContact) // modification de la charge et du pas de temps qu'au premier passage
                              // mais pas après un changement de statut
       { Pilotage_du_temps(charge,arret_pilotage); // appel du Pilotage 
         if (arret_pilotage) break; // pilotage -> arret du calcul                
       #ifdef UTILISATION_MPI
       // seule le process 0 s'occupe de la sortie
       if (ParaGlob::Monde()->rank() == 0)
       #endif
         if (aff_incr)
               {cout << "\n======================================================================"
                     << "\nINCREMENT DE CHARGE : " << icharge 
                     << "  intensite " << charge->IntensiteCharge() 
                     << "  t= " << charge->Temps_courant()
                     << " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
                     << "\n======================================================================";
                 };    
         // -- on regarde si l'on doit initialiser l'incrément avec le pas précédent: cas d'un premier calcul
         // sinon c'est fait à la fin lors de la préparation pour le prochain incrément
         lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1); // sert pour calculer le delta_X après CL (**)
        
         if ((!premier_calcul) && (delta_t_precedent_a_convergence > 0.)
              && pa.IniIncreAvecDeltaDdlPrec() && Pilotage_init_Xtdt()) // si oui, calcul
           { // de X_tdt = X_t + deltat(n)/deltat(n-1) *(X_tdt(n-1) - X_t(n-1))
             delta_X = delta_prec_X; // init avec le précédent delta_X qui a convergé
             X_tdt = X_t; delta_X *= pa.Deltat() * pa.IniIncreAvecDeltaDdlPrec(); X_tdt += delta_X;
             //  passage de ces nouvelles positions aux niveaux des maillages
             lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_tdt,X1);
           }; 

         // -- initialisation des coordonnees et des ddl a tdt en fonctions des
         // ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
         lesCondLim->MiseAJour_tdt
                (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
                ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
         // on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
         lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
//        delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
         Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);

         // --- calcul des éléments de contact: (correspond à la définition de la surface  de contact)
         //   definition ou mise à jour, des elements de contact eventuels
         //  - imposition (en fonction de l'algorithme de contact) de conditions particulières de penetration (nulle par exemple)
         if (pa.ContactType()) // traitement différent lors du premier incément calculé (premier passage) puis des passages courants
          {bool a_changer = false; // init par défaut
           if (premier_calcul)
             {a_changer = lescontacts->DefElemCont(max_delta_X);}
           else
             { // on supprime les éléments inactifs testés à l'incr prec dans Actualisation()
               a_changer = lescontacts->SuppressionDefinitiveElemInactif();
               bool a_changer_nouveau = lescontacts->Nouveau(max_delta_X);
               a_changer = a_changer || a_changer_nouveau;
             };
           int niveau_substitution = 0; // on intervient sur toutes les matrices
           if (premier_calcul || a_changer)
             {//bool changement_sur_matrice =
              Gestion_stockage_et_renumerotation_avec_contact
                         (premier_calcul,lesMail,a_changer,lesCondLim,lesRef
                          ,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
              matglob=tab_mato(1);
             };
           
          };
       }
      else
       {if (arret_pilotage) break; // pilotage -> arret du calcul
      #ifdef UTILISATION_MPI
      // seule le process 0 s'occupe de la sortie
      if (ParaGlob::Monde()->rank() == 0)
      #endif
            cout << "\n============================================================================="
                 << "\n ....... re-analyse du contact ........ "
                 << "\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

      // récupération (initialisation) des ddl  position à t  
      lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
         
      // on démarre avec le compteur à 0 et on sauvegarde la position finale à l'itération 0
      lesMail->Quelconque_glob_vers_local(X1,X_tdt,typQ_XI_ITER_0);

      //  boucle de convergence sur un increment
      Vecteur * sol; // pointeur du vecteur solution
      bool arret_convergence = false;
      int tab_matmoysauve_rempli = 0; // ne sert que pour les matrices de raideur moyenne
//      for (compteur = 0; compteur<= pa.Iterations();compteur++)
      for (compteur = 0; (compteur<= pa.Iterations())&&(!pa.EtatSortieEquilibreGlobal()); compteur++)
//---//\\//\\// début de la boucle sur les itérations d'équilibres //\\//\\// 
        {// initialisation de la matrice et du second membre
         matglob->Initialise(0.);
         vglobin.Zero();
         vglobex.Zero();
         if (pa.ContactType())
            vcontact.Zero();
         vglobaal.Zero(); // puissance totale

         // init de var glob
         Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(compteur);
         
         // prise en compte du cas particulier ou l'utilisateur demande
         // une mise à jour des conditions limites à chaque itération
         if (cL_a_chaque_iteration)
           {// -- initialisation des coordonnees et des ddl a tdt en fonctions des
            // ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
            lesCondLim->MiseAJour_tdt
                   (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
                   ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
            // on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
            lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
         //        delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
            Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
           };
         
         // renseigne les variables définies par l'utilisateur via les valeurs déjà calculées par Herezh
//         if (compteur > 0)
           {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
         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
			
//---debug
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
//cout << "\ninitial Xtdt "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";cout << X_tdt(i)<<" ";}
//for (int j=1;j<=3;j++)  cout << X_tdt((i-1)*3+j)<<" ";};
//--fin-debug
			
         //  mise en place des conditions linéaires (ne comprend pas les conditions linéaires de contact éventuelles)
         lesCondLim->MiseAJour_condilineaire_tdt      
              (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
               ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
//---debug
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
//cout << "\naprès condlin Xtdt "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";cout << X_tdt(i)<<" ";}
//for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";for (int j=1;j<=3;j++)  cout << X_tdt((i-1)*3+j)<<" ";};
//--fin-debug
         // 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 ; 
         // 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);
         lesLoisDeComp->MiseAJour_umat_nbiter(compteur); // init pour les lois Umat éventuelles
         // actualisation des conditions de contact qui peuvent changer la largeur de bande, 
         // quand un noeud glisse d'une facette sur une voisine, peut changer la position du noeud
         // qui est projeté sur la facette dans le cas de l'algorithme cinématique
         if (pa.ContactType())
           { int niveau_substitution = 0; // on intervient sur toutes les matrices
             bool a_changer =  lescontacts->Actualisation(1);
             // mise à jour éventuelle des matrices de raideur en fonction du contact
             if (a_changer)
              {//bool changement_sur_matrice =
               Gestion_stockage_et_renumerotation_avec_contact
                          (premier_calcul,lesMail,a_changer,lesCondLim,lesRef
                           ,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
               matglob=tab_mato(1);
              };
           }
         else if (change_statut)// sinon il faut éventuellement tenir compte du cht du au CLL
           // NB: c'est pris en compte directement dans le contact, quand celui-ci est actif
          {bool premier_calcul_inter=false; // si pas de contact, normalement il n'y a pas à changer
           int niveau_substitution = 0; // on intervient sur toutes les matrices
           Gestion_stockage_et_renumerotation_sans_contact
                               (lescontacts,premier_calcul_inter,lesMail,change_statut
                                ,lesCondLim,lesRef,tab_mato,Ass.Nb_cas_assemb()
                                ,niveau_substitution);
          };

         // -- appel du calcul de la raideur et du second membre, énergies
         // dans le cas d'un calcul inexploitable arrêt de la boucle
         // avec prise en compte éventuelle  d'un newton modifié
         if ((deb_newton_modifie >= 0) && (compteur >= deb_newton_modifie) && (compteur <= fin_newton_modifie))
           { if (((compteur-deb_newton_modifie)  % nb_iter_NM)== 0)
               // on est au début du cycle -> on récupère la partie effort externes relative aux chargements
               { matsauve->Initialise(0.);
                 (*matsauve) -= (*matglob); // change de signe
                 // -- appel du calcul de la raideur et du second membre, énergies
                 // dans le cas d'un calcul inexploitable arrêt de la boucle
                 if (!RaidSmEner(lesMail,Ass,vglobin,(*matglob))) break;
                 // on sauvegade la raideur seule
                 (*matsauve) += (*matglob);  // sans les efforts externes
               }
             else
               // sinon on est en newton modifié, on utilise la matrice modifiée pour la raideur
               { (*matglob) += (*matsauve);
                 // on calcul uniquement le second membre
                 if (!SecondMembreEnerg(lesMail,Ass,vglobin)) break;
               };
           }
         else
           // sinon on regarde si on utilise de la raideur moyenne
           {if (deb_raideur_moyenne >= 0)
             { if ((compteur >= (deb_raideur_moyenne-nb_raideur_moyenne))
                  && (compteur <= deb_raideur_moyenne)&& (compteur <= fin_raideur_moyenne))
                 // phase de premier remplissage
                 { tab_matmoysauve_rempli++;
                   if (tab_matmoysauve_rempli > nb_raideur_moyenne) tab_matmoysauve_rempli = 1;
                   (*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1)->Initialise(0.);
                   // -- appel du calcul de la raideur et du second membre, énergies
                   // dans le cas d'un calcul inexploitable arrêt de la boucle
                   if (!RaidSmEner(lesMail,Ass,vglobin
                       ,(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))))
                       break;
                   // on met à jour la raideur
                   (*matglob) += (*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1));
                   (*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))
                             *= (1./nb_raideur_moyenne); // on prépare la moyenne
                 }
               else
                 // phase d'exploitation
                {  tab_matmoysauve_rempli++;
                   if (tab_matmoysauve_rempli > nb_raideur_moyenne) tab_matmoysauve_rempli = 1;
                   (*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1)->Initialise(0.);
                   // -- appel du calcul de la raideur et du second membre, énergies
                   // dans le cas d'un calcul inexploitable arrêt de la boucle
                   if (!RaidSmEner(lesMail,Ass,vglobin
                       ,(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))))
                       break;
                   (*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))
                                   *= (1./nb_raideur_moyenne); // on prépare la moyenne
                   // on met à jour la raideur utilisée
                   for (int ii=1;ii<=nb_raideur_moyenne;ii++)
                      (*matglob) += (*(*tab_tab_matmoysauve(ii))(1));
                };
             }
            else
             {// sinon calcul classique NR
              if (!RaidSmEner(lesMail,Ass,vglobin,(*matglob))) break;
             };
           };


         // calcul des maxi des puissances internes
         maxPuissInt = vglobin.Max_val_abs();
//cout << "\n debug AlgoNonDyna::CalEquilibre: maxPuissInt => "<<maxPuissInt
//     << " compteur= " << compteur <<flush;

         // dans le cas où l'on utilise de l'amortissement numérique le second membre
         // et la matrice de raideur sont modifiés
         if (pa.Amort_visco_artificielle())
           {Algori::Cal_mat_visqueux_num_stat(*matglob,forces_vis_num);
            vglobaal += forces_vis_num;
           };

         F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures
         if (pa.ContactType() == 4) // si contact on passe les efforts aux noeuds
              // on transfert les forces internes aux noeuds
              lesMail->Quelconque_glob_vers_local(X1,F_int_tdt,typQ_gene_int);
        
         // mise en place du chargement impose sur le second membre
         // et éventuellement sur la raideur en fonction de sur_raideur

         // 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;};

//cout << "\n debug AlgoNonDyna::CalEquilibre: vglobex => "; vglobex.Affiche();

			      // cas des efforts de contact, contribution second membre et matrice,
			      // suivant le type de contact on utilise ou on recalcule les reactions de contact éventuelles (contact et frottement)
         if (pa.ContactType()) // et des énergies développées pendant le contact
             // dans le cas où le calcul est inexploitable (pb dans le calcul) arrêt de la boucle
             if (!RaidSmEnerContact(lescontacts,Ass,vcontact,(*matglob))) break;
//cout << "\n debug AlgoNonDyna::CalEquilibre: vcontact => "; vcontact.Affiche();
         // on globalise tout pour les forces externes généralisées
         
         F_ext_tdt_prec = F_ext_tdt; // sauvegarde des valeurs de l'itération précédente
         if (pa.ContactType())
              vglobex += vcontact;
         maxPuissExt = vglobex.Max_val_abs();
         F_ext_tdt = vglobex; // sauvegarde des forces généralisées extérieures
         // second membre total
         vglobaal += vglobex ;vglobaal += vglobin ;
//cout << "\n debug AlgoNonDyna::CalEquilibre: vglobal => "; vglobal.Affiche();
         // calcul des reactions de contact pour les noeuds esclaves
         // dans le repere absolu ( pour la sortie des infos sur le contact)
         // et test s'il y a decollement de noeud en contact (pour les contacts actifs)
			      // mais ici, il n'y a pas de modification des éléments de contact (elles ont été faites dans  lescontacts->Actualisation())
         bool decol=false; // création et init de decol
         if (pa.ContactType()) 
			        lescontacts->CalculReaction(vglobin,decol,Ass.Nb_cas_assemb(),aff_iteration);
         //  - definition éventuelle de conditions limites linéaires de contact, en fonction des éléments du contact existant à ce niveau 
			      
         //  (certains contacts (par pénalisation par exemple) ne produise pas de conditions linéaires)
         const Tableau <Condilineaire>* tabCondLine=NULL;
         if ((pa.ContactType()==1) || (pa.ContactType()==3))
           tabCondLine = &(lescontacts->ConditionLin(Ass.Nb_cas_assemb()));
				  
         // - 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);

// ---exploratoire
//         //  mise en place des conditions linéaires (ne comprend pas les conditions linéaires de contact éventuelles)
//         lesCondLim->MiseAJour_condilineaire_tdt      
//              (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
//               ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
// ---exploratoire



         // -->> expression de la raideur et du second membre dans un nouveau repere
         //      mais ici on n'impose pas les conditons, on fait simplement le changement de repère
         lesCondLim->CoLinCHrepere_int((*matglob),vglobaal,Ass.Nb_cas_assemb(),vglob_stat);
         if (pa.ContactType()==1)
			        lesCondLim->CoLinCHrepere_ext((*matglob),vglobaal,*tabCondLine,Ass.Nb_cas_assemb(),vglob_stat);
         if (pa.ContactType()==3) // *** exploratoire
           lesCondLim->CoLinUneOpe_ext((*matglob),vglobaal,*tabCondLine,Ass.Nb_cas_assemb(),vglob_stat);
         // sauvegarde des reactions pour les  ddl bloques (simplement)
// en fait ne sert à rien, car les réactions maxi sont calculées dans condlin, mais comme c'est peut-être un peu spécial ici on laisse
// mais dans les autres algos c'est supprimé !!!!!
         lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom          

         // prise en compte des conditions imposée sur la matrice et second membres (donc dans le nouveau repère)
         lesCondLim->ImposeConLimtdt(lesMail,lesRef,(*matglob),vglobaal,Ass.Nb_cas_assemb()
			                            ,cas_combi_ddl,vglob_stat);
         if (pa.ContactType()!=3) // *** exploratoire
           // cas des conditions linéaires: répercutions sur matrices et second membre
           // (blocage de toutes les  conditions lineaires, quelque soit leur origines ext ou int donc contact éventuel)
           lesCondLim->CoLinBlocage((*matglob),vglobaal,Ass.Nb_cas_assemb(),vglob_stat);
         // calcul du maxi des reactions
         maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
         
         // 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());
         // calcul des énergies et affichage des balances
         // récupération (initialisation) des ddl  position à t+dt 
         lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
         // calcul de la variation de ddl / delta t
//         delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
         Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
         #ifdef UTILISATION_MPI
           // cas d'un  calcul //, pour l'instant seul le CPU 0 sont concerné
           if ((ParaGlob::Monde()->rank() == 0)&&(permet_affichage > 3))
         #else
           if (permet_affichage > 3)
         #endif
          { cout << "\n --- |max_var_DeltaDdl|= "<< max_var_delta_X
                 << " , |max_deltaDdl|= " << max_delta_X << flush;};
         // ---dans le cas du mode debug on sort éventuellement les infos au fil du calcul (un peu bricolé)

          if ((mode_debug > 0)||(pa.EtatSortieEtatActuelDansCVisu()))
           {bool a_sortir_debug=false; // pour éviter une division par 0 du test (compteur % mode_debug == 0)
            if (pa.EtatSortieEtatActuelDansCVisu()) {a_sortir_debug=true;}
            else if (compteur % mode_debug == 0) {a_sortir_debug=true;};
            if (a_sortir_debug)
         	  {// on passe les déplacements de tdt à t
             tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
         	   lesMail->Vect_glob_vers_local(TEMPS_t,X1,X_tdt,X1);
             // visualisation éventuelle au fil du calcul: essentiellement la déformée 
             VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
                          ,lesCondLim,lescontacts,resultats,type_incre,(icharge*1000000+compteur));
             tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
         	   // on remet les choses dans l'ordre initial
         	   lesMail->Vect_glob_vers_local(TEMPS_t,X1,X_t,X1);
         	  };
           };

         CalEnergieAffichage(delta_X,icharge,brestart,forces_vis_num);
         // test de convergence sur un increment
			      // en tenant compte éventuellement du contact (non decollement) decol = false systématiquement si pas de contact
			
decol = false; // pour debugger

         bool arret_iteration = false;
       #ifdef UTILISATION_MPI
       // seule le process 0 s'occupe de la convergence
       if (ParaGlob::Monde()->rank() == 0)
        {
       #endif
			      if (Convergence(aff_iteration,last_var_ddl_max,vglobaal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence)
            && !decol) 
			       { // on sort de la boucle  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, 
             {arret_iteration = true; }; //break;};
          }
         else if (arret_convergence) 
          {arret_iteration = true; }; //break;} // cas ou la méthode Convergence() demande l'arret
       #ifdef UTILISATION_MPI
        };
       temps_transfert_court.Mise_en_route_du_comptage(); // comptage cpu
       broadcast(*ParaGlob::Monde(), arret_iteration, 0);
       temps_transfert_court.Arret_du_comptage(); // fin comptage cpu
       #endif
         if (arret_iteration)
             break;
             
         // sinon on continue    
         // pour le pilotage ou pour l'accélération de convergence, sauvegarde du résidu
         if (pa.Line_search() || (acceleration_convergence)) 
            (*Vres) = vglobaal;
                  
         // ---- resolution ----
         tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu
         bool erreur_resolution_syst_lineaire = false; // init
         int nb_matrice_secondaire = tab_mato.Taille(); // = 1 par défaut, mais on peut en avoir d'autre
         int niveau_substitution = 1; // par défaut on utilise la matrice de raideur matglob = tab_mato(1)
       #ifdef UTILISATION_MPI
       // seule le process 0 fait la résolution globale
       if (ParaGlob::Monde()->rank() == 0)
        {
       #endif
         while (niveau_substitution <= nb_matrice_secondaire)
          { // on sauvegarde éventuellement le second membre
            if (nb_matrice_secondaire > 1) // cela veut dire que l'on est suceptible de faire plusieurs boucles
             { if (niveau_substitution == 1)
                 // init au premier passage
                 {vglobal_sauv = vglobaal;
                  matglob->Transfert_vers_mat(*tab_mato(niveau_substitution+1));
                 }
               else
                 {vglobaal = vglobal_sauv; // récup du second membre
                  // s'il y a une matrice de substitution supplémentaire, on sauvegarde 
                  if (nb_matrice_secondaire > niveau_substitution)
                     tab_mato(niveau_substitution)->Transfert_vers_mat
                                         (*tab_mato(niveau_substitution+1));
                  if (ParaGlob::NiveauImpression() >= 3)
                   { cout <<  "\n  nouvelle resolution du systeme avec la matrice "<<niveau_substitution
                          << " de substitution " << endl;
                   };
                 };
             };
         
            residu_final = vglobaal; // sauvegarde pour le post-traitement
            try
             {// ici sol en fait = vecglob qui est ecrase par la resolution
              sol = &(tab_mato(niveau_substitution)->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
              if (pa.ContactType()!=3) // *** exploratoire
                 lesCondLim->RepInitiaux( *sol,Ass.Nb_cas_assemb());
              erreur_resolution_syst_lineaire = false;
              break; // on sort du while
             }
            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
               }
           // il y a eu un pb de résolution
           niveau_substitution++;
          };
         tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu

         // cas où on a eu au final une erreur de résolution
         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
           };
         // idem si la norme de la solution est infinie
         // calcul du maxi de variation de ddl  
         maxDeltaDdl = sol->Max_val_abs(inSol); last_var_ddl_max=maxDeltaDdl; 
         double maxDeltatDdl_signe=(*sol)(inSol); // récupération de la grandeur signée
         if ((std::isinf(maxDeltaDdl))||( std::isnan(maxDeltaDdl)))
           {if (ParaGlob::NiveauImpression() > 2)
              cout << "\n resolution du systeme lineaire global (equilibre global) norme de delta_ddl infinie "
                   << maxDeltaDdl;
            Change_PhaseDeConvergence(-9); // on signale une divergence due à la résolution
            break; // arrêt si on avait détecté une erreur à la résolution
           };
         if (((ParaGlob::NiveauImpression() > 6) && (ParaGlob::NiveauImpression() < 10))
             || (permet_affichage > 6))
              {cout << "\n vecteur solution: "; sol->Affiche();};

     
         // 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());

       #ifdef UTILISATION_MPI
        }
       else // s'il s'agit d'un process de calcul élémentaire
        {sol = &vglobaal; // il faut affecter sol pour récupérer ensuite la solution
        };
       // le process 0 transmet aux autres process le vecteur résultat
       temps_transfert_long.Mise_en_route_du_comptage(); // comptage cpu
       
//// essai pour remplacer broadcast
//       int nb_process =  ParaGlob::Monde()->size();
//       mpi::request reqs1;
//       if (ParaGlob::Monde()->rank() == 0)
//         // NB: le process 0 c'est le main
//         {for (int i=1;i<nb_process;i++) // < absolu, donc le max c'est nb_process-1
//            {reqs1 = sol->Ienvoi_MPI(i, 38);}
//         }
//       else
//         {reqs1 = sol->Irecup_MPI(0,38);};
////       ParaGlob::Monde()->barrier();
//       reqs1.wait();
       
//         mpi::request Ienvoi_MPI(int dest, int tag) const
//             {return ParaGlob::Monde()->isend(dest,tag,v,taille);};
//         mpi::request Irecup_MPI(int source, int tag) const

       sol->Broadcast(0);
//       broadcast(*ParaGlob::Monde(), *sol, 0);
       // synchronisation ici de tous les process (à supprimer par la suite car n'est
       // pas nécessaire pour le déroulementa priori ?? )
//       ParaGlob::Monde()->barrier();
       temps_transfert_long.Arret_du_comptage(); // fin comptage cpu 
       #endif

         // effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
         lesCondLim->EffMarque();
         if ((pa.ContactType()==1) || (pa.ContactType()==3))
           lescontacts->EffMarque();
         
         // suite du pilotage
         // ------------------------------------------------------------
         // |on regarde s'il faut utiliser l'algorithme de line search |
         // ------------------------------------------------------------
         bool avec_line_search = false;
         if (pa.Line_search())
           { // la méthode de line_search incrémente la solution 
             // même s'il n'y a pas de mise en oeuvre de la méthode
             avec_line_search = Line_search1 
                        (*sauve_deltadept,puis_precedente,*Vres,lesMail,sol 
                        ,compteur,*sauve_dept_a_tdt,charge,vglobex,Ass,*v_travail,
                        lesCondLim,vglobaal,lesRef,vglobin,Ass.Nb_cas_assemb(),cas_combi_ddl,lesCourbes1D,lesFonctionsnD);
           }
         else      
           //cas ou l'on ne fait pas de line seach
           { // on regarde si l'on veut une accélération de convergence, par une méthode d'extrapolation
             if (acceleration_convergence)
         	    { sauve_sol = *sol;// on sauvegarde le vecteur solution, car = vglobal qui va être écrasé
         	      if (!(AccelerationConvergence(aff_iteration,(*Vres),lesMail,compteur,X_t,delta_X,charge,vglobex 
                      ,Ass,sauve_sol,lesCondLim,vglobaal,lesRef,vglobin,Ass.Nb_cas_assemb(),cas_combi_ddl,lesCourbes1D,lesFonctionsnD)
                       == 4))
         	         // 4 cas ou on a a priori convergé avec l'extrapolation, 
         	         // les positions finales des noeuds a été modifiée en conséquence
         	         // donc dans ce cas on ne fait rien, sinon on continue normalement
                   { // actualisation des ddl actifs a t+dt à chaque incrément
                     lesMail->PlusDelta_tdt(sauve_sol,Ass.Nb_cas_assemb());
                   }; 
         	    }
         	   else
         	   // cas normal, sans accélération  
               { // actualisation des ddl actifs a t+dt à chaque incrément
                 lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb());
//---debug
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
//cout << "\nXtdt+deltaddl "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";for (int j=1;j<=3;j++)  cout << X_tdt((i-1)*3+j)<<" ";};
//--fin-debug
               }; 
           };
        };
 
//---//\\//\\// fin de la boucle sur les itérations d'équilibres //\\//\\//
      // effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
      // car ici on n'est pas passé par cette endroit si l'on a convergé
      lesCondLim->EffMarque();
      
      // mise à jour des indicateurs contrôlés par le tableau: *tb_combiner
      if (tb_combiner != NULL) // cas d'un contrôle via des fonctions nD
       {if ((*tb_combiner)(1) != NULL)
           validation_calcul = (*tb_combiner)(1)->Valeur_pour_variables_globales()(1);
        if ((*tb_combiner)(2) != NULL)
           sortie_boucle_controler_par_fctnD = (*tb_combiner)(2)->Valeur_pour_variables_globales()(1);
       };

      if ((pa.ContactType()==1) || (pa.ContactType()==3)) lescontacts->EffMarque();
      
      // === gestion de la fin des itérations ===
    #ifdef UTILISATION_MPI
      // seule le process 0 a fait la résolution globale
      // il gère seul également la convergence, mais il doit tenir au courant les autres process
      Algori::Passage_indicConvergenceAuxProcCalcul();
      // ce qui permet le déroulement correct de la suite pour tous les process
    #endif

      if ((!Pilotage_fin_iteration_implicite(compteur))||(pa.EtatSortieEquilibreGlobal()))
//      if ((!Pilotage_fin_iteration_implicite(compteur))
//           && (!pa.EtatSortieEtatActuelDansBI()))
       { // cas d'une non convergence
         pas_de_convergence_pour_l_instant = 1;
         // 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();
         lescontacts->TversTdt(); // idem pour les contacts éventuels
				     // on remet indicCycleContact à 0 pour que le pilotage sur le temps se refasse
				     indicCycleContact = 0;
				
         // ------ cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
         if (Algori::PhaseDeConvergence() == -8)
           { int nb_incr_en_arriere = 3; // !!!!! nombre actuellement arbitraire -> par la suite mettre dans les para
             if (Controle_retour_sur_un_increment_enregistre(nb_incr_en_arriere,icharge))
               { // cas ou on a réussi à trouver un incrément sauvegardé adoc = maintenant icharge
                 int cas=2;
                 this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
                                        ,charge,lesCondLim,lescontacts,resultats,icharge);
                 // comme les conditions limites cinématiques peuvent être différentes en restart
                 // on libére 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());
                 // on remet à jour les éléments pour le contact s'il y du contact présumé
                 if (pa.ContactType())
                    lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
                 brestart = true; // on signale que l'on repars avec un restart
               };
             // sinon on ne fait rien, on se contente du pilotage de divergence existant  
           };        
         // ------ fin cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
       }
      else   
       { // --- sinon calcul correcte
         pas_de_convergence_pour_l_instant = 0;
         if (permet_affichage > 0)
          { cout << "\n --- |max_var_DeltaDdl|= "<< max_var_delta_X
                 << " , |max_deltaDdl|= " << max_delta_X << flush;};
         if (pa.ContactType())
           { // actualisation du contact en fonction du dernier incrément
             bool nevez_contact = lescontacts->Actualisation(0);
             // réexamen du contact pour voir s'il n'y a pas de nouveau element de contact
			          // en fait on  fera au plus deux passages supplémentaire, sinon la boucle peut être infini,
				         // à la fin du second passage, on regarde s'il y a décollement, si oui on relâche et on refait un passage
				         // sinon on valide
				         //I)--------------
				         if (indicCycleContact == 0 )
				          { bool nouveau_contact = lescontacts->Nouveau(lesMail->Max_var_dep_t_a_tdt());
                nevez_contact = nevez_contact || nouveau_contact;
                if (nevez_contact)
					             {indicCycleContact=1;} // on a de nouveau contact on refait le deuxième cycle
					           else 
					             // sinon, on n'a pas de nouveau contact, on regarde s'il y a du relachement	 
					             { indicCycleContact=2;}; 
              }
				         else if (indicCycleContact == 1)  
				          {indicCycleContact=2;} // pour regarder le relachement
				         else                              
					         {indicCycleContact=0;}; // pas de newcontact, ni de relachement donc c'est ok
				         //II)---------------
             bool relachement_contact = false;
				         if (indicCycleContact == 2)
				          {relachement_contact = lescontacts->RelachementNoeudcolle();
               if (relachement_contact)
					           {indicCycleContact=3;} // pour une dernière boucle d'équilibre
				           else                                        
					           {indicCycleContact=0;};// pas de relachement donc ok
				          };
            
             if (   (nevez_contact || relachement_contact)
                )
                 {int niveau_substitution = 0; // on intervient sur toutes les matrices
                  bool nouveau = (nevez_contact || relachement_contact);
                  //bool changement_sur_matrice =
                  Gestion_stockage_et_renumerotation_avec_contact
                          (premier_calcul,lesMail,nouveau,lesCondLim
                          ,lesRef,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
                  matglob=tab_mato(1);
                 };
			        }
			      else
			        // concerne ici le cas où c'est un problème sans contact (=contact non activé)
			        { indicCycleContact = 0; }; //pour le prochain increment 
			      if (!(pa.ContactType()) || (indicCycleContact == 0))
			        { 
// --- pour l'instant en test, mais normalement on fait la sauvegarde et la sortie d'info éventuelle avant le passage de t à tdt
// ce qui permet de différencier les grandeurs à t et celles à tdt	
// non !!! ce n'est pas une bonne chose, car il y a plein de grandeur que l'on ne sauve qu'à t, or t c'est la valeur de départ donc cela fait en pratique
// un décalage de temps d'un incrément !! c'est pas une bonne chose, il faudrait intervenir à plein d'endroit. donc on fait t et tdt = idem
//			
//            // 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);
// --- fin de la partie en test				
				
            // on regarde si l'on doit initialiser le prochain incrément avec le pas précédent
            if (pa.IniIncreAvecDeltaDdlPrec()) // si oui on sauvegarde le delta_X actuel / delta_t
             { // récupération (initialisation) des ddl  position à t et t+dt 
               lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
               lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
               // calcul de la variation de ddl / delta t
//               delta_X = X_tdt; delta_X -= X_t; delta_X /= pa.Deltat();
//         delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
               Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
               // si le pas de temps est trop petit il y aura un pb
               if (pa.Deltat() > ConstMath::unpeupetit)
                 {delta_prec_X = delta_X/pa.Deltat(); // on sauvegarde le delta_X qui a convergé
                  delta_t_precedent_a_convergence = pa.Deltat();
                 }
               else // sinon on neutralise
                 {delta_prec_X.Zero(); // on neutralise
                  delta_t_precedent_a_convergence = -1; // pour signaler une valeur non utilisable
                 }
             };
             
             // si on est sans validation, on ne fait rien, sinon on valide l'incrément
             // avec sauvegarde éventuelle
             if (validation_calcul)
               {// actualisation des ddl et des grandeurs actives de t+dt vers t
                lesMail->TdtversT();
                lescontacts->TdtversT();
                // cas du calcul des énergies, passage des grandeurs de tdt à t
                Algori::TdtversT();
                // on valide l'activité des conditions limites et condition linéaires
                lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
                tempsCalEquilibre.Arret_du_comptage(); // pour enregistrer
                //s'il y a remonté des sigma et/ou def aux noeuds et/ou calcul d'erreur
                bool change =false;  // calcul que s'il y a eu initialisation
                if(prepa_avec_remont) {change = Algori::CalculRemont(lesMail,type_incre,icharge);};
                if (change) // dans le cas d'une remonté il faut réactiver les bon ddls
                 {lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);};
                
                // --- sauvegarde de l'incrément si nécessaire: ici on est après le passage de tdt vers t donc, les grandeurs à t et tdt sont identiques !!
                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);
                tempsCalEquilibre.Mise_en_route_du_comptage(); // en remet en route pour la suite
               }; // -- fin du test: if (validation_calcul)

            premier_calcul = false;// -- on enregistre le fait que l'on n'est plus au premier passage

								  
            brestart = false; // dans le cas où l'on était en restart, on passe l'indicateur en cas courant       
            if (validation_calcul)
             {icharge++;
              // init de var glob
              Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
             };
			        }; //- fin du cas où l'incrément est validé pour l'équilibre avec le contact
		     }; // -- fin du cas ou le calcul converge
     // cas particulier où la sortie de la boucle est pilotée
     if (sortie_boucle_controler_par_fctnD && (!pas_de_convergence_pour_l_instant))
       break;

    }; // -- fin du while sur les incréments de charge
    // on remet à jour le nombre d'incréments qui ont convergés:
    if (validation_calcul)
      {icharge--;
       Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
       // dans le cas d'une suite de sous algo on signale qu'il y a validation
       if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
          (*tb_combiner)(3) = NULL;
      }
    else // si on ne valide pas le calcul, on reinitialise la charge
     // c-a-d l'avancement en temps, incrément et facteur multiplicatif
     // de manière à avoir les mêmes conditions de départ pour le prochain calcul
      { charge->Precedant(true);
        // dans le cas d'une suite de sous algo on signale qu'il n'y a pas validation
        if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
          (*tb_combiner)(3) = (*tb_combiner)(1);
      }  ;
    tempsCalEquilibre.Arret_du_comptage(); // temps cpu
  };

// dernière passe                  
void AlgoriNonDyna::FinCalcul(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)
 {
    // fin des calculs
    type_incre = OrdreVisu::DERNIER_INCRE;  
    Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
    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()));
 };

// accélération de convergence, suivant une méthode MMPE  (modified minimal polynomial extrapolation)
//   ou une méthode pour essayer de régler les oscillations en dents de scie : n'a pas l'air de marcher
// compteur : compteur d'itération
// retour = 0: l'accélération n'est pas active (aucun résultat, aucune action, aucune sauvegarde)
//        = 1: phase de préparation: sauvegarde d'info, mais aucun résultat
//        = 2: calcul de l'accélération mais ... pas d'accélération constatée
//        = 3: calcul de l'accélération et l'accélération est effective
// dans le cas différent de 0 et 1, le programme a priori, change le stockage des conditions
// limites, en particulier CL linéaire, mais avec des hypothèses, pour les sorties de réactions
// etc, il vaut mieux refaire une boucle normale avec toutes les initialisation ad hoc
// affiche: indique si l'on veut l'affichage ou non des infos
//  on travaille avec les deltaX, car les deltaX valent 0 pour les ddl bloqués (imposés)
int AlgoriNonDyna::AccelerationConvergence(bool affiche,const Vecteur& vres ,LesMaillages * lesMail 
          ,const int& compteur,const Vecteur& X_t,const Vecteur& delta_X,Charge* charge,Vecteur& vglobex 
          ,Assemblage& Ass ,const Vecteur& delta_delta_X,LesCondLim* lesCondLim,Vecteur& vglobal 
          ,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb 
          ,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)

 { // ne fonctionne que si le compteur est supérieur à 0
	if (compteur <= 0) return 0;
	int retour = 0; // par defaut
   if (cas_acceleration_convergence < 4)
//--- cas de la méthode MMPE  (modified minimal polynomial extrapolation) -----------------	
	{    
    
    // borne maxi du cycle qui varie de 1 à nb_vec_cycle
    // indique le nombre de vecteur actif
    int N = compteur % (nb_vec_cycle+2);
    if (N==0) N=(nb_vec_cycle+2);
    	
    //  --- 1) récupération des informations
    // calcul des nouvelles grandeurs des vecteurs d'entrées à l'accélération
    //    (pour toutes les affectations, on a un dimensionnement automatique)
    if (N == 1)
       { S_0 = delta_X; // affectation et dimensionnement automatique de S_1
         Vi(N)=delta_delta_X; 
         switch (cas_acceleration_convergence)
          { case 1: case 10:  Yi(N)=delta_X; break;
            case 2: Yi(N)=vres; break;
            case 3: Yi(N)=delta_delta_X; break;
          };
         return 1; 
       }
    else    
       { Vi(N) = delta_delta_X; // affectation et dimensionnement automatique de S_1
         switch (cas_acceleration_convergence)
          { case 1: case 10:  Yi(N)=delta_X; break;
            case 2: Yi(N)=vres; break;
            case 3: Yi(N)=delta_delta_X; break;
          };
       };
	retour = 2; // par défaut
	 
	//  --- 2) calcul d'une nouvelle position extrapolée   
	// préparation du calcul des coeff ai:
	//   calcul de la matrice et du second membre
	mat_ai.Initialise(0.);Sm_ai.Zero(); // on initialise l'ensemble des containers
	// mais seule la partie de 1 à N est utilisé
	for (int i=1;i<=N-1;i++)
	  { Sm_ai(i)=-(Vi(1) * Yi(i));
	    for (int j=1;j<=N-1;j++)
	       // projection des delta_Gi sur les Yi
	       mat_ai(i,j)=Yi(i) * (Vi(j+1)-Vi(j)); 
		};
	// pour éviter d'avoir une matrice singulière on met des 1 sur la partie de la diagonale restante
	for (int i=N;i<= nb_vec_cycle+1;i++)
	   mat_ai(i,i)=1.;	
	// calcul des coef ai	
	coef_ai = mat_ai.Resol_systID (Sm_ai);
	// construction du vecteur extrapolé, de position
	X_extrapol = S_0; // affectation et dimensionnement automatique de X_extrapol
	for (int i=1;i<=N-1;i++)
		X_extrapol += coef_ai(i) * Vi(i);
	X_extrapol += X_t;
	
//	cout << "\n coef_ai " << coef_ai ;
	
	//  --- 3) l'ancien résidu 
	double norme_residu_entree = vres.Max_val_abs();  

	//  --- 4) calcul du nouveau résidu 
	// maintenant on va calculer le résidu correspondant aux vecteur extrapolé de position
	int re_init = 0; // sert dans le cas d'un pb de calcul
       // 1) passage de ces nouvelles positions aux niveaux des maillages
    lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
       // 2 - initialisation de la puissance externe puis on la calcule
    vglobex.Zero();
    // mise en place du chargement impose, c-a-d calcul de la puissance externe
    // si pb on sort de la boucle
    if (!(charge->ChargeSecondMembre_Ex_mecaSolid
             (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
        { Change_PhaseDeConvergence(-10);};
    double  maxPuissExt = vglobex.Max_val_abs();
       // 3 - idem pour la puissance interne 
    vglobin.Zero();
    if (pa.ContactType())
        vcontact.Zero();
    vglobaal.Zero(); // puissance totale
    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
       // 4 - calcul du second membre et des énergies
    // dans le cas d'un calcul inexploitable on ressort en remettant les choses telles qu'elles
    // étaient en entrée
    if (!SecondMembreEnerg(lesMail,Ass,vglobin))
    	{ cout << "\n pb dans l'acceleration de convergence, on neutralise l'acceleration";
          re_init = 1;
    	};
    double  maxPuissInt = vglobin.Max_val_abs();
       // 5 - second membre total
    vglobal += vglobex ; vglobal += vglobin;
       // 6 - mise en place des conditions limites, vglobal contiend le nouveau résidu
       
    // sauvegarde des reactions aux ddl bloque
    lesCondLim->ReacApresCHrepere(vglobal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom          
       
    // mise en place des conditions limites, uniquement sur le second membre 
    ///!!!!! on considère que les conditions limites sont identiques à celle utilisée avec Xtd
    ///!!!!! au moment de la résolution (qui a précédé l'appel de AccelerationConvergence)
    ///!!!!! donc on ne s'occupe pas de CoLinCHrepere  
    lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobal,nb_casAssemb,cas_combi_ddl,vglob_stat);
    double nouvelle_norme = vglobal.Max_val_abs ();
    
// pour le débug !!!!!!!!!!!!!!!!!!!!!!!!!

/*	X_extrapol = X_t; 
	X_extrapol += delta_X;

	//  --- 4) calcul du nouveau résidu 
	// maintenant on va calculer le résidu correspondant aux vecteur extrapolé de position
	re_init = 0; // sert dans le cas d'un pb de calcul
       // 1) passage de ces nouvelles positions aux niveaux des maillages
    lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
       // 2 - initialisation de la puissance externe puis on la calcul
    vglobex.Zero();
    charge->ChargeSecondMembre_Ex_mecaSolid(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D);
    maxPuissExt = vglobex.Max_val_abs();
       // 3 - idem pour la puissance interne 
    vglobin.Zero();
       // 4 - calcul du second membre et des énergies
    // dans le cas d'un calcul inexploitable on ressort en remettant les choses telles qu'elles
    // étaient en entrée
    if (!SecondMembreEnerg(lesMail,Ass,vglobin))
    	{ cout << "\n pb dans l'acceleration de convergence, on neutralise l'acceleration";
          re_init = 1;
    	};
    maxPuissInt = vglobin.Max_val_abs();
       // 5 - second membre total ( vglobal est identique a vglobin)
    vglobal += vglobex ; 
       // 6 - mise en place des conditions limites, vglobal contiend le nouveau résidu
       
    // sauvegarde des reactions aux ddl bloque
    lesCondLim->ReacApresCHrepere(vglobal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom          
       
    // mise en place des conditions limites, uniquement sur le second membre 
    ///!!!!! on considère que les conditions limites sont identiques à celle utilisée avec Xtd
    ///!!!!! au moment de la résolution (qui a précédé l'appel de AccelerationConvergence)
    ///!!!!! donc on ne s'occupe pas de CoLinCHrepere  
    lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobal,nb_casAssemb,cas_combi_ddl);
    double new_norme = vglobal.Max_val_abs ();
    cout << "\n new_norme = " << new_norme;
*/

// fin pour le débug !!!!!!!!!!!!!!!!!!!!!!    
    
    
    
    
    //  --- 5) exploitation: comparaison des résidus
    if (norme_residu_entree < nouvelle_norme)
      { // dans le cas où le nouveau résidu est plus grand que l'ancien on ne fait rien, et on affiche éventuellement
    	if (affiche && (ParaGlob::NiveauImpression() > 1))
    	  cout << "\n ..pas d'acceleration....koz_res= " << norme_residu_entree << " nevez_res= " << nouvelle_norme;
        // on remet en place le vecteur position
        X_extrapol = X_t; X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
        lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
    	retour = 2;
    	}
    else 
      { // cas où on est meilleurs, petit message éventuel 
    	if (affiche && (ParaGlob::NiveauImpression() > 1))
    	  cout << "\n ... acceleration positive....koz_res= " << norme_residu_entree << " nevez_res= " << nouvelle_norme;
        // puis on appel de la convergence, pour voir si en plus on aurait convergé
        double maxReaction = MaX(maxPuissExt,maxPuissInt); // on simplifie
        bool arret_convergence; // ne sert pas ici
        double last_var_ddl_max = delta_delta_X.Max_val_abs (); // le dernier accroissement de ddl
        if (Convergence(affiche,last_var_ddl_max,vglobal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence))
           // a priori on a convergé donc on laisse le nouveau vecteur position en conséquence
          { retour = 4; }
        else 
          // c'est meilleur mais on n'a pas convergé donc on remet en place le vecteur position 
          { X_extrapol = X_t; X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
            lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
            retour = 3; 
           };
      };
    } 
	 
 //---- fin du cas de l'accélération avec la méthode MMPE  (modified minimal polynomial extrapolation)

 else 
 {
 // --- cas simple où l'on essaie de gérer le cas d'une oscillation infinie entre deux positions --------- 
  // tout d'abord on regarde si effectivement on est dans le cas en question, pour cela il faut que l'on ait au moins 4 iterations enregistrées
    
    // borne maxi du cycle qui varie de 1 à nb_vec_cycle (==2 a priori)
    // indique le nombre de vecteur actif
    int N = compteur % (nb_vec_cycle+2);
    if (N==0) N=(nb_vec_cycle+2);
    	
    
    Yi(N)=delta_X; //  1) stockage des delta_X 
	 Vi(N)(1) = vres.Max_val_abs(); //  2) stockage du maxi du résidu a priori non nul sinon cela veut dire que l'on a convergé
	 if (Vi(N)(1) < ConstMath::trespetit ) return 1; // ce n'est pas la pein de continuer
	       
	retour = 2; // par défaut
	if (compteur < 4) return 1;
	// sinon
	// def des 4 indices successifs
	int j1 = (N+1) % (nb_vec_cycle+2); if (j1 == 0) j1 = (nb_vec_cycle+2);
	int j2 = (N+2) % (nb_vec_cycle+2); if (j2 == 0) j2 = (nb_vec_cycle+2);
	int j3 = (N+3) % (nb_vec_cycle+2); if (j3 == 0) j3 = (nb_vec_cycle+2);
	int j4 = N ;
	// on regarde s'il y a matière à s'inquiéter
	// si le j4 > J3, J3 < J2, J2 > J1 : on a une forme de dent de scie ou
	// si le j4 < J3, J3 > J2, J2 < J1 : on a une forme de dent de scie
	double taux=0.15; // on se met une marge de 15%
	if (   (( Vi(j4)(1) > Vi(j3)(1)) && ( Vi(j3)(1) < Vi(j2)(1)) && ( Vi(j2)(1) > Vi(j1)(1)))
	    || (( Vi(j4)(1) < Vi(j3)(1)) && ( Vi(j3)(1) > Vi(j2)(1)) && ( Vi(j2)(1) < Vi(j1)(1))) )
	  // si on retombe deux à deux sur les mêmes résidus à taux près
	  {if ((!diffpourcent(Vi(j4)(1),Vi(j2)(1),Vi(j4)(1),taux)) && (!diffpourcent(Vi(j3)(1),Vi(j1)(1),Vi(j3)(1),taux)))
	    // dans ce cas on est dans une boucle: on choisit un vecteur x = à la moitié des deux précédents delta_delta_X
		 { X_extrapol = X_t; 
			X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
			X_extrapol += 0.5*delta_delta_X; 
			lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
			retour = 4;
		  }
		else retour = 1.;  
	   }
	else
	 { retour = 1.;
	  };	  
	 
 // --- fin cas simple où l'on essaie de gérer le cas d'une oscillation infinie entre deux positions --------- 	 
 };	   
	 
// retour
return retour;
};
   
       //---- gestion des commndes interactives --------------
    // écoute et prise en compte d'une commande interactive
    // ramène true tant qu'il y a des commandes en cours
bool AlgoriNonDyna::ActionInteractiveAlgo()
	{ cout << "\n commande? ";
	  return false;
	};
	
    // sortie du schemaXML: en fonction de enu
void AlgoriNonDyna::SchemaXML_Algori(ofstream& sort,const Enum_IO_XML enu) const 
  {
	switch (enu)
	{ case XML_TYPE_GLOBAUX :
  	   {
		 break;
		}
		case XML_IO_POINT_INFO :
		{
		 break;
		}
		case XML_IO_POINT_BI :
		{
		 break;
		}
		case XML_IO_ELEMENT_FINI :
		{
		 break;
		}
		case XML_ACTION_INTERACTIVE :
  	   {sort << "\n <!--  ********** algorithme implicite non dynamique ********************  -->"
  	         << "\n<xs:complexType name=\"INIT\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation> initialisation de l'algo "
  	         << "\n      </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n</xs:complexType>";
  	    sort << "\n<xs:complexType name=\"EXECUTION\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation> execution de l'ensemble de l'algo, sans l'initialisation et la derniere passe "
  	         << "\n      </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n</xs:complexType>";
  	    sort << "\n<xs:complexType name=\"FIN_ALGO_EXPLI\" >"
  	         << "\n    <xs:annotation>"
  	         << "\n      <xs:documentation>  fin de l'algo "
  	         << "\n      </xs:documentation>"
  	         << "\n    </xs:annotation>"
  	         << "\n</xs:complexType>";
		 break;
		}
		case XML_STRUCTURE_DONNEE :
		{
		 break;
		}
	};		
  };
	
// Calcul de l'équilibre de la pièce avec pilotage de longueur d'arc
void AlgoriNonDyna::Calcul_Equilibre_longueur_arc
           (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(NON_DYNA); // transfert info
    // on défini globalement que l'on a pas de combinaison de ddl    
    int cas_combi_ddl=0;     // c'est-à-dire que le seul ddl libre est X      
    // cas du chargement, on verifie egalement la bonne adequation des references
    charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD);   
    // 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 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 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
    total = std::min(total,nbddl);
    //  def de la matrice bande et d'un second membre globale
    // a priori matrice symetrique 
    // initialisation a zero
    MatBand matglob2(BANDE_SYMETRIQUE,demi,nbddl,0);
    // vérification d'une singularité éventuelle de la matrice de raideur 
    VerifSingulariteRaideurMeca(nbddl,*lesMail);
    // on groupe des vecteurs résidus sous forme de tableau pour des
    // raison de facilité de manipulation par la suite
    Tableau <Vecteur> tab_residu(2);
    tab_residu(1).Change_taille(nbddl);
    tab_residu(2).Change_taille(nbddl);
    Vecteur& vglobin = tab_residu(1); // puissance interne
    Vecteur& vglobex = tab_residu(2); // puissance externe
    Vecteur  vglobal(vglobin); // puissance totale
    vglobal += vglobex;
    
    // 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 & matglob2,const Mat_abstraite & matloc,
                    const DdlElement& tab_ddl,const Tableau<Noeud *>&tab_noeud)
                                  = & Assemblage::AssembMatSym;

    // dans le cas où l'on fait du line search on dimensionne des vecteurs
    Vecteur * sauve_deltadept,*sauve_dept_a_tdt,*Vres,*v_travail;
    if (pa.Line_search())
      { sauve_deltadept = new Vecteur(nbddl);
        Vres = new Vecteur(nbddl);
        sauve_dept_a_tdt = new Vecteur(nbddl);
        v_travail = new Vecteur(nbddl);        
       }
    
    //  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
       //  et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
       try {
            bool nevez_contact = lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
            int niveau_substitution = 0; // on intervient sur toutes les matrices
            bool premier_calcul = true;
            // mise à jour éventuelle de la matrice de raideur en fonction du contact
            //bool changement_sur_matrice =
            Gestion_stockage_et_renumerotation_avec_contact
                             (premier_calcul,lesMail,nevez_contact,lesCondLim
                             ,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
            matglob=tab_mato(1);
           }
       // sortie anormale de l'initialisation du contact
       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 inconnue
          {  cout << "\n **** >>>>   ERREUR inconnuee en  en initialisant le contact *****  ";
             if (ParaGlob::NiveauImpression() >= 4)
               cout  << "\n AlgoriNonDyna::InitAlgorithme(..";
             cout << endl;
          };
     };
    //--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())->seekp(0);
          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())->seekp(debut_increment);
         }                         
      }                           
    //--fin cas de restart et/ou de sauvegarde--------
    OrdreVisu::EnumTypeIncre type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul

    tempsInitialisation.Arret_du_comptage(); // temps cpu
    tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
   
    // 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_pilotage=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 max_delta_X=0.; //  le maxi du delta X
      double max_var_delta_X=0.; // idem d'une itération à l'autre
      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
      
      // 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);

      // initialisation de la variable puissance_précédente d'une itération à l'autre
      double puis_precedente = 0.; 
      Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
      Pilotage_du_temps(charge,arret_pilotage); // appel du Pilotage
      if (arret_pilotage) 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 et des conditions linéaires imposées
      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);
      
 /*     // mise en place du chargement impose sur le second membre
      // et éventuellement sur la raideur en fonction de sur_raideur
      vglobex.Zero();
//      bool sur_raideur = false; // pour l'instant pas de prise en compte sur la raideur
      bool sur_raideur = true; // essai
      charge->ChargeSMembreRaideur_Im_mecaSolid
                     (Ass,lesMail,lesRef,vglobex,sur_raideur,matglob2,assembMat,pa,lesCourbes1D);
      maxPuissExt = vglobex.Max_val_abs(); */
      
      //  boucle de convergence sur un increment
      Vecteur * sol; // pointeur du vecteur solution delta ddl classique
      Vecteur * solF; // idem pour la solution delta ddl pour uniquement la puissance externe
      
   //   bool ifresol = false;// drapeau pour le cas d'une charge sans resolution
      int compteur; // déclaré à l'extérieur de la boucle car utilisé après la boucle
		    bool arret_convergence = false;
      for (compteur = 0; compteur<= pa.Iterations();compteur++) 
        {// initialisation de la matrice et du second membre
         matglob2.Initialise (0.);
         vglobin.Zero();
         vglobex.Zero();
         if (pa.ContactType())
            vcontact.Zero();
         vglobaal.Zero(); // puissance totale
         // prise en compte du cas particulier ou l'utilisateur demande
         // une mise à jour des conditions limites à chaque itération
         if (cL_a_chaque_iteration)
           {// -- initialisation des coordonnees et des ddl a tdt en fonctions des
            // ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
            lesCondLim->MiseAJour_tdt
                   (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
                   ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
            // on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
            lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
         //        delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
            Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
           };
         // 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
         // init de var glob
         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
         // mise en place du chargement impose sur le second membre
         // et éventuellement sur la raideur en fonction de sur_raideur
         //  mise en place des conditions linéaires
         lesCondLim->MiseAJour_condilineaire_tdt      
              (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
               ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
         // 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
    //   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,matglob2,assembMat,pa,lesCourbes1D,lesFonctionsnD)))
           { Change_PhaseDeConvergence(-10);break;};
         maxPuissExt = vglobex.Max_val_abs();
         // -- appel du calcul de la raideur et du second membre, énergies
         // dans le cas d'un calcul inexploitable arrêt de la boucle
         if (!RaidSmEner(lesMail,Ass,vglobin,matglob2)) break;
         // calcul des maxi des puissances internes
         maxPuissInt = vglobin.Max_val_abs();
         // second membre total
         vglobal += vglobex ;   vglobal += vglobin;
         // initialisation des sauvegardes sur matrice et second membre
         lesCondLim->InitSauve(Ass.Nb_cas_assemb());
         // 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,matglob2,vglobal,Ass.Nb_cas_assemb()
			                            ,cas_combi_ddl,vglob_stat);
    // *************  il faut aussi les conditions limites sur vglobex***********
         // calcul du maxi des reactions
         maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
         // resolution 
   //      matglob2.Affiche(1,6,1,1,6,1);
  //       matglob2.Affiche(1,8,1,7,8,1);
    //     matglob2.Affiche(1,18,1,13,18,1);
 //        vglobal.Affiche();
      //   matglob2.Affiche(1,12,1,1,6,1);
      //  matglob2.Affiche(1,12,1,7,12,1);
     //    matglob2.Affiche(1,12,1,9,12,1);
     //    matglob2.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,vglobal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence)) 
          { // 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_convergence) {break;} // cas ou la méthode Convergence() demande l'arret
         // sinon on continue    
         // pour le pilotage, sauvegarde du résidu
         if (pa.Line_search()) (*Vres) = vglobal;
         // on résoud deux systèmes, correspondant pour le premier
         // aux déplacements classiques stockés en sortie dans tab_résidu(1)
         // ce dernier contenant en entrée le résidu interne + externe
         // tab_résidu(2) en entrée correspond uniquement aux puissances externes
         // en sortie il correspond aux delta ddl relativement uniquement aux puissances
         // externes       
         tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu
         matglob2.Resol_systID(tab_residu);
         tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu
         sol = &tab_residu(1); // solution d'incrément de déplacement classique
         solF = &tab_residu(2); // delta ddl pour le résidu externe uniquement
         // 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());
         
         // suite du pilotage
         // ------------------------------------------------------------
         // |on regarde s'il faut utiliser l'algorithme de line search |
         // ------------------------------------------------------------
         bool avec_line_search = false;
         if (pa.Line_search())
           { // la méthode de line_search incrémente la solution 
             // même s'il n'y a pas de mise en oeuvre de la méthode
             avec_line_search = Line_search1
                        (*sauve_deltadept,puis_precedente,*Vres,lesMail,sol 
                        ,compteur,*sauve_dept_a_tdt,charge,vglobex,Ass,*v_travail,
                        lesCondLim,vglobal,lesRef,vglobin,Ass.Nb_cas_assemb()
                        ,cas_combi_ddl,lesCourbes1D,lesFonctionsnD);
            }
         else      
           //cas ou l'on ne fait pas de line seach
           { // actualisation des ddl actifs a t+dt
             lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb()); 
             }  
//---//\\//\\// fin de la boucle sur les itérations d'équilibres //\\//\\//
        } 
      // 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();
         // cas du calcul des énergies, passage des grandeurs de tdt à t
         Algori::TdtversT();
         // sauvegarde de l'incrément si nécessaire
         tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
         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);
         tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
         // test de fin de calcul effectue dans charge via : charge->Fin()
         icharge++;
         Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
         }  
     } 
    // fin des calculs
    tempsCalEquilibre.Arret_du_comptage(); // temps cpu
    // fin des calculs
    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()));                 
  };

