// 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 "Condilineaire.h"

    // surcharge de l'opérateur =
Condilineaire& Condilineaire::operator = (const Condilineaire& cond)
    { pt = cond.pt;
      val = cond.val;
      beta = cond.beta;
		    Uk_impose = cond.Uk_impose;
      iddl =cond.iddl;
      t_enu = cond.t_enu;
      t_noeud = cond.t_noeud;
      casAssemb = cond.casAssemb;
      return *this;
    };
    
// mise en place des pointeurs de ddl d'assemblage 
const Condilineaire& Condilineaire::ConditionPourPointeursAssemblage(const Nb_assemb& nb_casAssemb)
{ // pour les appels aux noeuds
  casAssemb = nb_casAssemb; int nb_assemb = casAssemb.n;
  // il s'agit ici de construire la condition pour les pointeurs d'assemblage
  int taille = pt.Taille();
  int nb_noeud = t_noeud.Taille();int itab=1;
  int nbddlfamille = taille / nb_noeud;
  for (int i_noe=1;i_noe <= nb_noeud;i_noe++)
    for (int i =1; i<= nbddlfamille; i++,itab++) 
      // récup du pointeur d'assemblage  
      { Enum_ddl enu = t_enu(itab); // pour simplifier
	       pt(itab) = t_noeud(i_noe)->Pointeur_assemblage(enu,nb_assemb);
	       // dans le cas où le pointeur n'existe pas, on regarde si l'on est en dynamique et que la condition linéaire est
		      // sur des positions, déplacement. Si le cas d'assemblage est de type dynamique, c'est sur les gammas qu'il faut récupérer les infos
        if (pt(itab) == -1)
          { if (Evolution_temporelle_du_calcul(ParaGlob::param->TypeCalcul_maitre()) == DYNAMIQUE)
             if (Dans_combinaison(1,enu)) //1 pour la combinaison dynamique
               { //on construit le ddl en gama équivalent aux ddl donné
                 Enum_ddl enugamma = Enum_ddl(((int)enu)-((int)PremierDdlFamille(enu)) + ((int)GAMMA1));
                 // on récupère le pointeur éventuelle
                 pt(itab) = t_noeud(i_noe)->Pointeur_assemblage(enugamma,nb_assemb);
               };
          };
       #ifdef MISE_AU_POINT
        if ( pt(itab) == -1 )
          { cout << "\nErreur : ddl X1 inexistant  pour le cas de charge " << nb_assemb
                 <<  '\n'
                 << "Condilineaire::ConditionPourPointeursAssemblage(.. 3\n";
            Sortie(1);
          };
       #endif
      };
  // retour
  return *this;	
};

 
// ramène la différence maxi qui existe entre les numéros de noeuds de la condition linéaire
// peut-être utilisé pour calculer une largeur de bande par exemple
// important: cette méthode n'est valide que si les numéros de noeuds sont tous différents
//            donc que la numérotation interne des noeuds a été changé pour cela
// NB: en fonctionnement normal, ce n'est pas le cas ! sauf dans le cas où un seul maillage existe
//     voir LesMaillages::Renumerotation( pour un exemple d'utilisation
int Condilineaire::DiffMaxiNumeroNoeud()const
  { // on va parcourir les noeuds de la condition
    int nb_noeud = t_noeud.Taille();
    int num_mini = t_noeud(1)->Num_noeud(); // initialisation
    int num_maxi = num_mini; // init
    for (int i_noe=2;i_noe <= nb_noeud;i_noe++)
      { Noeud & noe = *t_noeud(i_noe); // pour simplifier
        num_mini = MiN (num_mini, noe.Num_noeud());
        num_maxi = MaX(num_maxi,noe.Num_noeud());
      };
    return (num_maxi-num_mini);
  };


// ramène la largeur de bande en ddl
// à cause de la condition linéaire
// casAssemb : donne le cas d'assemblage a prendre en compte
// les condi linéaires ne donnent pas des largeurs de bande sup et inf égales !!!
// I/O : demi = la demi largeur de bande maxi ,
//        total = le maxi = la largeur sup + la largeur inf +1
void Condilineaire::Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb)
  { int nb_Assemb = casAssemb.n; // récup du numéro d'assemblage
    // on va parcourir les noeuds de la condition
    int nb_noeud = t_noeud.Taille();
    int noe=1;
    Noeud & nne = *t_noeud(noe);
    for ( int no=noe+1; no<=nb_noeud;no++)
      { Noeud & nno = *t_noeud(no);
        int di;
        if (nne.PosiAssemb(nb_Assemb) >= nno.PosiAssemb(nb_Assemb))
           di = nne.PosiAssemb(nb_Assemb) - nno.PosiAssemb(nb_Assemb)
                + nne.NB_ddl_actif_casAssemb(nb_Assemb);
        else
           di = nno.PosiAssemb(nb_Assemb) - nne.PosiAssemb(nb_Assemb)
                + nno.NB_ddl_actif_casAssemb(nb_Assemb);
        if ( di > demi)  demi = di;
        if ( 2*di > total) total = 2*di;
      };
  };



// affichaga à l'écran des infos de la CL
void Condilineaire::Affiche() const
  {  cout << "\n --- condition lineaire ---\n";
     cout << "\n tableau pt: " << pt;
     // le tableau des coefficients
     cout  << "\n val= "<< val;
     // la valeur de la condition linéaire
     cout  << "\n beta= " << beta << " Uk_impose= "<< Uk_impose << " ";
     // le repérage des noeuds supportant la condition linéaire
     int nb_noeud = t_noeud.Taille();
     cout << "\n  les noeuds: nb_noeud= " << nb_noeud << " ";
     for (int i=1; i<= nb_noeud; i++)
        cout << " num_mail= " << t_noeud(i)->Num_Mail() << " num_noeud= " << t_noeud(i)->Num_noeud() << " ";
     // le tableau des énumérés
     cout << "\n enumeres: t_enu= " << t_enu << " ";   
     // le numéro d'ordre du ddl modifié dans noeud
     cout << "\n numero d'ordre du ddl modifie dans le noeud " << iddl  << " \n";
   };
    
	 //----- lecture écriture de restart -----
void Condilineaire::Lecture_base_info
    (Tableau <int>& numMaillage, ifstream& ent,Tableau <int>& numNoeud) 
  {  // lecture du tableau
     pt.Entree(ent); 
     // le tableau des coefficients
     ent >> val;
     // la valeur de la condition linéaire
     ent >> beta >> Uk_impose;
     // le repérage des noeud supportant la condition linéaire
     string nom;int taille;
     ent >> nom >> taille;
     t_noeud.Change_taille(taille,NULL);
     numMaillage.Change_taille(taille);
     numNoeud.Change_taille(taille);
     for (int i=1;i<= taille; i++)
        ent >> numMaillage(i) >>numNoeud(i);
     // lecture des énumérés
     ent >> t_enu;   
     // lecture du numéro d'ordre du ddl modifié dans noeud
     ent >> iddl;
   };
void Condilineaire::Ecriture_base_info(ofstream& sort) 
  {  // sauvegarde du tableau
     pt.Sortir(sort); 
     // le tableau des coefficients
     sort << val;
     // la valeur de la condition linéaire
     sort << beta << " "<< Uk_impose << " ";
     // le repérage des noeuds supportant la condition linéaire
     int nb_noeud = t_noeud.Taille();
     sort << " nb_noeud= " << nb_noeud << " ";
     for (int i=1; i<= nb_noeud; i++)
        sort << t_noeud(i)->Num_Mail() << " " << t_noeud(i)->Num_noeud() << " ";
     // le tableau des énumérés
     sort << t_enu << " ";   
     // le numéro d'ordre du ddl modifié dans noeud
     sort << iddl  << " \n";
   };
   
#ifdef UTILISATION_MPI // spécifique au calcul parallèle
     // stockage dans un unique vecteur, des infos à  partir de l'indice rang inclus
     // correspond à une sérialisation des  infos
     // ramène le positionnement dans  v pour un prochain enreg, sauf si > à la taille de v
     // dans ce cas ramène 0
     int Condilineaire::Pack_vecteur(Vecteur&  v,int rang) const
       {
       
////debug Condilineaire::Pack_vecteur
//{      int rang_inter = rang;
//       cout << "\n debug Condilineaire::Pack_vecteur ";
//       // le tableau de pointeurs
//       int taille_pt = pt.Taille();
//       cout << "\n taille_pt "<<taille_pt << " rang= " << rang_inter;
//       rang_inter++;
//       for  (int i=1;i<=taille_pt;i++)
//        {cout << " pt(i)= "<<pt(i) << " rang= " << rang_inter;
//        rang++;};
//       // le vecteur val
//       int taille_val = val.Taille();
//       cout << "\n taille_val "<<taille_val << " rang= " << rang_inter;
//       v(rang) = taille_val;
//       for  (int i=1;i<=taille_val;i++)
//        {v(rang)= val(i);rang++;};
//       // beta
//       v(rang)=beta; rang++;
//       // Uk_impose
//       v(rang)=Uk_impose; rang++;
//       // le cas d'assemblage associé
//       rang = casAssemb.Pack_vecteur(v,rang);
//       // le tableau t_enu
//       int taille_t_enu = t_enu.Taille();
//       v(rang) = taille_t_enu;rang++;
//       for  (int i=1;i<=taille_t_enu;i++)
//        {v(rang)= t_enu(i);rang++;};
//       // iddl
//       v(rang)=iddl; rang++;
//       // le taleau t_noeud
//       // on considère que la numérotation est la même pour tous les cpu
//       // du coup on sauvegarde le numéro de maillage et le numéro de noeud
//       int taille_t_noeud = t_noeud.Taille();rang++;
//       v(rang)= taille_t_noeud;
//       for  (int i=1;i<=taille_t_noeud;i++)
//        {v(rang)= t_noeud(i)->Num_Mail();rang++;
//         v(rang)= t_noeud(i)->Num_noeud();rang++;
//        };
//       if (rang > v.Taille())  rang = 0;
//
//
//}
//fin debug Condilineaire::Pack_vecteur

         // le tableau de pointeurs
         int taille_pt = pt.Taille();
         v(rang) = taille_pt;rang++;
         for  (int i=1;i<=taille_pt;i++)
          {v(rang)= pt(i);rang++;};
         // le vecteur val
         int taille_val = val.Taille();
         v(rang) = taille_val;rang++;
         for  (int i=1;i<=taille_val;i++)
          {v(rang)= val(i);rang++;};
         // beta
         v(rang)=beta; rang++;
         // Uk_impose
         v(rang)=Uk_impose; rang++;
         // le cas d'assemblage associé
         rang = casAssemb.Pack_vecteur(v,rang);
         // le tableau t_enu
         int taille_t_enu = t_enu.Taille();
         v(rang) = taille_t_enu;rang++;
         for  (int i=1;i<=taille_t_enu;i++)
          {v(rang)= t_enu(i);rang++;};
         // iddl
         v(rang)=iddl; rang++;
         // le taleau t_noeud
         // on considère que la numérotation est la même pour tous les cpu
         // du coup on sauvegarde le numéro de maillage et le numéro de noeud
         int taille_t_noeud = t_noeud.Taille();
         v(rang)= taille_t_noeud;rang++;
         for  (int i=1;i<=taille_t_noeud;i++)
          {v(rang)= t_noeud(i)->Num_Mail();rang++;
           v(rang)= t_noeud(i)->Num_noeud();rang++;
          };
         if (rang > v.Taille())  rang = 0;
         

         
         
         return rang;
       };
       
     // taille du conteneur actuel de la condition  linéaire
     int Condilineaire::Taille_Pack() const
       {int taille_pack = 0; // init
        taille_pack += pt.Taille() + 1;
        taille_pack += val.Taille() + 1;
        taille_pack += 2; // beta et Uk
        taille_pack += casAssemb.Taille_Pack();
        taille_pack += t_enu.Taille()+1;
        taille_pack += 1; // iddl
        taille_pack += 2*t_noeud.Taille()+1;
        return taille_pack;
       };
       
#endif

/*
    
   // VARIABLES PROTEGEES :
   Tableau<int>  pt;  //tableau des pointeurs de ddl concerne, pt(i) = la position du ddl i
                      // dans la matrice globale
   Vecteur val;    // tableau des coefficients de la condition lineaire
   double beta;  // valeur beta a laquelle est egale la condition lineaire
   // dans le cas de la mise en place de la CL à partir d'un changement de repère, on peut stocker la valeur imposée avant chg de repère
   double Uk_impose; // valeur a imposer sur le ddl avant changement de repère, qui correspondra à beta après chg de repère
   // Uk_impose sert uniquement de stockage, mais n'est pas forcément cohérent avec la CL, sa manipulation est faite en dehors de la classe
   // via : ChangeUk_impose et Val_Uk_impose
   Nb_assemb casAssemb; // le cas d'assemblage associé
   
   // le blocage de  condition est appliquee sur le ddl numero "iddl" du noeud "noe"
   Tableau <Enum_ddl > t_enu; // tableau des identificateur de ddl de la CLL
                    // t_enu(1) est l'identificateur du  ddl qui est bloqué pour la CLL
                    // lorsque seul t_enu(1) existe, cela signifie qu'il faut construire
                    // les indices,
                    
   // iddl -> le numéro d'ordre dans sa famille, du ddl bloqué
   // NB: ce n'est pas la position du ddl dans le noeud !!, cette dernière est: Tab_Enum()(1)
   int iddl;
   // le tableau des noeuds de la CLL, le premier contient la condition
   Tableau < Noeud *> t_noeud;
   
*/