Herezh_dev/Algo/AlgorithmeCombiner/AlgoriCombine2.cc
2023-05-03 17:23:49 +02:00

477 lines
24 KiB
C++
Executable file

// 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 "AlgoriCombine.h"
#include "MatBand.h"
#include <cmath>
//------- décomposition en 3 du calcul d'équilibre -------------
// a priori : InitAlgorithme et FinCalcul ne s'appellent qu'une fois,
// par contre : CalEquilibre peut s'appeler plusieurs fois, le résultat sera différent si entre deux calcul
// certaines variables ont-été changés
// initialisation
void AlgoriCombine::InitAlgorithme(ParaGlob * paraGlob,LesMaillages * lesMail,
LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
,VariablesExporter* varExpor
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts
,Resultats* resultats)
{ // INITIALISATION globale
tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(COMBINER); // transfert info
#ifdef UTILISATION_MPI
// calcul de l'équilibrage initiale par le cpu 0
if (distribution_CPU_algo.Tableau_element_CPU_en_cours()->Taille() == 0 )
{distribution_CPU_algo.Calcul_Equilibrage_initiale(lesMail);
distribution_CPU_algo.Passage_Equilibrage_aux_CPU();
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
};
#endif
// on s'occupe des fonctions nD de pilotage
// 1) cas de choix_algo
if ((nom_choix_algo.length()) && (choix_algo == NULL))
// cas où on doit récupérer la fonction nD
{choix_algo = lesFonctionsnD->Trouve(nom_choix_algo);
if (choix_algo->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
{// on vérifie qu'en retour on a un 2 scalaires
choix_algo->Valeur_pour_variables_globales(); // pour simplifier
if (choix_algo->NbComposante() != 1)
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_choix_algo
<< " qui permet de faire le choix de l'algo interne a utiliser "
<< " ne retourne pas 1 scalaire !! a priori ce n'est pas correct ";
Sortie(1);
};
}
else
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_choix_algo
<< " qui permet de faire le choix de l'algo interne a utiliser "
<< " utilise des variables autres que globales, ce n'est pas possible ! ";
Sortie(1);
};
};
// 2) cas de la validation et sauvegarde
if ((nom_gestion_sauvegarde.length()) && (gestion_sauvegarde == NULL))
// cas où on doit récupérer la fonction nD
{gestion_sauvegarde = lesFonctionsnD->Trouve(nom_gestion_sauvegarde);
if (gestion_sauvegarde->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
{// on vérifie qu'en retour on a un scalaire
gestion_sauvegarde->Valeur_pour_variables_globales(); // pour simplifier
if (gestion_sauvegarde->NbComposante() != 1)
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_gestion_sauvegarde
<< " qui permet le pilotage de la sauvegarde "
<< " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
Sortie(1);
};
}
else
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_gestion_sauvegarde
<< " qui permet le pilotage de la sauvegarde "
<< " utilise des variables autres que globales, ce n'est pas possible ! ";
Sortie(1);
};
};
// 3) gestion de la sortie à convergence de chaque algo
if ((nom_gestion_sortie_a_convergence.length()) && (gestion_sortie_a_convergence == NULL))
// cas où on doit récupérer la fonction nD
{gestion_sortie_a_convergence = lesFonctionsnD->Trouve(nom_gestion_sortie_a_convergence);
if (gestion_sortie_a_convergence->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
{// on vérifie qu'en retour on a un scalaire
gestion_sortie_a_convergence->Valeur_pour_variables_globales(); // pour simplifier
if (gestion_sortie_a_convergence->NbComposante() != 1)
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_gestion_sortie_a_convergence
<< " qui permet de piloter la sortie a convergence de chaque algo "
<< " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
Sortie(1);
};
}
else
{cout << "\n *** erreur parametre AlgoriCombine: la fonction nD " << nom_gestion_sortie_a_convergence
<< " qui permet de piloter la sortie a convergence de chaque algo "
<< " utilise des variables autres que globales, ce n'est pas possible ! ";
Sortie(1);
};
};
// on passe en revue tous les algorithmes et on les initialise
int nb_algo = tab_algo.Taille();
for (int i=1;i<=nb_algo;i++)
{ParaGlob::param->Change_ParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
#ifdef UTILISATION_MPI
// passage de l'équilibrage à ParaGlob
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
#endif
charge->ChangeParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
tab_algo(i)->InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts,resultats);
};
// on regarde s'il y a besoin de sauvegarde
// explication: cela ce fait ici, car au niveau de chaque sous-algo, l'ouverture en écriture a été gelée
// du fait que chaque sous algo n'est pas le maitre, ceci pour éviter une sucession d'ouverture écritures
// mais il faut quand même finir par ouvrir en écriture si cela est demandé après toutes les lectures
if (this->Active_sauvegarde())
{ // on récupère la position de restart lue par le dernier algo
// récupération de la position lue par l'algo dans le .BI, changé lors d'un restart par exemple
// il s'agit de la sauvegarde par l'algo de la position qu'il a lue en restart
debut_increment = tab_algo(nb_algo)->Debut_increment();
//&& (ParaGlob::param->TypeCalcul_maitre() == this->typeCalcul) )
// si le fichier base_info n'est pas en service on l'ouvre
entreePrinc->Ouverture_base_info("ecriture");
// dans le cas ou se n'est pas un restart on sauvegarde l'incrément actuel
// c'est-à-dire le premier incrément
// après s'être positionné au début du fichier
if (this->Num_restart() == 0)
{ (entreePrinc->Sort_BI())->seekp(0);
int cas = 1;
paraGlob->Ecriture_base_info(*(entreePrinc->Sort_BI()),cas);
this->Ecriture_base_info
(cas,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
,charge,lesCondLim,lesContacts,resultats,OrdreVisu::INCRE_0);
}
else
{ // sinon on se place dans le fichier à la position du restart
// debut_increment a été définit dans algori (classe mère)
(entreePrinc->Sort_BI())->seekp(debut_increment);
}
};
tempsInitialisation.Arret_du_comptage(); // temps cpu
};
// mise à jour
void AlgoriCombine::MiseAJourAlgo(ParaGlob * paraGlob,LesMaillages * lesMail,
LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
,VariablesExporter* varExpor
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts
,Resultats* resultats)
{ // INITIALISATION globale
tempsMiseAjourAlgo.Mise_en_route_du_comptage(); // temps cpu
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(COMBINER); // transfert info
// on passe en revue tous les algorithmes et on demande leur mise à jour
int nb_algo = tab_algo.Taille();
for (int i=1;i<=nb_algo;i++)
{ParaGlob::param->Change_ParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
#ifdef UTILISATION_MPI
// passage de l'équilibrage à ParaGlob
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
#endif
charge->ChangeParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
tab_algo(i)->MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts,resultats);
};
tempsMiseAjourAlgo.Arret_du_comptage(); // temps cpu
};
// calcul
// si tb_combiner est non null -> un tableau de 3 fonctions
// - la première fct dit si on doit valider ou non le calcul à convergence ok,
// - la deuxième dit si on doit sortir de la boucle ou non à convergence ok
// - la troisième sert d'indicateur: si == un pointeur nulle, cela signifie qu'au début du
// sous - algo on part pour le calcul final des positions à t, sinon on part des position à tdt
// ==> sert en I/O des sous-algo, chaque sous-algo disant au suivant s'il a valider ou pas
// le paramètre est figé pour le premier algo
//
// si la validation est effectuée, la sauvegarde pour le post-traitement est également effectuée
// en fonction de la demande de sauvegard,
// sinon pas de sauvegarde pour le post-traitement à moins que l'on a demandé un mode debug
// qui lui fonctionne indépendamment
void AlgoriCombine::CalEquilibre(ParaGlob * paraGlob,LesMaillages * lesMail
,LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
,VariablesExporter* varExpor
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage
,Charge* charge,LesCondLim* lesCondLim,LesContacts* lescontacts
,Resultats* resultats,Tableau < Fonction_nD* > * )
{
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(COMBINER); // transfert info
int nb_algo = tab_algo.Taille();
Tableau < Fonction_nD* > * tb_combiner = new Tableau < Fonction_nD* >;
tb_combiner->Change_taille(3,NULL); // init par défaut
// --- mise à jour du numéro de chargement des algos
// le numéro de chargement est initialement déterminé par le premier algo
icharge = tab_algo(1)->Num_increment();
for (int i=1;i<=nb_algo;i++)
tab_algo(i)->Affectation_icharge(icharge);
// concernant la troisième fonction qui gère le départ de chaque sous-algo
// à partir de X_t ou pas,
(*tb_combiner)(3)=NULL; // on part de la position X_t
// ensuite ce sont les sous-algos qui modifient le paramètre
// en fonction du fait qu'il valide ou pas le calcul
// on boucle sur les incréments de charge
bool affichage = true; // affichage a priori de la fin des calculs
while ( (!charge->Fin(icharge,affichage))
&& (charge->Fin(icharge,true)!=2) // si on a dépassé le nombre d'incrément permis on s'arrête dans tous les cas
&& (charge->Fin(icharge,false)!=3) // idem si on a dépassé le nombre d'essai d'incrément permis
// 1er appel avec true: pour affichage et second avec false car c'est déjà affiché
&& (!pa.EtatSortieEquilibreGlobal())
)
{
// l'appel des algos s'effectuent soit successivement si aucune info particulière
// soit en fonction du retour de la fonction choix
if (choix_algo == NULL)
{// cas où on passe les algos successivement dans l'ordre de leurs définitions
for (int i=1;i<=nb_algo;i++)
{// avant tout chose, on met à jour
// //------ debug
// cout << "\n ********* debug calequilibre Combiner: "
// << " tab_algo(1)->pa.Deltat()= " << tab_algo(1)->pa.Deltat()
// << "\n tab_algo(2)->pa.Deltat()= " << tab_algo(2)->pa.Deltat()
// << "\n tab_algo(3)->pa.Deltat()= " << tab_algo(3)->pa.Deltat() << flush;
// //--- fin debug
ParaGlob::param->Change_ParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
#ifdef UTILISATION_MPI
// passage de l'équilibrage à ParaGlob
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
#endif
charge->ChangeParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
bool aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
if (aff_incr)
cout << "\n---------------------------------------------------------------------"
<< "\n >>>> algorithme ("<< i <<"): "
<< Nom_TypeCalcul(tab_algo(i)->TypeDeCalcul())
<< " >>>> "
<< "\n---------------------------------------------------------------------"
<< flush;
tab_algo(i)->MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim
,lescontacts,resultats
);
// on met à jour tb_combiner
if (gestion_sortie_a_convergence != NULL)
{(*tb_combiner)(2)=gestion_sortie_a_convergence;}
else // sinon par défaut
{(*tb_combiner)(2)=cst_1; // sortie de boucle à la convergence propre à l'algo
};
if (gestion_sauvegarde != NULL)
{(*tb_combiner)(1)=gestion_sauvegarde;}
else // sinon c'est le dernier algo qui sauvegarde par défaut
{if (i != nb_algo)
{(*tb_combiner)(1)=cst_0;}// pas de validation
else // pour le dernier algo
{(*tb_combiner)(1)=cst_1;}; // validation
};
// //------ debug
// cout << "\n ********* debug calequilibre Combiner: "
// << " tab_algo(1)->pa.Deltat()= " << tab_algo(1)->pa.Deltat()
// << "\n tab_algo(2)->pa.Deltat()= " << tab_algo(2)->pa.Deltat()
// << "\n tab_algo(3)->pa.Deltat()= " << tab_algo(3)->pa.Deltat() << flush;
// //--- fin debug
// puis on calcul l'équilibre
tab_algo(i)->CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim,lescontacts,resultats
,tb_combiner);
// //------ debug
// cout << "\n ********* debug calequilibre Combiner: apres tab_algo(i)->CalEquilibre "
// << " tab_algo(1)->pa.Deltat()= " << tab_algo(1)->pa.Deltat()
// << "\n tab_algo(2)->pa.Deltat()= " << tab_algo(2)->pa.Deltat()
// << "\n tab_algo(3)->pa.Deltat()= " << tab_algo(3)->pa.Deltat() << flush;
// //--- fin debug
// s'il y a une fctnD de sauvegarde on garde le numéro du dernier sous-algo qui a sauvegardé
// car c'est le seul important pour la sauvegarde
if (gestion_sauvegarde != NULL)
{if ((bool) gestion_sauvegarde->Valeur_pour_variables_globales()(1))
{nb_dernier_algo_qui_a_fait_une_sauvegarde = i;};
}
else // sinon c'est le dernier par défaut qui sauvegarde
{nb_dernier_algo_qui_a_fait_une_sauvegarde = nb_algo; };
};
// récup du numéro de chargement
icharge = tab_algo(nb_algo)->Num_increment(); // c'est le dernier qui sauvegarde
}
else // sinon il existe une fonction de choix, on s'en sert
{ bool sans_changement_increment = true;
do
{int i = choix_algo->Valeur_pour_variables_globales()(1);
if ((i >0)&&(i <= nb_algo))
{// on met à jour
ParaGlob::param->Change_ParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
#ifdef UTILISATION_MPI
// passage de l'équilibrage à ParaGlob
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
#endif
charge->ChangeParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
bool aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
if (aff_incr)
cout << "\n---------------------------------------------------------------------"
<< "\n >>>> algorithme ("<< i <<"): "
<< Nom_TypeCalcul(tab_algo(i)->TypeDeCalcul())
<< " >>>> "
<< "\n---------------------------------------------------------------------"
<< flush;
tab_algo(i)->MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim
,lescontacts,resultats
);
// on met à jour tb_combiner
if (gestion_sortie_a_convergence != NULL)
{(*tb_combiner)(2)=gestion_sortie_a_convergence;}
else // sinon par défaut
{(*tb_combiner)(2)=cst_1; // sortie de boucle à la convergence propre à l'algo
};
if (gestion_sauvegarde != NULL)
{(*tb_combiner)(1)=gestion_sauvegarde;}
else // sinon c'est le dernier algo qui sauvegarde par défaut
{if (i != nb_algo)
{(*tb_combiner)(1)=cst_0;}// pas de validation
else // pour le dernier algo
{(*tb_combiner)(1)=cst_1;}; // validation
};
// puis on calcul l'équilibre
tab_algo(i)->CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim,lescontacts,resultats
,tb_combiner);
// récup du numéro de chargement
icharge = tab_algo(i)->Num_increment();
}
else
{cout << "\n erreur** la fonction de choix d'algo indique l'algo num: "<< i
<< " qui n'a pas ete defini !! on ne peut pas continuer "
<< "\n AlgoriCombine::CalEquilibre(..."<<flush;
Sortie(1);
};
// on regarde s'il était demandé une validation
sans_changement_increment = !((bool) gestion_sauvegarde->Valeur_pour_variables_globales()(1));
// si on a sauvegardé on va sortir de la boucle, on sauvegarde le num d'algo
if (!sans_changement_increment)
nb_dernier_algo_qui_a_fait_une_sauvegarde = i;
} while (sans_changement_increment);
};
// --- mise à jour du numéro de chargement pour tous les algos
for (int i=1;i<=nb_algo;i++)
tab_algo(i)->Affectation_icharge(icharge);
}; // fin du while
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
};
// dernière passe
void AlgoriCombine::FinCalcul(ParaGlob * paraGlob,LesMaillages * lesMail,LesReferences* lesRef
,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
,VariablesExporter* varExpor
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
{
// fin des calculs
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(COMBINER); // transfert info
// // on passe en revue tous les algorithmes et on demande la fin des calculs
// non, sinon on a plusieurs dernières sauvegardes !!
// donc on ne sauvegarde la fin que via le dernier sous_algo qui a sauvegardé
// int nb_algo = tab_algo.Taille();
// for (int i=1;i<=nb_algo;i++)
int i=nb_dernier_algo_qui_a_fait_une_sauvegarde;
{ParaGlob::param->Change_ParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
#ifdef UTILISATION_MPI
// passage de l'équilibrage à ParaGlob
paraGlob->Init_tableau (distribution_CPU_algo.Tableau_element_CPU_en_cours());
#endif
charge->ChangeParaAlgoControle(tab_algo(i)->ParaAlgoControle_de_lalgo());
tab_algo(i)->FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts,resultats);
};
};
//---- gestion des commndes interactives --------------
// écoute et prise en compte d'une commande interactive
// ramène true tant qu'il y a des commandes en cours
bool AlgoriCombine::ActionInteractiveAlgo()
{ cout << "\n commande? ";
return false;
};
// sortie du schemaXML: en fonction de enu
void AlgoriCombine::SchemaXML_Algori(ofstream& sort,const Enum_IO_XML enu) const
{
switch (enu)
{ case XML_TYPE_GLOBAUX :
{
break;
}
case XML_IO_POINT_INFO :
{
break;
}
case XML_IO_POINT_BI :
{
break;
}
case XML_IO_ELEMENT_FINI :
{
break;
}
case XML_ACTION_INTERACTIVE :
{sort << "\n <!-- ********** algorithme implicite non dynamique ******************** -->"
<< "\n<xs:complexType name=\"INIT\" >"
<< "\n <xs:annotation>"
<< "\n <xs:documentation> initialisation de l'algo "
<< "\n </xs:documentation>"
<< "\n </xs:annotation>"
<< "\n</xs:complexType>";
sort << "\n<xs:complexType name=\"EXECUTION\" >"
<< "\n <xs:annotation>"
<< "\n <xs:documentation> execution de l'ensemble de l'algo, sans l'initialisation et la derniere passe "
<< "\n </xs:documentation>"
<< "\n </xs:annotation>"
<< "\n</xs:complexType>";
sort << "\n<xs:complexType name=\"FIN_ALGO_EXPLI\" >"
<< "\n <xs:annotation>"
<< "\n <xs:documentation> fin de l'algo "
<< "\n </xs:documentation>"
<< "\n </xs:annotation>"
<< "\n</xs:complexType>";
break;
}
case XML_STRUCTURE_DONNEE :
{
break;
}
};
};