// 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/>.

/************************************************************************
 *     DATE:        23/01/97                                            *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  Definition d'un container pour une condition limite        *
 *           lineaire.                                                   *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *                                                                      *
 *     VERIFICATION:                                                    *
 *                                                                      *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *     !        !            !                                    !     *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 *     MODIFICATIONS:                                                   *
 *     !  date  !   auteur   !       but                          !     *
 *     ------------------------------------------------------------     *
 *                                                                $     *
 ************************************************************************/
#ifndef CONDILINEAIRE_H
#define CONDILINEAIRE_H

#include "Noeud.h"
#include "Nb_assemb.h"
#include <stdlib.h>
#ifdef UTILISATION_MPI
  #include <boost/serialization/split_member.hpp>
  #include <boost/serialization/string.hpp>
  #include "mpi.h"
  #include <boost/mpi/environment.hpp>
  #include <boost/mpi/communicator.hpp>
  #include <boost/serialization/string.hpp>
  #include <boost/mpi.hpp>
  namespace mpi = boost::mpi;
#endif


/// @addtogroup Les_classes_Matrices
///  @{
///


class Condilineaire
{   // surcharge de l'operator de lecture typée
    // en fait ces fonctions ne doivent pas être utilisées, elles existent uniquement
    // pour que Tableau_T puisse exister
    friend istream & operator >> (istream & ent, Condilineaire &)
      { Sortie(1); return ent;}; // erreur 
    // surcharge de l'operator d'ecriture typée
    friend ostream & operator << (ostream & sort , const Condilineaire &)
      { Sortie(1); return sort;}; // erreur 

  public :    
    // CONSTRUCTEURS :
    // par defaut
    Condilineaire () :
      pt(),val(),beta(0.),t_noeud(),t_enu(),casAssemb()
		    ,Uk_impose(ConstMath::tresgrand),iddl(0)
       {} ;
    // cas ou l'on connait toutes les infos, sauf Uk_impose, qui est une variable de stockage gérée indépendament 
    Condilineaire (Tableau <Enum_ddl>& t_enuu, const Tableau<int> & ptt, const Vecteur& vall
                 , double betar,int posiddl, const Tableau < Noeud *>& t_n) :
      pt(ptt),val(vall),beta(betar),iddl(posiddl),t_noeud(t_n)
      ,t_enu(t_enuu),casAssemb()
		    ,Uk_impose(ConstMath::tresgrand)
       {};
    // cas ou l'on connait les infos relatives uniquements aux noeuds, aux enum ddl
    Condilineaire(Tableau <Enum_ddl>& t_enuu,  const Tableau < Noeud *>& t_n) :
      t_noeud(t_n),t_enu(t_enuu),casAssemb()
      ,pt(),val(),beta(0.)
       ,Uk_impose(ConstMath::tresgrand),iddl(0)
       {};
    // de copie
    Condilineaire (const Condilineaire& a) :
      pt(a.pt),val(a.val),beta(a.beta),iddl(a.iddl),t_noeud(a.t_noeud)
      ,t_enu(a.t_enu),casAssemb(a.casAssemb),Uk_impose(a.Uk_impose)
        { };
    // DESTRUCTEUR :
    ~Condilineaire () {};
    // METHODES PUBLIQUES :
    // surcharge de l'opérateur =
    Condilineaire& operator = (const Condilineaire& cond);
    
    inline const Tableau<int>& Pt_t() const{ return pt;};
    Tableau<int>& ChangePt() { return pt;}; // acces lecture / écriture
    inline const Vecteur& Val() const{ return val;};
    Vecteur& Valchange() {return val;}; // acces lecture / écriture
    void ChangeCoeff(const Vecteur& v) {val=v;}; 
    inline double Beta() const { return beta;};
    double& BetaChange() { return beta;}; // acces lecture / écriture
    void ChangeBeta(const double& x) { beta = x;}; 

    // 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
    // cette valeur a imposer sur le ddl avant changement de repère, 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 les deux méthodes qui suivent
    void ChangeUk_impose(double Uk_new) {Uk_impose=Uk_new;};
    // lorsque la valeur retourné par Val_Uk_impose() == ConstMath::tresgrand, cela signifie qu'elle n'est pas a considérer
    const double & Val_Uk_impose() const {return Uk_impose;};

    Noeud* Noe() {return t_noeud(1);}; // acces lecture / écriture
    void Change_tab_enum(const Tableau <Enum_ddl> & t_enuu) {t_enu = t_enuu;};
    // le tableau de noeuds associé
    const Tableau < Noeud *>& TabNoeud() const { return t_noeud;}; 
    void ChangeTabNoeud(const Tableau < Noeud *>& t_n) {t_noeud = t_n;};

    // 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)
    inline  const int& Iddl() const { return iddl;};
    int& ChangeIddl() { return iddl;};  // acces lecture / écriture
	 
    // changement de la taille des tableaux de pointeur et valeurs
    void Change_taille(int taille)  {pt.Change_taille(taille); val.Change_taille(taille);};

    // mise en place des pointeurs de ddl d'assemblage 
    const Condilineaire& ConditionPourPointeursAssemblage(const Nb_assemb& nb_casAssemb);
    const Nb_assemb& CasAssemb() const {return casAssemb;};
    
    // retour du tableau d'énuméré correspondant aux coefficients de la CLL
    const Tableau <Enum_ddl >&  Tab_Enum() const {return t_enu;};
 
    // 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 DiffMaxiNumeroNoeud()const;
 
    // 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 Largeur_Bande(int& demi,int& total,const Nb_assemb& casAssemb);

    // affichage à l'écran des infos de la CL
	   void Affiche() const ;
	 
    //----- lecture écriture de restart -----
    // la lecture ramène en retour le numéro de maillage et le numéro de 
    // noeud sur lequel s'applique la condition limite
    // il est nécessaire ensuite d'utiliser la fonction Change_noeud pour`
    // attibuer le noeud
    void Lecture_base_info(Tableau <int>& numMaillage, istream& ent,Tableau <int>& numNoeud) ;
    void Ecriture_base_info(ostream& sort) ;
 #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 Pack_vecteur(Vecteur&  v,int rang) const;
   // taille du conteneur actuel de la condition  linéaire
   int Taille_Pack() const;
   // modification des infos à  partir de l'indice rang inclus en fonction du vecteur passé en paramètre
   // correspond à une désérialisation
   // ramène le positionnement dans  v pour un prochain enreg, sauf si > à la taille de v
   // dans ce cas ramène 0
   // on passe  un  pointeur  de fonctions qui ramène un noeud en fonction d'un numéro de maillage et d'un
   // numéro de noeud, ceci pour éviter de  passer toute l'instance de la classe Les_maillages
   template <class T> int UnPack_vecteur(T& instance,const Vecteur&  v,int rang,
                       Noeud & (T::*Ptfonc) (int num_mail,int  num_noeud) const );
 #endif

  protected :  
    // 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;
    
    
    // METHODES PROTEGEES :

 };
 // pour faire de l'inline: nécessaire avec les templates
 // on n'inclut que les méthodes templates
 #include "Condilineaire_2.cc"
 #define  Condilineaire_deja_inclus
 /// @}  // end of group

#endif