254 lines
11 KiB
C++
254 lines
11 KiB
C++
|
// 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 "Distribution_CPU.h"
|
||
|
#include <boost/mpi/environment.hpp>
|
||
|
#include <boost/mpi/communicator.hpp>
|
||
|
#include <boost/serialization/string.hpp>
|
||
|
#include <boost/mpi.hpp>
|
||
|
namespace mpi = boost::mpi;
|
||
|
|
||
|
// constructeur par défaut
|
||
|
Distribution_CPU::Distribution_CPU():
|
||
|
tab_list_maillage_element(),tab_indic()
|
||
|
,total_elem(0)
|
||
|
,tab_vide_list_maillage_element()
|
||
|
{};
|
||
|
|
||
|
// constructeur de copie
|
||
|
Distribution_CPU::Distribution_CPU (const Distribution_CPU& a):
|
||
|
tab_list_maillage_element(a.tab_list_maillage_element)
|
||
|
,tab_indic(a.tab_indic),total_elem(a.total_elem)
|
||
|
,tab_vide_list_maillage_element()
|
||
|
{};
|
||
|
|
||
|
// calcul de l'équilibrage initiale
|
||
|
void Distribution_CPU::Calcul_Equilibrage_initiale(const LesMaillages * lesMaillages)
|
||
|
{
|
||
|
if (ParaGlob::Monde()->rank() == 0)
|
||
|
{ // on équilibre sur tous les cpu excepté le maître, qui lui ne calcule pas
|
||
|
int nb_proc_calcul = ParaGlob::Monde()->size() - 1;
|
||
|
// si nb_proc_calcul == 0 on ne peut pas continuer, aucun cpu n'étant disponible
|
||
|
// pour le calcul, on arrête
|
||
|
if (nb_proc_calcul == 0)
|
||
|
{cout << "\n *** erreur en calcul d'equilibrage initial: le nombre de cpu "
|
||
|
<< " disponible pour le calcul est nul ! on ne peut pas continuer "
|
||
|
<< " (il faut utiliser la version mono-processeur d'Herezh++ ! ) "
|
||
|
<< endl;
|
||
|
Sortie(1);
|
||
|
};
|
||
|
|
||
|
tab_indic.Change_taille(nb_proc_calcul);
|
||
|
|
||
|
// dans une première étape on ne s'intéresse qu'aux éléments
|
||
|
// on suppose que les éléments sont identiques en temps de calcul
|
||
|
// on repère les éléments par le numéro de maillage + le numéro d'élément, en cours
|
||
|
// on récupère le nombre total d'éléments
|
||
|
int nb_mail = lesMaillages->NbMaillage();
|
||
|
|
||
|
total_elem = 0; // init
|
||
|
Tableau <Tableau <bool > > inter(nb_mail); // inter utilisé ensuite pour dimensionner tab_indic
|
||
|
for (int i=1;i<=nb_mail;i++)
|
||
|
{int nb_elem_mail = lesMaillages->Nombre_element(i);
|
||
|
total_elem += nb_elem_mail;
|
||
|
inter(i).Change_taille(nb_elem_mail,false);
|
||
|
};
|
||
|
// on dimensionne tab_indic, tout est à false
|
||
|
tab_indic.Change_taille(nb_proc_calcul,inter);
|
||
|
// il faut que le nombre d'élément soit au moins >= au nb de proc de calcul
|
||
|
// pour que l'on puisse distribuer au moin un elem par proc de calcul
|
||
|
if (total_elem < nb_proc_calcul)
|
||
|
{cout << "\n *** erreur en calcul d'equilibrage initial: le nombre de cpu "
|
||
|
<< " disponible pour le calcul \n est inferieur au nb d'element total ! on ne peut pas continuer "
|
||
|
<< "\n (il faut utiliser la version mono-processeur d'Herezh++ ! ) "
|
||
|
<< endl;
|
||
|
Sortie(1);
|
||
|
};
|
||
|
|
||
|
|
||
|
// le nombre théorique d'élément par cpu
|
||
|
int nb_elem_un_cpu = total_elem/nb_proc_calcul; // arrondi inférieur
|
||
|
// on adapte le tableau de liste
|
||
|
tab_list_maillage_element.Change_taille(nb_proc_calcul);
|
||
|
for (int iproc =1;iproc <= nb_proc_calcul; iproc++)
|
||
|
{tab_list_maillage_element(iproc).Change_taille(nb_mail);
|
||
|
for (int imail=1; imail<= nb_mail; imail++)
|
||
|
tab_list_maillage_element(iproc)(imail).clear();
|
||
|
};
|
||
|
// on parcours tous les éléments et on remplit les tableaux
|
||
|
int iproc = 1; // le num du proc en cours
|
||
|
int nb_ele_enreg_iproc = 1; // init le nombre d'élément enregistré pour le proc
|
||
|
for (int imail=1;imail<=nb_mail;imail++)
|
||
|
{
|
||
|
int nb_ele = lesMaillages->Nombre_element(imail);
|
||
|
{list <int > * li_maillage_element = & tab_list_maillage_element(iproc)(imail); // init
|
||
|
// de la liste courante
|
||
|
for (int ile = 1; ile<=nb_ele;ile++,nb_ele_enreg_iproc++)
|
||
|
{ li_maillage_element->push_back(ile);
|
||
|
tab_indic(iproc)(imail)(ile)=true; // on signale
|
||
|
// on regarde s'il faut changer de cpu
|
||
|
// si c'est le dernier cpu, on ne change pas -> pour éviter
|
||
|
// les pb d'arrondi
|
||
|
if ((nb_ele_enreg_iproc > nb_elem_un_cpu)
|
||
|
&& (iproc < nb_proc_calcul) )
|
||
|
{iproc++;
|
||
|
nb_ele_enreg_iproc=1; // reinit du compteur
|
||
|
li_maillage_element = & tab_list_maillage_element(iproc)(imail); // pointage liste associée
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// passage de l'équilibrage à tous les cpu autres que 0
|
||
|
void Distribution_CPU::Passage_Equilibrage_aux_CPU()
|
||
|
{ //if (ParaGlob::Monde()->rank() == 0)
|
||
|
broadcast(*ParaGlob::Monde(), *this, 0);
|
||
|
// synchronisation ici de tous les process
|
||
|
// ParaGlob::Monde()->barrier();
|
||
|
|
||
|
// mise à jour de ParaGlob, qui peut transmettre à tous
|
||
|
// la liste des numéros d'éléments concernés
|
||
|
ParaGlob::param->Init_tableau(&tab_list_maillage_element);
|
||
|
};
|
||
|
|
||
|
|
||
|
// -- serialisation ---
|
||
|
// 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 Distribution_CPU::save(Archive & ar, const unsigned int version) const
|
||
|
{ // comme on a des listes on sauvegarde explicitement
|
||
|
int nb_proc_calcul = tab_list_maillage_element.Taille();
|
||
|
ar << std::string("Distribution_CPU:taille= ") << nb_proc_calcul ;
|
||
|
for (int i_proc=1;i_proc<= nb_proc_calcul; i_proc++)
|
||
|
{int nb_mail = tab_list_maillage_element(i_proc).Taille();
|
||
|
ar << std::string(" nb_mail= ")<< nb_mail ;
|
||
|
// on sauvegarde également le nombre total d'élément par maillage
|
||
|
// pour cela on se sert de tab_indic pour le premier cpu
|
||
|
for (int num_mail = 1; num_mail <= nb_mail;num_mail++)
|
||
|
ar << (int) tab_indic(1)(num_mail).Taille();
|
||
|
for (int imail=1;imail<=nb_mail;imail++)
|
||
|
{ const list <int >& list_maillage_element = tab_list_maillage_element(i_proc)(imail);
|
||
|
ar << std::string(" list:i_taille= ")<< (int) list_maillage_element.size() ;
|
||
|
list <int >::const_iterator il, ilfin= list_maillage_element.end();
|
||
|
for (il = list_maillage_element.begin(); il != ilfin; il++)
|
||
|
{ int truc = (*il);
|
||
|
ar << truc ;
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
}
|
||
|
|
||
|
// en lecture, le num de version permet de ce positionner sur une version particulière
|
||
|
// ==> dans notre cas, on ne sent sert pas pour l'instant: supposé tjs == 0
|
||
|
template<class Archive>
|
||
|
void Distribution_CPU::load(Archive & ar, const unsigned int version)
|
||
|
{ // opération inverse de save
|
||
|
std::string toto; int taille;
|
||
|
ar >> toto >> taille;
|
||
|
// on vérifie que c'est cohérent avec le nombre de CPU en cours
|
||
|
int nb_proc_calcul = ParaGlob::Monde()->size() - 1;
|
||
|
if (taille != nb_proc_calcul)
|
||
|
{cout << "\n **** erreur en recuperation d'une distribution CPU, le nombre de cpu "
|
||
|
<< " en cours: "<<nb_proc_calcul << "est different de celui archive: "
|
||
|
<< taille << " on ne peut pas continuer l'execution !!!";
|
||
|
Sortie(1);
|
||
|
};
|
||
|
|
||
|
// redimentionnement éventuel, si même taille, aucune action
|
||
|
tab_list_maillage_element.Change_taille(nb_proc_calcul);
|
||
|
// idem tab_indic
|
||
|
tab_indic.Change_taille(nb_proc_calcul);
|
||
|
|
||
|
total_elem = 0; // init
|
||
|
|
||
|
for (int i_proc=1;i_proc<= nb_proc_calcul; i_proc++)
|
||
|
{ int nb_mail;
|
||
|
ar >> toto >> nb_mail;
|
||
|
tab_list_maillage_element(i_proc).Change_taille(nb_mail);
|
||
|
tab_indic(i_proc).Change_taille(nb_mail);
|
||
|
// on va lire le nombre total d'éléments pour chaque maillage
|
||
|
for (int num_mail = 1; num_mail <= nb_mail;num_mail++)
|
||
|
{ int nb_elem_mail;
|
||
|
ar >> nb_elem_mail;
|
||
|
tab_indic(i_proc)(num_mail).Change_taille(nb_elem_mail,false);
|
||
|
};
|
||
|
for (int imail=1;imail<=nb_mail;imail++)
|
||
|
{ Tableau <bool > & tab_indic_cpu_mail = tab_indic(i_proc)(imail); // pour simplifier
|
||
|
// tab_indic_cpu_mail.Inita(false); // par défaut init à false pour tous les éléments
|
||
|
list <int >& list_maillage_element = tab_list_maillage_element(i_proc)(imail);
|
||
|
int size_list;
|
||
|
ar >> toto >> size_list;
|
||
|
if (size_list == list_maillage_element.size())
|
||
|
{// si la liste existante a la bonne taille, on ne fait que lire
|
||
|
int inter;
|
||
|
list <int >::iterator il, ilfin= list_maillage_element.end();
|
||
|
for (il = list_maillage_element.begin(); il != ilfin; il++)
|
||
|
{ar >> inter; (*il)=inter;
|
||
|
tab_indic_cpu_mail(inter)=true; // on rempli tab_indic
|
||
|
}
|
||
|
}
|
||
|
else // cas où la taille n'est pas bonne
|
||
|
{list_maillage_element.clear();
|
||
|
int inter; // élément de travail
|
||
|
for (int j=1;j<= size_list;j++)
|
||
|
{ar >> inter;
|
||
|
list_maillage_element.push_back(inter);
|
||
|
tab_indic_cpu_mail(inter)=true; // on rempli tab_indic
|
||
|
};
|
||
|
};
|
||
|
// mise à jour du nombre total d'élément
|
||
|
total_elem += list_maillage_element.size();
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// 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 Distribution_CPU::Lecture_base_info(ifstream& ent,const int cas)
|
||
|
{ // on récupère le tableau de list : tab_list_maillage_element
|
||
|
// on suit exactement la même procédure que pour archive
|
||
|
load(ent,cas);
|
||
|
};
|
||
|
// cas donne le niveau de sauvegarde
|
||
|
// = 1 : on sauvegarde tout
|
||
|
// = 2 : on sauvegarde uniquement les données variables (supposées comme telles)
|
||
|
void Distribution_CPU::Ecriture_base_info(ofstream& sort,const int cas)
|
||
|
{ // on sauvegarde le tableau de list : tab_list_maillage_element
|
||
|
// on suit exactement la même procédure que pour archive
|
||
|
save(sort,cas);
|
||
|
};
|
||
|
|
||
|
|