// 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) . // // 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 . // // For more information, please consult: . #include "Distribution_CPU.h" #include #include #include #include namespace mpi = boost::mpi; // constructeur par défaut Distribution_CPU::Distribution_CPU(): tab_list_maillage_element(),tab_indic() ,total_elem(0),total_elem_maitre(0) ,tab_vide_list_maillage_element() ,tab_list_maillage_noeud(),tab_indic_noeud() ,total_noeud(0) ,tab_vide_list_maillage_noeud() {}; // 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),total_elem_maitre(a.total_elem_maitre) ,tab_vide_list_maillage_element() ,tab_list_maillage_noeud(a.tab_list_maillage_noeud) ,tab_indic_noeud(a.tab_indic_noeud),total_noeud(a.total_noeud) ,tab_vide_list_maillage_noeud() {}; // calcul de l'équilibrage initiale void Distribution_CPU::Calcul_Equilibrage_initiale(const LesMaillages * lesMaillages, LesContacts * lesContacts) { 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); }; // 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 > inter(nb_mail); // inter utilisé ensuite pour dimensionner tab_indic Tableau > inter_noeud(nb_mail); // inter utilisé ensuite pour dimensionner tab_indic_noeud 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); int nb_noeud_mail = lesMaillages->Nombre_noeud(i); total_noeud += nb_noeud_mail; inter_noeud(i).Change_taille(nb_noeud_mail,false); }; // on dimensionne tab_indic, tout est à false tab_indic.Change_taille(nb_proc_calcul,inter); tab_indic_noeud.Change_taille(nb_proc_calcul,inter_noeud); // il faut que le nombre d'élément soit au moins >= au nb de proc de calcul // pour que l'on puisse distribuer au moins 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); tab_list_maillage_noeud.Change_taille(nb_proc_calcul); for (int iproc =1;iproc <= nb_proc_calcul; iproc++) {tab_list_maillage_element(iproc).Change_taille(nb_mail); tab_list_maillage_noeud(iproc).Change_taille(nb_mail); for (int imail=1; imail<= nb_mail; imail++) {tab_list_maillage_element(iproc)(imail).clear(); tab_list_maillage_noeud(iproc)(imail).clear(); }; }; // on différencie le cas sans et avec contact // dans le cas sans contact on parcours linéairement tous les maillages successivement int nb_mail_Esclave = lesMaillages->NbEsclave(); // def du nombre de maillages esclaves // si aucun esclave if (nb_mail_Esclave==0) {// 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 * li_maillage_element = & tab_list_maillage_element(iproc)(imail); // init list * li_maillage_noeud = & tab_list_maillage_noeud(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 // idem pour les noeuds Element& ele = lesMaillages->Element_LesMaille(imail,ile); Tableau& tab_N = ele.Tab_noeud(); int nb_N = tab_N.Taille(); for (int ne =1;ne<=nb_N;ne++) {int num_noeud = tab_N(ne)->Num_noeud(); tab_indic_noeud(iproc)(imail)(num_noeud)=true; li_maillage_noeud->push_back(num_noeud); }; // 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 li_maillage_noeud = & tab_list_maillage_noeud(iproc)(imail); }; }; }; }; } else // cas où on a des maillages maîtres particuliers donc du contact {// l'idée est de tout d'abord, ventiler les éléments des maillages maîtres ou en autocontact // de manière à l'exécution qu'il y ait une ventilation: // 1) de la recherche du contact // 2) potentiellement (si contact il y a) d'élément de contact int iproc = 1; // le num du proc en cours // on va calculer le nb d'éléments maitres (environ) qui doivent être attribué à chaque cpu int nbmailautocontact = lesContacts->NbmailAutoContact(); // int nbmailMaitre = nb_mail-(nb_mail_Esclave-nbmailautocontact); // def du nombre de maillage maitres // ce sont les derniers maillages total_elem_maitre = 0; // init for (int i=1+nb_mail_Esclave-nbmailautocontact;i<=nb_mail;i++) {int nb_elem_mail = lesMaillages->Nombre_element(i); total_elem_maitre += nb_elem_mail; }; int nb_elem_maitre_un_cpu = total_elem_maitre/nb_proc_calcul; // arrondi inférieur // // --- debug // cout << "\n *** debug Distribution_CPU::Calcul_Equilibrage_initiale" // << "\n total_elem_maitre= "<< total_elem_maitre // << " nb_elem_maitre_un_cpu= "<< nb_elem_maitre_un_cpu; // //--- fin debug // on distribue en parcourant les maillages maîtres int nb_ele_enreg_iproc = 1; // init le nombre d'élément enregistré pour le proc for (int imail=1+nb_mail_Esclave-nbmailautocontact;imail<=nb_mail;imail++) { int nb_ele = lesMaillages->Nombre_element(imail); {list * li_maillage_element = & tab_list_maillage_element(iproc)(imail); // init list * li_maillage_noeud = & tab_list_maillage_noeud(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 // idem pour les noeuds Element& ele = lesMaillages->Element_LesMaille(imail,ile); Tableau& tab_N = ele.Tab_noeud(); int nb_N = tab_N.Taille(); for (int ne =1;ne<=nb_N;ne++) {int num_noeud = tab_N(ne)->Num_noeud(); tab_indic_noeud(iproc)(imail)(num_noeud)=true; li_maillage_noeud->push_back(num_noeud); }; // 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_maitre_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 li_maillage_noeud = & tab_list_maillage_noeud(iproc)(imail); }; }; }; }; //// --- debug //cout << "\n *** debug Distribution_CPU::Calcul_Equilibrage_initiale"; //cout << "\n 1) elements maitres pour chaque proc : "; //for (int iproc = 1;iproc <= nb_proc_calcul; iproc++) // {for (int imail=1+nb_mail_Esclave-nbmailautocontact;imail<=nb_mail;imail++) // {list * li_maillage_element = & tab_list_maillage_element(iproc)(imail); // init // list ::iterator il,ilfin = li_maillage_element->end(); // for (il = li_maillage_element->begin();il != ilfin; il++) // cout << "\n proc("< * li_maillage_element = & tab_list_maillage_element(iproc)(imail); // init // list ::iterator il,ilfin = li_maillage_element->end(); // for (il = li_maillage_element->begin();il != ilfin; il++) // cout << "\n proc("<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,&tab_indic ,&tab_list_maillage_noeud,&tab_indic_noeud); }; // -- 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 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(); // maintenant tab_list_maillage_element for (int imail=1;imail<=nb_mail;imail++) { const list & list_maillage_element = tab_list_maillage_element(i_proc)(imail); ar << std::string(" list_maillage_element:i_taille= ")<< (int) list_maillage_element.size() ; list ::const_iterator il, ilfin= list_maillage_element.end(); for (il = list_maillage_element.begin(); il != ilfin; il++) { int truc = (*il); ar << truc ; }; }; // on sauvegarde également le nombre total de noeud par maillage // pour cela on se sert de tab_indic_noeud pour le premier cpu for (int num_mail = 1; num_mail <= nb_mail;num_mail++) ar << (int) tab_indic_noeud(1)(num_mail).Taille(); // puis tab_list_maillage_noeud for (int imail=1;imail<=nb_mail;imail++) { const list & list_maillage_noeud = tab_list_maillage_noeud(i_proc)(imail); ar << std::string(" list_maillage_noeud:i_taille= ")<< (int) list_maillage_noeud.size() ; list ::const_iterator il, ilfin= list_maillage_noeud.end(); for (il = list_maillage_noeud.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 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: "<> toto >> nb_mail; tab_list_maillage_element(i_proc).Change_taille(nb_mail); tab_indic(i_proc).Change_taille(nb_mail); tab_list_maillage_noeud(i_proc).Change_taille(nb_mail); tab_indic_noeud(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); }; // puis les tableaux for (int imail=1;imail<=nb_mail;imail++) { Tableau & tab_indic_cpu_mail = tab_indic(i_proc)(imail); // pour simplifier list & 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 ::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(); }; // on va lire le nombre total de noeud pour chaque maillage for (int num_mail = 1; num_mail <= nb_mail;num_mail++) { int nb_noeud_mail; ar >> nb_noeud_mail; tab_indic_noeud(i_proc)(num_mail).Change_taille(nb_noeud_mail,false); }; // puis les tableaux for (int imail=1;imail<=nb_mail;imail++) { Tableau & tab_indic_noeud_cpu_mail = tab_indic_noeud(i_proc)(imail); // pour simplifier list & list_maillage_noeud = tab_list_maillage_noeud(i_proc)(imail); int size_list; ar >> toto >> size_list; if (size_list == list_maillage_noeud.size()) {// si la liste existante a la bonne taille, on ne fait que lire int inter; list ::iterator il, ilfin= list_maillage_noeud.end(); for (il = list_maillage_noeud.begin(); il != ilfin; il++) {ar >> inter; (*il)=inter; tab_indic_noeud_cpu_mail(inter)=true; // on rempli tab_indic } } else // cas où la taille n'est pas bonne {list_maillage_noeud.clear(); int inter; // élément de travail for (int j=1;j<= size_list;j++) {ar >> inter; list_maillage_noeud.push_back(inter); tab_indic_noeud_cpu_mail(inter)=true; // on rempli tab_indic }; }; // mise à jour du nombre total d'élément total_noeud += list_maillage_noeud.size(); }; }; }; // affichage des infos relatives à la distribution void Distribution_CPU::Affiche() const { // comme on a des listes on sauvegarde explicitement cout << "\n ------ Distribution ---------"; int nb_proc_calcul = tab_list_maillage_element.Taille(); cout << std::string(" nb total de proc de calcul : ") << nb_proc_calcul ; for (int i_proc=1;i_proc<= nb_proc_calcul; i_proc++) {cout << "\n ... cas du proc de calcul : "<< i_proc; int nb_mail = tab_list_maillage_element(i_proc).Taille(); cout << std::string(" nb_mail considere = ")<< nb_mail ; // on affiche é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++) cout << ", nb elem total du maillage " << num_mail << " => " << (int) tab_indic(1)(num_mail).Taille(); for (int imail=1;imail<=nb_mail;imail++) { const list & list_maillage_element = tab_list_maillage_element(i_proc)(imail); cout << " \n cas du maillage "<< imail << std::string(": nb elem pour le proc => ")<< (int) list_maillage_element.size() << " c-a-d les elem : \n "; list ::const_iterator il, ilfin= list_maillage_element.end(); for (il = list_maillage_element.begin(); il != ilfin; il++) { int truc = (*il); cout << truc << " , "; }; }; // idem pour les noeuds on affiche le nombre total de noeud par maillage // pour cela on se sert de tab_indic_noeud pour le premier cpu for (int num_mail = 1; num_mail <= nb_mail;num_mail++) cout << ", nb noeud total du maillage " << num_mail << " => " << (int) tab_indic_noeud(1)(num_mail).Taille(); for (int imail=1;imail<=nb_mail;imail++) { const list & list_maillage_noeud = tab_list_maillage_noeud(i_proc)(imail); cout << " \n cas du maillage "<< imail << std::string(": nb noeud pour le proc => ")<< (int) list_maillage_noeud.size() << " c-a-d les elem : \n "; list ::const_iterator il, ilfin= list_maillage_noeud.end(); for (il = list_maillage_noeud.begin(); il != ilfin; il++) { int truc = (*il); cout << truc << " , "; }; }; }; } // 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); };