// 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:        03/01/2022                                          *
 *                                                                $     *
 *     AUTEUR:      G RIO   (mailto:gerardrio56@free.fr)                *
 *                                                                $     *
 *     PROJET:      Herezh++                                            *
 *                                                                $     *
 ************************************************************************
 *     BUT:  une classe qui a pour objectif de gérer, calculer,         *
 *           certaines particularités liées à la parallélisation:       *
 *           - l'équilibrage de charge de calcul sur les processeurs    *
 *                                                                $     *
 *     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''     *
 ************************************************************************/
 
#ifndef DISTRIBUTION_CPU_H
#define DISTRIBUTION_CPU_H

#include <boost/serialization/split_member.hpp>



#include "LesMaillages.h"
#include "LesContacts.h"
#include "Basiques.h"

/**
*
*     BUT:  une classe qui a pour objectif de gérer, calculer,
*           certaines particularités liées à la parallélisation:
*           - l'équilibrage de charge de calcul sur les processeurs
*           La classe sert de conteneur basique: des tableaux de numéros
*           L'idée est d'avoir un accès rapide aux données.
*           NB: Par contre si les maillages évolues (nb noeuds, nb éléments, numérotations)
*           il faut réinitialiser les tableaux
*
*
* \author    Gérard Rio
* \version   1.0
* \date      03/01/2022
* \brief     classe pour gérer certaines particularités liées à la parallélisation, ex: l'équilibrage de charge de calcul sur les processeurs
*
*/

class Distribution_CPU 
{
  public :
    // CONSTRUCTEURS :
    // par défaut
    Distribution_CPU();
           
    // constructeur de copie
    Distribution_CPU (const Distribution_CPU& a);

    // DESTRUCTEUR :
    ~Distribution_CPU() {};
    
    // METHODES PUBLIQUES :
    // calcul de l'équilibrage initiale par le cpu 0
    void Calcul_Equilibrage_initiale(const LesMaillages *   lesMaillages, LesContacts * lesContacts);
    // passage de l'équilibrage à tous les cpu autres que 0
    void Passage_Equilibrage_aux_CPU();
    // retour de tab_list_maillage_element(i)(j) contient la liste
    // pour le maillage j des num <élément> associés au cpu i
    // NB: si la taille du tableau == 0, cela signifie qu'il n'a pas encore été construit
    //     on peut dans ce cas déclancher un calcul d'équilibrage initial
    const Tableau <Tableau < list <int > > > * Tableau_element_CPU_en_cours() const
       {return &tab_list_maillage_element;};

    // retour de la liste des éléments relatif au cpu en cours
    // si c'est le cpu 0, retourne un tableau vide
    const Tableau < list <int > > & List_element_CPU_en_cours() const
       {if (ParaGlob::Monde()->rank() != 0)
          return tab_list_maillage_element(ParaGlob::Monde()->rank());
        else return tab_vide_list_maillage_element;
       };
    // retour de tab_list_maillage_noeud(i)(j) contient la liste
    // pour le maillage j des num <noeud> associés au cpu i
    // NB: si la taille du tableau == 0, cela signifie qu'il n'a pas encore été construit
    //     on peut dans ce cas déclancher un calcul d'équilibrage initial
    const Tableau <Tableau < list <int > > > * Tableau_noeud_CPU_en_cours() const
       {return &tab_list_maillage_noeud;};

    // retour de la liste des noeud relatif au cpu en cours
    // si c'est le cpu 0, retourne un tableau vide
    const Tableau < list <int > > & List_noeud_CPU_en_cours() const
       {if (ParaGlob::Monde()->rank() != 0)
          return tab_list_maillage_noeud(ParaGlob::Monde()->rank());
        else return tab_vide_list_maillage_noeud;
       };
       
    // retourne le tableau indicateur permettant de dire si un élément est concerné par un CPU
    // tab_indic(CPU)(mail)(ele) : = 1 si l'élément ele du maillage mail est concerné
    // par le CPU
    const  Tableau <Tableau < Tableau  <bool > > > * Tab_indique_CPU_en_cours() const {return  &tab_indic;};

    // indicateur permettant de dire si un élément est concerné par un CPU donné
    // tab_indic(CPU)(mail)(ele) : = 1 si l'élément ele du maillage mail est concerné
    // par le CPU
    bool Element_concerner(int CPU,int mail,int ele) const
       {return tab_indic(CPU)(mail)(ele);};
       
    // récup du nombre total d'éléments, cumul sur tous les maillages
    int NB_total_element() const {return total_elem ;};
       
    // retourne le tableau indicateur permettant de dire si un noeud est concerné par un CPU
    // tab_indic_noeud(CPU)(mail)(ne) : = 1 si le noeud ne du maillage mail est concerné
    // par le CPU
    const  Tableau <Tableau < Tableau  <bool > > > * Tab_indique_noeud_CPU_en_cours() const {return  &tab_indic_noeud;};

    // indicateur permettant de dire si un noeud est concerné par un CPU donné
    // tab_indic_noeud(CPU)(mail)(ne) : = 1 si le noeud ne du maillage mail est concerné
    // par le CPU
    bool Noeud_concerner(int CPU,int mail,int ne) const
       {return tab_indic_noeud(CPU)(mail)(ne);};
       
    // récup du nombre total de noeud, cumul sur tous les maillages
    int NB_total_noeud() const {return total_noeud ;};

    // affichage des infos relatives à la distribution
    void Affiche() const ;
       
    //============= lecture écriture dans base info ==========
    // cas donne le niveau de la récupération
    // = 1 : on récupère tout
    // = 2 : on récupère uniquement les données variables (supposées comme telles)
    void Lecture_base_info(istream& ent,const int cas);
    // cas donne le niveau de sauvegarde
    // = 1 : on sauvegarde tout
    // = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
    void Ecriture_base_info(ostream& sort,const int cas);

    
  private :
    // VARIABLES PROTEGEES :
    
    // les conteneurs sont basiques, en particulier on ne stocke pas
    // un pointeur sur les maillages, du coup il faut tout sauvegarder et
    // tout relire, mais normalement c'est une opération qui s'effectue peu souvent (à voir !!)
    
    // tab_list_maillage_element(i)(j) contient la liste
    // pour le maillage j des num <élément> associés au cpu i
    Tableau <Tableau < list <int > > > tab_list_maillage_element;
    // un tableau vide, qui correspond au cas du CPU 0
    Tableau < list <int > >  tab_vide_list_maillage_element;
    
    // indicateur permettant de dire si un élément est concerné par un CPU donné
    // tab_indic(CPU)(mail)(ele) : = 1 si l'élément ele du maillage mail est concerné
    // par le CPU
    Tableau <Tableau < Tableau  <bool > > > tab_indic;
    
    int total_elem ; // nombre total d'éléments cumulé sur tous les maillages
    int total_elem_maitre; // nombre total d'éléments maitres cumulé sur tous les maillages;
    
    // tab_list_maillage_noeud(i)(j) contient la liste
    // pour le maillage j des num <noeud> associés au cpu i
    // c-a-d appartenent à un élément de maillage associés au cpu
    // important: un noeud peut être associés à plusieurs cpu
    Tableau <Tableau < list <int > > > tab_list_maillage_noeud;
    // un tableau vide, qui correspond au cas du CPU 0
    Tableau < list <int > >  tab_vide_list_maillage_noeud;
    
    // indicateur permettant de dire si un noeud est concerné par un CPU donné
    // tab_indic_noeud(CPU)(mail)(ne) : = 1 si le noeud ne du maillage mail est concerné
    // par le CPU
    Tableau <Tableau < Tableau  <bool > > > tab_indic_noeud;
    
    int total_noeud; // nombre total de noeud cumulé sur tous les maillages

 
    // METHODES PROTEGEES :
    // -- serialisation ---
    // déclaration en friend pour l'acces direct de boost
    friend class boost::serialization::access;
    // on spécialise la sauvegarde et la restitution
    // version == 0 pour la première sauvegarde et ensuite > 0
    // NB: c'est toujours la version en cours au moment de la sauvegarde
    // ==> dans notre cas, on ne sent sert pas pour l'instant: supposé tjs == 0
    template<class Archive>
    void save(Archive & ar, const unsigned int version) const;
    // en lecture, le num de version permet de ce positionner sur une version particulière
    template<class Archive>
    void load(Archive & ar, const unsigned int version);
    // la macro suivante va définir automatiquement la méthode : "serialize"
    BOOST_SERIALIZATION_SPLIT_MEMBER()
    // pour mémoire on indique l'entête de la méthode "serialize"
//    // la méthode serialize fonctionne dans les deux sens: lecture et écriture dans ar
//    // << et >> est remplacé par &
//    // le choix dépend du fait que ar est un flux entrant ou sortant
//    template<class Archive>
//    void serialize(Archive & ar, const unsigned int version);

 };
 
#endif
