Gérard Rio
ea11c75ff8
- fct nD: amélioration message d'erreur (arguments), et en fct du niveau géré par une fct nD - première validation du fct. en // en implicite statique et en RD, nombreuses modifications et amélioration ! Signed-off-by: Gérard Rio <gerardrio56@free.fr>
4208 lines
232 KiB
C++
4208 lines
232 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 "Algori_relax_dyna.h"
|
|
#include "MatDiag.h"
|
|
using namespace std; //introduces namespace std
|
|
#include <cmath>
|
|
#include "TypeQuelconqueParticulier.h"
|
|
|
|
// ---------- pour le calcul de la masse pour la méthode de relaxation dynamique
|
|
// masseRelax_1 : pour le premier type de calcul de masse : type_calcul_mass= 1
|
|
Ddl_enum_etendu AlgoriRelaxDyna::masseRelax_1; // init à rien, def à l'initialisation
|
|
// masseRelax_2 : pour le deuxième type de calcul de masse: type_calcul_mass= 2
|
|
TypeQuelconque AlgoriRelaxDyna::masseRelax_2;
|
|
|
|
// CONSTRUCTEURS :
|
|
AlgoriRelaxDyna::AlgoriRelaxDyna () : // par defaut
|
|
Algori()
|
|
,cL_a_chaque_iteration(0)
|
|
,delta_t(),typeCalRelaxation(1)
|
|
,lambda(0.605),alph(1.),beta(1.),gamma(1.),theta(1.),casMass_relax(3)
|
|
,lambda_initial(0.605)
|
|
// pilotage automatique éventuel
|
|
,lambda_min(0.605),lambda_max(50.),delta_lambda(0.1)
|
|
,pilotage_auto_lambda(false),list_iter_relax()
|
|
,niveauLambda_grandeurGlobale(NULL),niveauLambda_ddlEtendu(NULL),niveauLambda_temps(NULL)
|
|
// calcul masse
|
|
,option_recalcul_mass(1,0)
|
|
,nom_fct_nD_option_recalcul_mass(1,""),fct_nD_option_recalcul_mass(1)
|
|
,ncycle_calcul(100),type_calcul_mass(2)
|
|
,fac_epsilon(1),type_activation_contact(1),choix_mini_masse_nul(0)
|
|
,proportion_cinetique(0.1),visqueux_activer(false)
|
|
,et_recalcul_masse_a_la_transition(1)
|
|
,niveauF_grandeurGlobale(NULL),niveauF_ddlEtendu(NULL),niveauF_temps(NULL)
|
|
,Ass1_(NULL),Ass2_(NULL),Ass3_(NULL)
|
|
,cas_combi_ddl(),icas(),compteur(0),prepa_avec_remont(false)
|
|
,brestart(false),type_incre(OrdreVisu::PREMIER_INCRE)
|
|
,compteur_demarrage(-1)
|
|
,vglobin(),vglobex(),vglobaal(),vcontact()
|
|
,save_X_t()
|
|
,X_Bl(),V_Bl(),G_Bl(),forces_vis_num(0)
|
|
,li_gene_asso(),t_assemb(),tenuXVG(),mat_masse(NULL),mat_masse_sauve(NULL),mat_C_pt(NULL)
|
|
,v_mass(),v_mass1(),matglob(NULL)
|
|
{ //vglobaal = &vglobin;
|
|
fct_nD_option_recalcul_mass(1)=NULL; // init
|
|
// message d'erreur
|
|
cout << "\n constructeur par defaut de AlgoriRelaxDyna, ne doit pas etre utilise !!";
|
|
Sortie(1);
|
|
};
|
|
|
|
// constructeur en fonction du type de calcul et du sous type
|
|
// il y a ici lecture des parametres attaches au type
|
|
AlgoriRelaxDyna::AlgoriRelaxDyna (const bool avec_typeDeCal
|
|
,const list <EnumSousTypeCalcul>& soustype
|
|
,const list <bool>& avec_soustypeDeCal
|
|
,UtilLecture& entreePrinc) :
|
|
Algori(RELAX_DYNA,avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc)
|
|
,cL_a_chaque_iteration(0)
|
|
,delta_t(0.),typeCalRelaxation(1)
|
|
,lambda(0.605),alph(1.),beta(1.),gamma(1.),theta(1.),casMass_relax(3)
|
|
,lambda_initial(0.605)
|
|
// pilotage automatique éventuel
|
|
,lambda_min(0.605),lambda_max(50.),delta_lambda(0.1)
|
|
,pilotage_auto_lambda(false),list_iter_relax()
|
|
,niveauLambda_grandeurGlobale(NULL),niveauLambda_ddlEtendu(NULL),niveauLambda_temps(NULL)
|
|
// calcul masse
|
|
,option_recalcul_mass(1,0)
|
|
,nom_fct_nD_option_recalcul_mass(1,""),fct_nD_option_recalcul_mass(1)
|
|
,ncycle_calcul(100),type_calcul_mass(2)
|
|
,fac_epsilon(1),type_activation_contact(1),choix_mini_masse_nul(0)
|
|
,proportion_cinetique(0.1),visqueux_activer(false)
|
|
,et_recalcul_masse_a_la_transition(1)
|
|
,niveauF_grandeurGlobale(NULL),niveauF_ddlEtendu(NULL),niveauF_temps(NULL)
|
|
,Ass1_(NULL),Ass2_(NULL),Ass3_(NULL)
|
|
,cas_combi_ddl(),icas(),compteur(0),prepa_avec_remont(false)
|
|
,brestart(false),type_incre(OrdreVisu::PREMIER_INCRE)
|
|
,compteur_demarrage(-1)
|
|
,vglobin(),vglobex(),vglobaal(),vcontact()
|
|
,save_X_t()
|
|
,X_Bl(),V_Bl(),G_Bl(),forces_vis_num(0)
|
|
,li_gene_asso(),t_assemb(),tenuXVG(),mat_masse(NULL),mat_masse_sauve(NULL),mat_C_pt(NULL)
|
|
,v_mass(),v_mass1(),matglob(NULL)
|
|
{ //vglobaal = &vglobin;
|
|
fct_nD_option_recalcul_mass(1)=NULL; // init
|
|
// intro para globaux
|
|
int toto=1; // on est en cinétique par défaut
|
|
Grandeur_scalaire_entier grand_courant(toto);
|
|
TypeQuelconque typQ1(GENERIQUE_UNE_GRANDEUR_GLOBALE,NU_DDL,grand_courant);
|
|
ParaGlob::param->Ajout_grandeur_consultable(&typQ1,AMOR_CINET_VISQUEUX);
|
|
|
|
// lecture des paramètres attachés au type de calcul
|
|
switch (entreePrinc.Lec_ent_info())
|
|
{ case 0 :
|
|
{lecture_Parametres(entreePrinc); break;}
|
|
case -11 : // cas de la création d'un fichier de commande
|
|
{ Info_commande_parametres(entreePrinc); break;}
|
|
case -12 : // cas de la création d'un schéma XML, on ne fait rien à ce niveau
|
|
{ break;}
|
|
default:
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
// constructeur de copie
|
|
AlgoriRelaxDyna::AlgoriRelaxDyna (const AlgoriRelaxDyna& algo):
|
|
Algori(algo)
|
|
,cL_a_chaque_iteration(algo.cL_a_chaque_iteration)
|
|
,Ass1_(NULL),Ass2_(NULL),Ass3_(NULL)
|
|
,delta_t(0.),typeCalRelaxation(algo.typeCalRelaxation)
|
|
,lambda(algo.lambda),alph(algo.alph),beta(algo.beta),gamma(algo.gamma),theta(algo.theta)
|
|
,lambda_initial(algo.lambda_initial)
|
|
// pilotage automatique éventuel
|
|
,lambda_min(algo.lambda_min),lambda_max(algo.lambda_max),delta_lambda(algo.delta_lambda)
|
|
,pilotage_auto_lambda(algo.pilotage_auto_lambda),list_iter_relax(algo.list_iter_relax)
|
|
,niveauLambda_grandeurGlobale(NULL),niveauLambda_ddlEtendu(NULL),niveauLambda_temps(NULL)
|
|
,casMass_relax(algo.casMass_relax)
|
|
,option_recalcul_mass(algo.option_recalcul_mass)
|
|
,nom_fct_nD_option_recalcul_mass(algo.nom_fct_nD_option_recalcul_mass)
|
|
,fct_nD_option_recalcul_mass(algo.fct_nD_option_recalcul_mass)
|
|
,ncycle_calcul(algo.ncycle_calcul),type_calcul_mass(algo.type_calcul_mass)
|
|
,fac_epsilon(algo.fac_epsilon),type_activation_contact(algo.type_activation_contact)
|
|
,proportion_cinetique(algo.proportion_cinetique),visqueux_activer(algo.visqueux_activer)
|
|
,et_recalcul_masse_a_la_transition(algo.et_recalcul_masse_a_la_transition)
|
|
,niveauF_grandeurGlobale(NULL),niveauF_ddlEtendu(NULL),niveauF_temps(NULL)
|
|
,choix_mini_masse_nul(algo.choix_mini_masse_nul)
|
|
,cas_combi_ddl(),icas()
|
|
,compteur(0),prepa_avec_remont(false)
|
|
,brestart(false),type_incre(OrdreVisu::PREMIER_INCRE)
|
|
,compteur_demarrage(algo.compteur_demarrage)
|
|
,vglobin(),vglobex(),vglobaal(),vcontact()
|
|
,save_X_t()
|
|
,X_Bl(),V_Bl(),G_Bl(),forces_vis_num(0)
|
|
,li_gene_asso(),t_assemb(),tenuXVG(),mat_masse(NULL),mat_masse_sauve(NULL),mat_C_pt(NULL)
|
|
,v_mass(algo.v_mass),v_mass1(algo.v_mass1),matglob(NULL)
|
|
{//vglobaal = &vglobin;
|
|
|
|
// -- cas d'un lambda piloté
|
|
if (algo.niveauLambda_grandeurGlobale != NULL)
|
|
niveauLambda_grandeurGlobale = new Ponderation_GGlobal(*algo.niveauLambda_grandeurGlobale);
|
|
if (algo.niveauLambda_ddlEtendu != NULL)
|
|
niveauLambda_ddlEtendu = new Ponderation(*algo.niveauLambda_ddlEtendu);
|
|
if (algo.niveauLambda_temps != NULL)
|
|
niveauLambda_temps = new Ponderation_temps(*algo.niveauLambda_temps);
|
|
|
|
// -- cas de l'algo mixte : pilotage du basculement entre cinétique et visqueux
|
|
if (algo.niveauF_grandeurGlobale != NULL)
|
|
niveauF_grandeurGlobale = new Ponderation_GGlobal(*algo.niveauF_grandeurGlobale);
|
|
if (algo.niveauF_ddlEtendu != NULL)
|
|
niveauF_ddlEtendu = new Ponderation(*algo.niveauF_ddlEtendu);
|
|
if (algo.niveauF_temps != NULL)
|
|
niveauF_temps = new Ponderation_temps(*algo.niveauF_temps);
|
|
};
|
|
|
|
// destructeur
|
|
AlgoriRelaxDyna::~AlgoriRelaxDyna ()
|
|
{ if (mat_masse != NULL) delete mat_masse;
|
|
if (mat_masse_sauve != NULL) delete mat_masse_sauve;
|
|
if (mat_C_pt != NULL) delete mat_C_pt;
|
|
if (Ass1_ != NULL) delete Ass1_;
|
|
if (Ass2_ != NULL) delete Ass2_;
|
|
if (Ass3_ != NULL) delete Ass3_;
|
|
if (matglob != NULL) delete matglob;
|
|
|
|
// -- cas d'un lambda piloté
|
|
if (niveauLambda_grandeurGlobale != NULL)
|
|
delete niveauLambda_grandeurGlobale;
|
|
if (niveauLambda_ddlEtendu != NULL)
|
|
delete niveauLambda_ddlEtendu;
|
|
if (niveauLambda_temps != NULL)
|
|
delete niveauLambda_temps;
|
|
|
|
// cas des pondérations
|
|
if (niveauF_grandeurGlobale != NULL)
|
|
delete niveauF_grandeurGlobale;
|
|
if (niveauF_ddlEtendu != NULL)
|
|
delete niveauF_ddlEtendu;
|
|
if (niveauF_temps != NULL)
|
|
delete niveauF_temps;
|
|
};
|
|
|
|
// execution de l'algorithme dans le cas dynamique explicite, sans contact
|
|
void AlgoriRelaxDyna::Execution(ParaGlob * paraGlob,LesMaillages * lesMail
|
|
,LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor,LesLoisDeComp* lesLoisDeComp, DiversStockage* divStock
|
|
,Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
|
|
{ Tableau < Fonction_nD* > * tb_combiner = NULL; // ici ne sert pas
|
|
// on définit le type de calcul a effectuer :
|
|
if ( soustypeDeCalcul->size()==0 )
|
|
// cas où il n'y a pas de sous type, on fait le calcul d'équilibre classique
|
|
// signifie que le type principal est forcément valide
|
|
{ // initialisation du calcul : deux cas, soit avec une lecture initiale du .info, soit une lecture secondaire
|
|
if (paraGlob->EtatDeLaLecturePointInfo() == 0)
|
|
{InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );}
|
|
else {MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
};
|
|
// on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
|
|
// bref que l'on n'a pas fini, sinon on passe
|
|
if (! (charge->Fin(icharge,true) ) )
|
|
{ // calcul de l'équilibre
|
|
CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats
|
|
,tb_combiner);
|
|
// fin du calcul, pour l'instant on ne considère pas les autres sous-types
|
|
FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
};
|
|
}
|
|
else
|
|
{if ( avec_typeDeCalcul )
|
|
// cas où le type principal est valide et qu'il y a des sous_types
|
|
{ // on regarde si le sous-type "commandeInteractive" existe, si oui on le met en place
|
|
// détermine si le sous type de calcul existe et s'il est actif
|
|
if (paraGlob->SousTypeCalcul(commandeInteractive))
|
|
{// -- cas avec commandes interactives
|
|
// initialisation du calcul : deux cas, soit avec une lecture initiale du .info, soit une lecture secondaire
|
|
if (paraGlob->EtatDeLaLecturePointInfo() == 0)
|
|
{InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
}
|
|
else {MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
};
|
|
// calcul de l'équilibre tant qu'il y a des commandes
|
|
while (ActionInteractiveAlgo())
|
|
{ // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
|
|
// bref que l'on n'a pas fini, sinon on passe
|
|
if (! (charge->Fin(icharge,true) ) )
|
|
CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats
|
|
,tb_combiner);
|
|
};
|
|
// fin du calcul, pour l'instant on ne considère pas les autres sous-types
|
|
FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
}
|
|
else // cas sans commandes interactives
|
|
{// on fait le calcul d'équilibre
|
|
// initialisation du calcul : deux cas, soit avec une lecture initiale du .info, soit une lecture secondaire
|
|
if (paraGlob->EtatDeLaLecturePointInfo() == 0)
|
|
{InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
}
|
|
else {MiseAJourAlgo(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
};
|
|
// on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi
|
|
// bref que l'on n'a pas fini, sinon on passe
|
|
if (! (charge->Fin(icharge,true) ) )
|
|
{ // calcul de l'équilibre
|
|
CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats
|
|
,tb_combiner);
|
|
|
|
// fin du calcul, pour l'instant on ne considère pas les autres sous-types
|
|
FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,divStock,charge,lesCondLim,lesContacts,resultats );
|
|
};
|
|
// ensuite on teste en fonction des calculs complémentaires
|
|
// dépendant des sous_types. Pour l'instant ici uniquement la remontée
|
|
list <EnumSousTypeCalcul>::const_iterator ili,ili_fin = soustypeDeCalcul->end();
|
|
list <bool>::const_iterator ila;
|
|
for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin();
|
|
ili!=ili_fin;ili++,ila++)
|
|
if (*ila) // cas où le sous type est valide
|
|
{if (Remonte_in(*ili)) // on test la présence du calcul de remonté
|
|
{ // certaines initialisations sont nécessaires car c'est le premier calcul
|
|
Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
|
|
Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
|
|
Algori::RemontSigma(lesMail);
|
|
Algori::RemontErreur(lesMail);
|
|
}
|
|
else if ( (*ili) == sauveMaillagesEnCours )
|
|
{ cout << "\n================================================================="
|
|
<< "\n| ecriture des maillages en cours en .her et .lis |"
|
|
<< "\n================================================================="
|
|
<< endl;
|
|
|
|
// ----- sort les informations sur fichiers
|
|
// Affichage des donnees des maillages dans des fichiers dont le nom est construit
|
|
// à partir du nom de chaque maillage au format ".her" et ".lis"
|
|
lesMail->Affiche_maillage_dans_her_lis(TEMPS_tdt,*lesRef);
|
|
};
|
|
};
|
|
};// fin du cas sans commandes interactives
|
|
}
|
|
else
|
|
// cas ou le type principal n'est pas valide
|
|
// on ne fait que le calcul complémentaire
|
|
{ list <EnumSousTypeCalcul>::const_iterator ili,ili_fin = soustypeDeCalcul->end();
|
|
list <bool>::const_iterator ila;
|
|
for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin();
|
|
ili!=ili_fin;ili++,ila++)
|
|
if (*ila) // cas où le sous type est valide
|
|
{if (Remonte_in(*ili)) // on test la présence du calcul de remonté
|
|
{ // certaines initialisations sont nécessaires car c'est le premier calcul
|
|
Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
|
|
Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats);
|
|
Algori::RemontSigma(lesMail);
|
|
Algori::RemontErreur(lesMail);
|
|
}
|
|
else if ( (*ili) == sauveMaillagesEnCours )
|
|
{ cout << "\n================================================================="
|
|
<< "\n| ecriture des maillages en cours en .her et .lis |"
|
|
<< "\n================================================================="
|
|
<< endl;
|
|
|
|
// ----- sort les informations sur fichiers
|
|
// Affichage des donnees des maillages dans des fichiers dont le nom est construit
|
|
// à partir du nom de chaque maillage au format ".her" et ".lis"
|
|
lesMail->Affiche_maillage_dans_her_lis(TEMPS_0,*lesRef);
|
|
};
|
|
};
|
|
}
|
|
}
|
|
// si on a forcé la sortie des itérations et incréments, il faut réinitialiser l'indicateur
|
|
if (!(pa.EtatSortieEquilibreGlobal()))
|
|
pa.ChangeSortieEquilibreGlobal(false);
|
|
};
|
|
|
|
// écriture des paramètres dans la base info
|
|
// = 1 : on écrit tout
|
|
// = 2 : on écrot uniquement les données variables (supposées comme telles)
|
|
void AlgoriRelaxDyna::Ecrit_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas)
|
|
{ // récup du flot
|
|
ofstream& sort = *entreePrinc.Sort_BI();
|
|
// sort << "\n parametres_algo_specifiques_ "<< Nom_TypeCalcul(this->TypeDeCalcul());
|
|
switch (cas)
|
|
{case 1 : // ------- on sauvegarde tout -------------------------
|
|
{ // ecriture des paramètres de contrôle
|
|
sort << "\n typeCalRelaxation= " << typeCalRelaxation;
|
|
// en fait on sort tous les paramètres de contrôle qu'ils servent ou non, ce qui permettra éventuellement de faire
|
|
// des changements de type de relaxation en cours de calcul
|
|
sort << "\n lambda= " << lambda << " type_calcul_mass= " << type_calcul_mass;
|
|
// option de recalcul de masse
|
|
{int nb_option = option_recalcul_mass.Taille(); // nombre d'options
|
|
sort << " nombre_option_option_recalcul_mass : " << nb_option;
|
|
for (int i=1;i<= nb_option;i++)
|
|
{ if (nom_fct_nD_option_recalcul_mass(i).length())
|
|
{sort << "\n nom_fct_nD_option_recalcul_mass("<<i<<")= "<< nom_fct_nD_option_recalcul_mass(i);}
|
|
else
|
|
{sort << "\n valeur_fixe_option_recalcul_mass("<<i<<")= "<< option_recalcul_mass(i); }
|
|
};
|
|
};
|
|
// suite des paramètres
|
|
sort << " alpha= " << alph << " beta= " << beta << " gamma= " << gamma << " theta= " << theta
|
|
<< " casMass_relax= " << casMass_relax
|
|
<< " fac_epsilon= " << fac_epsilon << " type_activation_contact= " << type_activation_contact
|
|
<< " choix_mini_masse_nul= "<< choix_mini_masse_nul
|
|
<< " proportion_cinetique= " << proportion_cinetique
|
|
<< " et_recalcul_masse_a_la_transition= " << et_recalcul_masse_a_la_transition;
|
|
|
|
// écriture d'un pilotage de lambda éventuelle
|
|
sort << "\n lambda_min= " << lambda_min << " lambda_max= " << lambda_max
|
|
<< " delta_lambda " << delta_lambda
|
|
<< " pilotage_auto_lambda= " << pilotage_auto_lambda ;
|
|
// pondération éventuelle
|
|
bool sans_courbe = true;
|
|
if (niveauLambda_temps == NULL)
|
|
{sort << "\n ponderationTemps_lambda 0 ";}
|
|
else
|
|
{sort << "\n ponderationTemps_lambda 1 " ;
|
|
niveauLambda_temps->Ecriture_base_info(sort,cas,sans_courbe);
|
|
};
|
|
if (niveauLambda_grandeurGlobale == NULL)
|
|
{sort << "\n ponderationGrandeurGlobale_lambda 0 ";}
|
|
else
|
|
{sort << "\n ponderationGrandeurGlobale_lambda 1 " ;
|
|
niveauLambda_grandeurGlobale->Ecriture_base_info(sort,cas,sans_courbe);
|
|
};
|
|
|
|
// écriture des pondérations éventuelles
|
|
if (niveauF_temps == NULL)
|
|
{sort << "\n ponderationTemps_prop_cinetique 0 ";}
|
|
else
|
|
{sort << "\n ponderation_prop_cinetique 1 " ;
|
|
niveauF_temps->Ecriture_base_info(sort,cas,sans_courbe);
|
|
};
|
|
if (niveauF_grandeurGlobale == NULL)
|
|
{sort << "\n ponderationGrandeurGlobale_prop_cinetique 0 ";}
|
|
else
|
|
{sort << "\n ponderationGrandeurGlobale_prop_cinetique 1 " ;
|
|
niveauF_grandeurGlobale->Ecriture_base_info(sort,cas,sans_courbe);
|
|
};
|
|
|
|
sort << " ncycle_calcul= " << ncycle_calcul << " "
|
|
<< "\n cL_a_chaque_iteration "<< cL_a_chaque_iteration<< " ";
|
|
sort << flush;
|
|
break;
|
|
}
|
|
case 2 : // ----------- on sauvegarde en minimaliste --------------------
|
|
{ sort << "\n lambda= "<<lambda << " ";
|
|
break;
|
|
}
|
|
default :
|
|
{ cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n";
|
|
cout << "AlgoriRelaxDyna::Ecrit_Base_info_Parametre(UtilLecture& ,const int& )"
|
|
<< " cas= " << cas << endl;
|
|
Sortie(1);
|
|
}
|
|
};
|
|
// sort << "\n fin_parametres_algo_specifiques_ ";
|
|
};
|
|
|
|
// lecture des paramètres dans la base info
|
|
// = 1 : on récupère tout
|
|
// = 2 : on récupère uniquement les données variables (supposées comme telles)
|
|
// choix = true : fonctionememt normal
|
|
// choix = false : la méthode ne doit pas lire mais initialiser les données à leurs valeurs par défaut
|
|
// car la lecture est impossible
|
|
void AlgoriRelaxDyna::Lecture_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas,bool choix)
|
|
{// récup du flot
|
|
ifstream& ent = *entreePrinc.Ent_BI();
|
|
string toto;
|
|
if (choix)
|
|
{switch (cas)
|
|
{ case 1 : // ------- on récupère tout -------------------------
|
|
{ // lecture du type de calcul de la relaxation
|
|
ent >> toto >> typeCalRelaxation;
|
|
switch (typeCalRelaxation)
|
|
{ case 1: visqueux_activer = false; break;
|
|
case 2: visqueux_activer = true; break;
|
|
case 4: visqueux_activer = false; break; // au début en cinétique
|
|
default:
|
|
cout <<"\n typeCalRelaxation = " << typeCalRelaxation
|
|
<< " cas non pris en compte dans AlgoriRelaxDyna::Lecture_Base_info_Parametre( ";
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
|
|
// en fait on lit tous les paramètres de contrôle qu'ils servent ou non, ce qui permettra éventuellement de faire
|
|
// des changements de type de relaxation en cours de calcul
|
|
ent >> toto >> lambda >> toto >> type_calcul_mass;
|
|
// option de recalcul de masse
|
|
{int nb_option = 0;
|
|
ent >> toto >> nb_option;
|
|
option_recalcul_mass.Change_taille(nb_option);
|
|
nom_fct_nD_option_recalcul_mass.Change_taille(nb_option);
|
|
fct_nD_option_recalcul_mass.Change_taille(nb_option);
|
|
for (int i=1;i<= nb_option;i++)
|
|
{ ent >> toto; // on lit l'identificateur
|
|
string iden("nom_fct_nD_option_recalcul_mass");
|
|
std::size_t found = toto.find(iden);
|
|
if (found!=std::string::npos) // si oui on a trouvé la chaine
|
|
{ ent >> nom_fct_nD_option_recalcul_mass(i);}
|
|
else // sinon cela signifie qu'il s'agit d'une valeur fixe
|
|
{ ent >> option_recalcul_mass(i); };
|
|
// dans tous les cas on met à NULL pour l'instant le pointeur de fonction
|
|
fct_nD_option_recalcul_mass(i) = NULL;
|
|
};
|
|
};
|
|
// suite des paramètres
|
|
ent >> toto >> alph >> toto >> beta >> toto >> gamma >> toto >> theta
|
|
>> toto >> casMass_relax
|
|
>> toto >> fac_epsilon >> toto >> type_activation_contact
|
|
>> toto >> choix_mini_masse_nul >> toto >> proportion_cinetique
|
|
>> toto >> et_recalcul_masse_a_la_transition;
|
|
|
|
// cas d'un pilotage de lambda éventuelle
|
|
ent >> toto >> lambda_min >> toto >> lambda_max
|
|
>> toto >> delta_lambda
|
|
>> toto >> pilotage_auto_lambda ;
|
|
// avec pondération éventuelle
|
|
// -> le temps
|
|
bool ponder_lambda_temps = false;
|
|
ent >> toto >> ponder_lambda_temps;
|
|
if (ponder_lambda_temps)
|
|
{ if (niveauLambda_temps == NULL)
|
|
{niveauLambda_temps = new Ponderation_temps();
|
|
niveauLambda_temps->Lecture_base_info(ent,cas);
|
|
}
|
|
else {niveauLambda_temps->Lecture_base_info(ent,cas);};
|
|
};
|
|
// -> les grandeurs globales
|
|
bool ponder_lambda_glob = false;
|
|
ent >> toto >> ponder_lambda_glob;
|
|
if (ponder_lambda_glob)
|
|
{ if (niveauLambda_grandeurGlobale == NULL)
|
|
{niveauLambda_grandeurGlobale = new Ponderation_GGlobal();
|
|
niveauLambda_grandeurGlobale->Lecture_base_info(ent,cas);
|
|
}
|
|
else {niveauLambda_grandeurGlobale->Lecture_base_info(ent,cas);};
|
|
};
|
|
|
|
// cas des pondérations éventuelles
|
|
// -> le temps
|
|
bool ponder_temps = false;
|
|
ent >> toto >> ponder_temps;
|
|
if (ponder_temps)
|
|
{ if (niveauF_temps == NULL)
|
|
{niveauF_temps = new Ponderation_temps();
|
|
niveauF_temps->Lecture_base_info(ent,cas);
|
|
}
|
|
else {niveauF_temps->Lecture_base_info(ent,cas);};
|
|
};
|
|
// -> les grandeurs globales
|
|
bool ponder_glob = false;
|
|
ent >> toto >> ponder_glob;
|
|
if (ponder_glob)
|
|
{ if (niveauF_grandeurGlobale == NULL)
|
|
{niveauF_grandeurGlobale = new Ponderation_GGlobal();
|
|
niveauF_grandeurGlobale->Lecture_base_info(ent,cas);
|
|
}
|
|
else {niveauF_grandeurGlobale->Lecture_base_info(ent,cas);};
|
|
};
|
|
|
|
ent >> toto >> ncycle_calcul ;
|
|
// lecture de cL_a_chaque_iteration
|
|
ent >> toto ;
|
|
if (toto != "cL_a_chaque_iteration")
|
|
{ cout << "\n erreur en lecture du parametre cL_a_chaque_iteration"
|
|
<< "\n on attendait le mot : cL_a_chaque_iteration , au lieu de " << toto
|
|
<< "\n AlgoriRelaxDyna::Lecture_Base_info_Parametre( ... ";
|
|
Sortie(1);
|
|
}
|
|
ent >> cL_a_chaque_iteration ;
|
|
break;
|
|
}
|
|
case 2 : // ----------- on récupère en minimaliste --------------------
|
|
{ double titi;
|
|
ent >> toto >> titi; // on ne relit pas le lambda ceci pour pouvoir le modifier
|
|
// au moment d'un restart par exemple
|
|
break;
|
|
}
|
|
default :
|
|
{ cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n";
|
|
cout << "AlgoriRelaxDyna::Lecture_Base_info_Parametre(UtilLecture& ,const int& )"
|
|
<< " cas= " << cas << endl;
|
|
Sortie(1);
|
|
}
|
|
};
|
|
}
|
|
//---- dans le cas où un restart en relaxation n'est pas prévu, car par exemple cela suit l'utilisation
|
|
// d'un autre algo, on ne fait rien, et on se contente de garder les paramètres qui viennent d'être lues
|
|
// ---> décision du 21 mars 2019 .... à voir si cela ne crée pas de pb
|
|
|
|
|
|
// else
|
|
// { // cas où la lecture est impossible
|
|
// typeCalRelaxation=1; lambda = 0.605; lambda_initial=lambda;
|
|
// type_calcul_mass= 2;
|
|
// option_recalcul_mass.Change_taille(1,0);
|
|
// nom_fct_nD_option_recalcul_mass.Change_taille(1,"");
|
|
// fct_nD_option_recalcul_mass.Change_taille(1,NULL);
|
|
// alph=1; beta = 1.;gamma=1.;theta=1.; casMass_relax=3;
|
|
// fac_epsilon= 1.; type_activation_contact=1;choix_mini_masse_nul=0;proportion_cinetique = 0.1;
|
|
// et_recalcul_masse_a_la_transition = 1;
|
|
// };
|
|
};
|
|
|
|
// gestion et vérification du pas de temps et modif en conséquence si nécessaire
|
|
// cas = 0: premier passage à blanc, delta t = 0
|
|
// cas = 1: initialisation du pas de temps et vérif / au pas de temps critique
|
|
// ceci pour le temps t=0
|
|
// cas = 2: initialisation du pas de temps et vérif / au pas de temps critique
|
|
// ceci pour le temps t
|
|
// en entrée: modif_pas_de_temps: indique qu'il y a eu par ailleurs (via Charge->Avance())
|
|
// une modification du pas de temps depuis le dernier appel
|
|
// retourne vrai s'il y a une modification du pas de temps, faux sinon
|
|
bool AlgoriRelaxDyna::Gestion_pas_de_temps(bool modif_pas_de_temps,LesMaillages * lesMail,int cas)
|
|
{ bool modif_deltat = modif_pas_de_temps; // booleen pour la prise en compte éventuelle de la modif du temps éventuelle
|
|
if (modif_pas_de_temps) // dans le cas où il y a eu une modification externe du pas de temps on modifie la variable interne
|
|
delta_t = pa.Deltat(); // sinon elle ne sera pas mise à jour dans l'algo
|
|
// double ancien_pas = delta_t;
|
|
switch (cas)
|
|
{ case 0 :
|
|
{ // cas d'un passage à blanc, rien ne bouge et delta t est mis à 0
|
|
delta_t = 0.;
|
|
break;
|
|
}
|
|
case 1:
|
|
{ // dans le cas où le pas de temps ou le pas de temps maxi dépendent d'un pas critique,
|
|
// on calcul le pas de temps critique et on met à jour les pas de temps
|
|
if (pa.DeltatOuDeltatmaxDependantTempsCritique())
|
|
// on calcul le pas de temps minimal pour cela on utilise
|
|
// les caractéristiques dynamiques d'une biellette de longueur
|
|
// valant le minimum d'un coté d'arrête
|
|
{ // ---- on calcul le pas de temps minimal
|
|
double l_sur_c = lesMail->Longueur_arrete_mini_sur_c(TEMPS_0);
|
|
double delta_t_essai = l_sur_c ;
|
|
// mise à jour éventuel du pas de temps et du pas de temps maxi et mini s'ils sont définit à partir du temps critique
|
|
modif_deltat = pa.Modif_Deltat_DeltatMaxi(delta_t_essai,l_sur_c); // mais pas de test vis-a-vis des bornes
|
|
delta_t = pa.Deltat(); // mise à jour éventuelle du pas de temps
|
|
};
|
|
break;
|
|
}
|
|
case 2:
|
|
{ // dans le cas où le pas de temps ou le pas de temps maxi dépendent d'un pas critique,
|
|
// on calcul le pas de temps critique et on met à jour les pas de temps
|
|
if (pa.DeltatOuDeltatmaxDependantTempsCritique())
|
|
// on calcul le pas de temps minimal pour cela on utilise
|
|
// les caractéristiques dynamiques d'une biellette de longueur
|
|
// valant le minimum d'un coté d'arrête
|
|
{ // ---- on calcul le pas de temps minimal
|
|
double l_sur_c = lesMail->Longueur_arrete_mini_sur_c(TEMPS_t);
|
|
double delta_t_essai = l_sur_c ;
|
|
// mise à jour éventuel du pas de temps et du pas de temps maxi et mini s'ils sont définit à partir du temps critique
|
|
modif_deltat = pa.Modif_Deltat_DeltatMaxi(delta_t_essai,l_sur_c); // mais pas de test vis-a-vis des bornes
|
|
delta_t = pa.Deltat(); // mise à jour éventuelle du pas de temps
|
|
// // on vérifie que le pas de temps est correcte: on propose le deltat actuel qui sera modifié s'il n'est pas bon
|
|
// double deltat_actuel = pa.Deltat();
|
|
// pa.Modif_Detat_dans_borne(deltat_actuel);
|
|
};
|
|
break;
|
|
} //-- fin du cas == 2
|
|
default :
|
|
{cout << "\nErreur : valeur incorrecte du cas = " << cas << "\n";
|
|
cout << "AlgoriRelaxDyna::Gestion_pas_de_temps(... \n";
|
|
Sortie(1);
|
|
}
|
|
}; // fin du switch
|
|
// if (modif_deltat)
|
|
// cout << "\n --->>>> modif increment de temps de " << ancien_pas << " a " << delta_t;
|
|
// retour
|
|
return modif_deltat;
|
|
};
|
|
|
|
// lecture des paramètres du calcul
|
|
void AlgoriRelaxDyna::lecture_Parametres(UtilLecture& entreePrinc)
|
|
{ MotCle motCle; // ref aux mots cle
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(RELAX_DYNA); // transfert info
|
|
deja_lue_entete_parametre = 1; // a priori pas de lecture d'entête
|
|
// on se positionne sur le prochain mot clé
|
|
do
|
|
{ entreePrinc.NouvelleDonnee();
|
|
}
|
|
while ( !motCle.SimotCle(entreePrinc.tablcar)) ;
|
|
// si le mot clé est "PARA_TYPE_DE_CALCUL" cela signifie
|
|
// qu'il y a un paramètre à lire
|
|
bool lecture_effective = false; // indiquera si oui ou non on a lue quelque chose
|
|
// donc que l'on doit passer à la ligne qui suit
|
|
string nom_class_methode("AlgoriRelaxDyna::lecture_Parametres"); // pour la lecture
|
|
int min=1,max=0;string mot_cle;int int_defaut=0; double double_defaut=0;// variables inter qui servent pour la lecture
|
|
double double_min = 1.; double double_max = 0.;
|
|
if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL)
|
|
{ //cas de la définition de paramètres
|
|
// on signale à Algori qu'il y a eu déjà une lecture de paramètre
|
|
deja_lue_entete_parametre=2;
|
|
// --- lecture facultative du premier paramètres de l'algorithme:
|
|
entreePrinc.NouvelleDonnee(); // ligne suivante
|
|
int_defaut=1; mot_cle="typeCalRelaxation=";min=1;max=4;
|
|
{bool lec_eff = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,typeCalRelaxation);
|
|
lecture_effective = lecture_effective || lec_eff;
|
|
// dans le cas où on va utiliser une relaxation avec amortissement visqueux on l'indique au niveau des paramètres généraux
|
|
if ((typeCalRelaxation ==2 )||(typeCalRelaxation ==3 )||(typeCalRelaxation ==4 ))
|
|
{pa.Change_amort_visco_artificielle(4);};
|
|
};
|
|
// --- lecture facultative du paramètres lambda :
|
|
double_defaut=0.605; mot_cle="lambda=";
|
|
min=1;max=0; // le max < min ==> pas de prise en compte de valeurs
|
|
{bool lec_eff = entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,lambda);
|
|
lecture_effective = lecture_effective || lec_eff;
|
|
lambda_initial=lambda;
|
|
};
|
|
|
|
// --- lecture facultative du paramètres type_calcul_mass :
|
|
int_defaut=2; mot_cle="type_calcul_mass="; min=1;max=2;
|
|
{bool lec_eff = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,type_calcul_mass);
|
|
lecture_effective = lecture_effective || lec_eff;
|
|
};
|
|
|
|
// --- lecture éventuelle de l'option_recalcul_mass
|
|
if (strstr(entreePrinc.tablcar,"option_recalcul_mass=")!=NULL)
|
|
{ // à ce niveau on ne lit a priori qu'une valeur
|
|
// 1- init par défaut
|
|
option_recalcul_mass.Change_taille(1,0);
|
|
nom_fct_nD_option_recalcul_mass.Change_taille(1,"");
|
|
fct_nD_option_recalcul_mass.Change_taille(1,NULL);
|
|
int_defaut=0; mot_cle="option_recalcul_mass="; min=-1;max=5;
|
|
// 2- on regarde s'il y a une présence d'une fonction nD
|
|
// pour cela on lit la première chaine de caractère
|
|
string nom_inter;
|
|
bool lec_eff = entreePrinc.Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_inter);
|
|
lecture_effective = lecture_effective || lec_eff;
|
|
// maintenant on scrute le nom_inter
|
|
string iden("nom_fct_nD_option_recalcul_mass_");
|
|
std::size_t found = nom_inter.find(iden);
|
|
if (found!=std::string::npos) // si oui on a trouvé la chaine
|
|
// on lit le nom de la fonction
|
|
{ *(entreePrinc.entree) >> nom_fct_nD_option_recalcul_mass(1);}
|
|
else // sinon cela signifie qu'il s'agit d'une valeur fixe
|
|
{option_recalcul_mass(1) = ChangeEntier(nom_inter);};
|
|
// dans tous les cas on met à NULL pour l'instant le pointeur de fonction
|
|
fct_nD_option_recalcul_mass(1) = NULL;
|
|
};
|
|
|
|
// --- lecture éventuelle de l'option_recalcul_mass spécifiquement pour l'amortissement visqueux
|
|
int_defaut=0; mot_cle="opt_visqueux_recal_mass="; min=-1;max=5;
|
|
{// on est obligé de regardé si l'indicateur existe avant toute chose
|
|
if (strstr(entreePrinc.tablcar,"opt_visqueux_recal_mass=")!=NULL)
|
|
{// 1) là if faut redimentionner les tableaux
|
|
option_recalcul_mass.Change_taille(2);
|
|
nom_fct_nD_option_recalcul_mass.Change_taille(2);
|
|
fct_nD_option_recalcul_mass.Change_taille(2);
|
|
// 2- on regarde s'il y a une présence d'une fonction nD
|
|
// pour cela on lit la première chaine de caractère
|
|
string nom_inter;
|
|
bool lec_eff = entreePrinc.Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_inter);
|
|
lecture_effective = lecture_effective || lec_eff;
|
|
// maintenant on scrute le nom_inter
|
|
string iden("nom_fct_nD_option_recalcul_mass_");
|
|
std::size_t found = nom_inter.find(iden);
|
|
if (found!=std::string::npos) // si oui on a trouvé la chaine
|
|
// on lit le nom de la fonction
|
|
{ *(entreePrinc.entree) >> nom_fct_nD_option_recalcul_mass(2);}
|
|
else // sinon cela signifie qu'il s'agit d'une valeur fixe
|
|
{ option_recalcul_mass(2) = ChangeEntier(nom_inter); };
|
|
// dans tous les cas on met à NULL pour l'instant le pointeur de fonction
|
|
fct_nD_option_recalcul_mass(2) = NULL;
|
|
};
|
|
};
|
|
|
|
// ----------- maintenant on va lire les paramètres de contrôle éventuelles ------------
|
|
if (lecture_effective)
|
|
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la première ligne on passe
|
|
lecture_effective=false;
|
|
};
|
|
|
|
while ( (strstr(entreePrinc.tablcar,"parametre_recalcul_de_la_masse_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_masse_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"parametre_activation_du_contact_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"choix_mini_masse_nul=")!= NULL)
|
|
|| (strstr(entreePrinc.tablcar,"proportion_cinetique=")!= NULL)
|
|
|| (strstr(entreePrinc.tablcar,"propCinetiqueAvecPonderation_temps_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"propCinetiqueAvecPonderation_Globale_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"lambdaAvecPonderation_temps_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"lambdaAvecPonderation_Globale_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"pilotageAutolambda_")!=NULL)
|
|
|| (strstr(entreePrinc.tablcar,"cL_a_chaque_iteration_")!=NULL)
|
|
)
|
|
{
|
|
//=== paramètres de controle du calcul de la masse =====
|
|
if (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_masse_")!=NULL)
|
|
{ mot_cle="parametre_calcul_de_la_masse_";
|
|
lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
|
|
// si on arrive ici c'est que l'on a bien lue le mot clé "parametre_calcul_de_la_masse_"
|
|
// donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen
|
|
if (type_calcul_mass == 1)
|
|
{ // cas, du modèle d'han lee amélioré
|
|
// --- lecture éventuelle de alpha
|
|
double_defaut=1.; mot_cle="alpha="; min=1;max=0;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,alph);
|
|
// --- lecture éventuelle de beta
|
|
double_defaut=1.; mot_cle="beta="; min=1;max=0;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,beta);
|
|
// --- lecture éventuelle de gamma
|
|
double_defaut=1.; mot_cle="gamma="; min=1;max=0;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,gamma);
|
|
// --- lecture éventuelle de theta
|
|
double_defaut=1.; mot_cle="theta="; min=1;max=0;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,theta);
|
|
// --- lecture éventuelle de casMass_relax
|
|
int_defaut=3; mot_cle="casMass_relax="; min=1;max=5;
|
|
entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,casMass_relax);
|
|
}
|
|
else if (type_calcul_mass == 2)
|
|
{ // cas du modèle de calcul utilisant la matrice de raideur
|
|
// --- lecture éventuelle de casMass_relax
|
|
int_defaut=3; mot_cle="casMass_relax="; min=0;max=9;
|
|
entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,casMass_relax);
|
|
};
|
|
};
|
|
if (lecture_effective)
|
|
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
|
|
lecture_effective=false;
|
|
};
|
|
|
|
//=== paramètres de controle du re-calcul de la masse =====
|
|
if (strstr(entreePrinc.tablcar,"parametre_recalcul_de_la_masse_")!=NULL)
|
|
{ mot_cle="parametre_recalcul_de_la_masse_";
|
|
lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
|
|
// si on arrive ici c'est que l'on a bien lue le mot clé "parametre_calcul_de_la_masse_"
|
|
// donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen
|
|
// --- lecture éventuelle de fac_epsilon
|
|
double_defaut=1.; mot_cle="fac_epsilon="; min=1;max=0;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,fac_epsilon);
|
|
// --- lecture éventuelle de ncycle_calcul
|
|
double_defaut=100; mot_cle="ncycle_calcul="; min=1;max=ConstMath::grand;
|
|
entreePrinc.Lecture_un_parametre_int(double_defaut,nom_class_methode,min,max,mot_cle,ncycle_calcul);
|
|
// --- vérification de l'existence éventuelle du mot clé: et_recalcul_masse_a_la_transition_
|
|
if (strstr(entreePrinc.tablcar,"et_pas_recalcul_masse_a_la_transition_")!=NULL)
|
|
{// si oui, on lit le mot clé
|
|
mot_cle="et_pas_recalcul_masse_a_la_transition_";
|
|
lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
|
|
et_recalcul_masse_a_la_transition = 0; // on enregistre
|
|
};
|
|
};
|
|
if (lecture_effective)
|
|
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
|
|
lecture_effective=false;
|
|
};
|
|
|
|
//=== paramètres de controle automatique de l'évolution de lambda =====
|
|
if (strstr(entreePrinc.tablcar,"pilotageAutolambda_")!=NULL)
|
|
{ mot_cle="pilotageAutolambda_";
|
|
lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
|
|
pilotage_auto_lambda = true;
|
|
// si on arrive ici c'est que l'on a bien lue le mot clé "pilotageAutolambda_"
|
|
// donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen
|
|
|
|
// --- lecture éventuelle de lambda_min
|
|
double xmin = 0.5; double xmax = 50.;
|
|
double_defaut=0.605; mot_cle="lambda_min=";
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,xmin,xmax,mot_cle,lambda_min);
|
|
|
|
// --- lecture éventuelle de lambda_max
|
|
xmin = 0.5; xmax = ConstMath::grand;
|
|
double_defaut=ConstMath::grand; mot_cle="lambda_max="; ;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,xmin,xmax,mot_cle,lambda_max);
|
|
|
|
// --- lecture éventuelle de delta_lambda
|
|
xmin = 0.; xmax = ConstMath::grand;
|
|
double_defaut=0.1; mot_cle="delta_lambda="; ;
|
|
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,xmin,xmax,mot_cle,delta_lambda);
|
|
};
|
|
if (lecture_effective)
|
|
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
|
|
lecture_effective=false;
|
|
};
|
|
|
|
//=== paramètres de controle de l'activation du contact =====
|
|
if (strstr(entreePrinc.tablcar,"parametre_activation_du_contact_")!=NULL)
|
|
{ mot_cle="parametre_activation_du_contact_";
|
|
lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
|
|
// si on arrive ici c'est que l'on a bien lue le mot clé "parametre_activation_du_contact_"
|
|
// donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen
|
|
// --- lecture éventuelle de type_activation_contact
|
|
int_defaut=1; mot_cle="type_activation_contact="; min=0;max=2;
|
|
entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,type_activation_contact);
|
|
};
|
|
|
|
//=== paramètres de controle d'une masse nulle =====
|
|
if (strstr(entreePrinc.tablcar,"choix_mini_masse_nul=")!=NULL)
|
|
{ // --- lecture éventuelle de choix_mini_masse_nul
|
|
int_defaut=1; mot_cle="choix_mini_masse_nul="; min=0;max=2;
|
|
lecture_effective = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,choix_mini_masse_nul);
|
|
};
|
|
|
|
//=== paramètres de controle de la proportion de cinétique / visqueux pour le type 4 =====
|
|
if (strstr(entreePrinc.tablcar,"proportion_cinetique=")!=NULL)
|
|
{ // --- lecture éventuelle de proportion_cinetique
|
|
double_defaut=0.1; mot_cle="proportion_cinetique="; double_min=0;double_max=1.;
|
|
lecture_effective = entreePrinc.Lecture_un_parametre_double
|
|
(double_defaut,nom_class_methode,double_min,double_max,mot_cle,proportion_cinetique);
|
|
};
|
|
|
|
//=== paramètres de controle de la proportion de cinétique / visqueux pour le type 4 =====
|
|
// utilisation d'une dépendance au temps éventuelle: on lit le nom de la fonction
|
|
if (strstr(entreePrinc.tablcar,"propCinetiqueAvecPonderation_temps_")!=NULL)
|
|
{ // --- lecture du nom de la fonction de dépendance au temps
|
|
mot_cle="propCinetiqueAvecPonderation_temps_";
|
|
niveauF_temps = new Ponderation_temps();
|
|
string nom_fonction; // init
|
|
lecture_effective = entreePrinc.Lecture_mot_cle_et_string
|
|
(nom_class_methode,mot_cle,nom_fonction);
|
|
niveauF_temps->Nom_fonction() = nom_fonction; // affectation du nom de la fonction
|
|
};
|
|
|
|
//=== paramètres de controle de la proportion de cinétique / visqueux pour le type 4 =====
|
|
// utilisation d'une dépendance à des variables globales éventuelles: on lit le nom de la fonction
|
|
if (strstr(entreePrinc.tablcar,"propCinetiqueAvecPonderation_Globale_")!=NULL)
|
|
{ // --- lecture du nom de la fonction de dépendance au temps
|
|
mot_cle="propCinetiqueAvecPonderation_Globale_";
|
|
niveauF_grandeurGlobale = new Ponderation_GGlobal();
|
|
string nom_fonction; // init
|
|
lecture_effective = entreePrinc.Lecture_mot_cle_et_string
|
|
(nom_class_methode,mot_cle,nom_fonction);
|
|
niveauF_grandeurGlobale->Nom_fonction() = nom_fonction; // affectation du nom de la fonction
|
|
};
|
|
|
|
|
|
//=== paramètres de controle de la proportion de cinétique / visqueux pour le type 4 =====
|
|
// utilisation d'une dépendance au temps éventuelle: on lit le nom de la fonction
|
|
if (strstr(entreePrinc.tablcar,"lambdaAvecPonderation_temps_")!=NULL)
|
|
{ // --- lecture du nom de la fonction de dépendance au temps
|
|
mot_cle="lambdaAvecPonderation_temps_";
|
|
niveauLambda_temps = new Ponderation_temps();
|
|
string nom_fonction; // init
|
|
lecture_effective = entreePrinc.Lecture_mot_cle_et_string
|
|
(nom_class_methode,mot_cle,nom_fonction);
|
|
niveauLambda_temps->Nom_fonction() = nom_fonction; // affectation du nom de la fonction
|
|
};
|
|
|
|
//=== paramètres de controle de la proportion de cinétique / visqueux pour le type 4 =====
|
|
// utilisation d'une dépendance à des variables globales éventuelles: on lit le nom de la fonction
|
|
if (strstr(entreePrinc.tablcar,"lambdaAvecPonderation_Globale_")!=NULL)
|
|
{ // --- lecture du nom de la fonction de dépendance au temps
|
|
mot_cle="lambdaAvecPonderation_Globale_";
|
|
niveauLambda_grandeurGlobale = new Ponderation_GGlobal();
|
|
string nom_fonction; // init
|
|
lecture_effective = entreePrinc.Lecture_mot_cle_et_string
|
|
(nom_class_methode,mot_cle,nom_fonction);
|
|
niveauLambda_grandeurGlobale->Nom_fonction() = nom_fonction; // affectation du nom de la fonction
|
|
};
|
|
|
|
if (mot_cle == "cL_a_chaque_iteration_")
|
|
{ // on lit le paramètre
|
|
*(entreePrinc.entree) >> cL_a_chaque_iteration;
|
|
lecture_effective = true;
|
|
};
|
|
|
|
if (lecture_effective)
|
|
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
|
|
lecture_effective=false;
|
|
};
|
|
}; // fin du while
|
|
|
|
}
|
|
else // sinon , cas où il n'y a pas de paramètres de calcul, on met les valeurs par défaut
|
|
{ typeCalRelaxation=1; lambda = 0.605;lambda_initial=lambda;
|
|
type_calcul_mass= 2;
|
|
option_recalcul_mass.Change_taille(1,0);
|
|
nom_fct_nD_option_recalcul_mass.Change_taille(1,"");
|
|
fct_nD_option_recalcul_mass.Change_taille(1,NULL);
|
|
alph=1; beta = 1.;gamma=1.;theta=1.; casMass_relax=3;
|
|
fac_epsilon= 1.;type_activation_contact= 1;choix_mini_masse_nul=0;
|
|
proportion_cinetique=0.1;
|
|
// pilotage auto éventuel
|
|
lambda_min=0.605;lambda_max=50.;delta_lambda=0.1;
|
|
pilotage_auto_lambda=false;
|
|
cL_a_chaque_iteration = 0;
|
|
};
|
|
|
|
// mise à jour variable globale
|
|
switch (typeCalRelaxation)
|
|
{ case 1: visqueux_activer = false; break;
|
|
case 2: visqueux_activer = true; break;
|
|
case 4: visqueux_activer = false; break; // au début en cinétique
|
|
default:
|
|
cout <<"\n typeCalRelaxation = " << typeCalRelaxation
|
|
<< " cas non pris en compte dans AlgoriRelaxDyna::Lecture_Base_info_Parametre( ";
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
|
|
// on prépare la prochaine lecture si la lecture a été effective et que l'on n'est pas
|
|
// sur un mot clé
|
|
if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar)))
|
|
entreePrinc.NouvelleDonnee(); // ligne suivante
|
|
// puis appel de la méthode de la classe mère
|
|
Algori::lecture_Parametres(entreePrinc);
|
|
};
|
|
|
|
// création d'un fichier de commande: cas des paramètres spécifiques
|
|
void AlgoriRelaxDyna::Info_commande_parametres(UtilLecture& entreePrinc)
|
|
{ // écriture dans le fichier de commande
|
|
ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
|
|
sort << "\n# -----------------------------------------------------------------------------"
|
|
<< "\n#| 1) parametres (falcultatifs ) associes au calcul de relaxation dynamique |"
|
|
<< "\n#| avec en continu, modification et optimisation de la matrice masse |"
|
|
<< "\n#| 2) un parametre (falcultatif ) specifique au contact |"
|
|
<< "\n# -----------------------------------------------------------------------------"
|
|
<< "\n"
|
|
<< "\n # PARA_TYPE_DE_CALCUL"
|
|
<< "\n # ........................................................."
|
|
<< "\n # / type d'algorithme /"
|
|
<< "\n #........................................................."
|
|
<< "\n # plusieurs methodes d'amortissement dynamique sont implantees "
|
|
<< "\n # le parametre typeCalRelaxation= indique le choix de la methode : "
|
|
<< "\n # "
|
|
<< "\n # typeCalRelaxation= 1 : Il s'agit d'une relaxation avec amortissement cinetique, qui utilise differente "
|
|
<< "\n # techniques pour le calcul de la pseudo-masse. Ces techniques sont differenciee a l'aide"
|
|
<< "\n # de parametres particuliers explicites par la suite. L'amortissement etant cinetique "
|
|
<< "\n # on peut donc modifier egalement les parametres de l'amortissement cinetique"
|
|
<< "\n # "
|
|
<< "\n # typeCalRelaxation= 2 : Il s'agit d'une relaxation avec amortissement visqueux critique, qui utilise les memes "
|
|
<< "\n # technique de calcul de la pseudo-masse que le cas typeCalRelaxation= 1 par contre "
|
|
<< "\n # l'amortissement est different car visqueux critique. "
|
|
<< "\n # "
|
|
<< "\n # typeCalRelaxation= 4 : Il s'agit d'une relaxation avec amortissement cinetique au debut du calcul "
|
|
<< "\n # puis a partir d'un seuil, le calcul se poursuit avec un amortissement visqueux."
|
|
<< "\n # La premiere partie suit la methodologie du cas : typeCalRelaxation= 1 "
|
|
<< "\n # La seconde partie suit la methodologie du cas: typeCalRelaxation= 2"
|
|
<< "\n # Le seuil est cacule a partir d'une fonction multidimensionnelle des grandeures globales"
|
|
<< "\n # exemple syntaxe, a inserer a la fin des parametres de l'algo : "
|
|
<< "\n # les_grandeurs_de_controle_= NORME_CONVERGENCE fin_grandeurs_ "
|
|
<< "\n # fonctions_changement_amortissement= fct1 fin_fonct_ "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # Pour chaque type de methode, des parametres specifiques sont associes pour controler son comportement "
|
|
<< "\n # "
|
|
<< "\n # le typeCalRelaxation= est par defaut = 1 "
|
|
<< "\n # "
|
|
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ------------- typeCalRelaxation= 1 ----------------------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # dans le cas ou typeCalRelaxation= 1, il s'agit d'une relaxation avec amortissement cinetique, "
|
|
<< "\n # associee avec un type particulier de calcul de la matrice masse "
|
|
<< "\n # a) le parametre qui permet de choisir parmis les differents cas est type_calcul_mass "
|
|
<< "\n # Son utilisation est decrite par la suite "
|
|
<< "\n # b) on peut egalement intervenir sur les parametres qui pilotes l'amortissement cinetique (cf. doc) "
|
|
<< "\n # c) Il y a egalement un parametre lambda permettant de ponderer le calcul de la masse "
|
|
<< "\n # d) enfin un parametre option_recalcul_mass= permet de choisir le test de re-calcul de la matrice masse "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## typeCalRelaxation= 1 lambda= 0.7 type_calcul_mass= 1 option_recalcul_mass= 1 "
|
|
<< "\n # "
|
|
<< "\n # >>>>> PARTICULARITE DU PARAMETRE: option_recalcul_mass= "
|
|
<< "\n # ==> A la place d'une valeur numerique pour option_recalcul_mass= il est possible d'indiquer le "
|
|
<< "\n # nom d'une fonction nD precede du mot cle : nom_fct_nD_option_recalcul_mass_ "
|
|
<< "\n # on aura alors la syntaxe suivane: "
|
|
<< "\n # option_recalcul_mass= nom_fct_nD_option_recalcul_mass_ <un nom de fonction nD> "
|
|
<< "\n # dans ce cas le recalcul de la masse suis l'option indiquee par le retour de la fonction nD "
|
|
<< "\n # en particulier si elle retourne 0 pendant l'execution, il n'y pas de recalcul de masse "
|
|
<< "\n # NB: La fonction doit evidemment exister, elle doit egalement uniquement utiliser des grandeurs"
|
|
<< "\n # globales. "
|
|
<< "\n # La fonction est appelee en particulier a chaque iteration. "
|
|
<< "\n # L'utilisation d'une fonction nD est possible avec tous les types de relaxation "
|
|
<< "\n # cinetique, visqueux et egalement mixte "
|
|
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ------------- typeCalRelaxation= 2 ----------------------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # dans le cas ou typeCalRelaxation= 2, il s'agit d'une relaxation avec amortissement visqueux critique, "
|
|
<< "\n # associee avec des types de calcul de la matrice masse different du cas de Barnes "
|
|
<< "\n # a) le parametre qui permet de choisir parmis les differents cas de masse est type_calcul_mass "
|
|
<< "\n # Son utilisation est decrite par la suite "
|
|
<< "\n # b) on peut egalement intervenir sur les parametres qui pilotes l'amortissement visqueux (cf. doc) "
|
|
<< "\n # c) Il y a egalement un parametre lambda permetant de ponderer le calcul de la masse "
|
|
<< "\n # d) enfin un parametre option_recalcul_mass= permet de choisir le test de re-calcul de la matrice masse "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## typeCalRelaxation= 2 lambda= 0.7 type_calcul_mass= 2 option_recalcul_mass= 4 "
|
|
<< "\n # "
|
|
<< "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: "
|
|
<< "\n # typeCalRelaxation= 2 ; lambda= 0.605 ; type_calcul_mass= 2; option_recalcul_mass= 0; "
|
|
<< "\n # "
|
|
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ------------- typeCalRelaxation= 4 ----------------------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # il s'agit d'une relaxation mixte qui debute en amortissement cinetique et peut terminer en visqueux "
|
|
<< "\n # On indique les parametres habituels: lambda , le type de calcul de masse , et son recalcul "
|
|
<< "\n # suivent dans un ordre quelconque les parametres facultatifs suivants ( explicites ensuite) : "
|
|
<< "\n # parametre_recalcul_de_la_masse_ parametre_calcul_de_la_masse_ "
|
|
<< "\n # parametre_activation_du_contact_ , choix_mini_masse_nul= , proportion_cinetique= "
|
|
<< "\n # propCinetiqueAvecPonderation_temps_ , propCinetiqueAvecPonderation_Globale_"
|
|
<< "\n # lambdaAvecPonderation_temps_ , lambdaAvecPonderation_Globale_ , pilotageAutolambda_ "
|
|
<< "\n # "
|
|
<< "\n # parmi l'ensemble de ces parametres, il faut noter: "
|
|
<< "\n # 1) proportion_cinetique= suivi d'un reel: par defaut vaut 0.1 "
|
|
<< "\n # ce parametre indique la proportion (proportion_cinetique) qu'il faut atteindre relativement "
|
|
<< "\n # a la precision demandee, pour basculer de l'amortissement cinetique a l'amortissement visqueux "
|
|
<< "\n # 2) propCinetiqueAvecPonderation_temps_ suivi d'un nom de fonction 1D "
|
|
<< "\n # --> indique le nom d'une fonction 1D du temps, qui permet de faire evoluer le parametre "
|
|
<< "\n # proportion_cinetique en fonction du temps : "
|
|
<< "\n # le resultat = la valeur initiale de proportion_cinetique * la valeur de la fonction(temps) "
|
|
<< "\n # 3) propCinetiqueAvecPonderation_Globale_ suivi d'un nom de fonction nD "
|
|
<< "\n # --> indique le nom d'une fonction nD de grandeurs globales, qui permet de faire "
|
|
<< "\n # evoluer le parametre proportion_cinetique en fonction de grandeurs globales : "
|
|
<< "\n # le resultat = la valeur initiale de proportion_cinetique * la valeur de la fonction nD "
|
|
<< "\n # 4) il est possible d'indiquer de ne pas recalculer la masse au moment de la transition "
|
|
<< "\n # cinetique - visqueux, pour cela il faut indiquer le mot cle "
|
|
<< "\n # et_pas_recalcul_masse_a_la_transition_ a la fin de la declaration "
|
|
<< "\n # des parametres de controle du re-calcul de la matrice masse (voir les declarations"
|
|
<< "\n # associees a ce parametre (par defaut, a la transition il y a recalcul de la masse)) "
|
|
<< "\n # "
|
|
<< "\n # 5) il est possible d'indiquer un parametre de recalcul de la masse, different du "
|
|
<< "\n # cas de l'amortissement cinetique. Pour cela, en plus et a la suite du mot cle "
|
|
<< "\n # option_recalcul_mass= on peut indiquer opt_visqueux_recal_mass= suivi du cas "
|
|
<< "\n # qui sera utilise pour le calcul de la masse lorsque l'on sera en amortissement "
|
|
<< "\n # visqueux"
|
|
<< "\n # Comme pour le premier parametre de recalcul de masse, a la place d'une "
|
|
<< "\n # valeur numerique, on peut indiquer la presence d'une fonction nD a l'aide "
|
|
<< "\n # du mot cle nom_fct_nD_option_recalcul_mass_ suivi du nom d'une fonction nD"
|
|
<< "\n # (cf. les informations precedentes concernant option_recalcul_mass) "
|
|
<< "\n # "
|
|
<< "\n # Important: en fait le parametre opt_visqueux_recal_mass= est utilisable avec "
|
|
<< "\n # tous les types de relaxation, lorsqu'il est presant, suivant qu'il s'agit d'un "
|
|
<< "\n # d'un amortissement cinetique ou visqueux, ce sera le premier ou le second"
|
|
<< "\n # type de recalcul de masse qui sera utilise "
|
|
<< "\n # "
|
|
<< "\n # Exemple de declaration, : "
|
|
<< "\n # (ici apres la transition vers l'amortissement visqueux, option_recalcul_mass "
|
|
<< "\n # initialement a 0, passe à 3) "
|
|
<< "\n # "
|
|
<< "\n # typeCalRelaxation= 4 lambda= 0.6 type_calcul_mass= 2 option_recalcul_mass= 0 \\ "
|
|
<< "\n # opt_visqueux_recal_mass= 3 "
|
|
<< "\n # parametre_calcul_de_la_masse_ casMass_relax= 3 "
|
|
<< "\n # proportion_cinetique= 0.1 "
|
|
<< "\n # parametre_recalcul_de_la_masse_ ncycle_calcul= 100 et_pas_recalcul_masse_a_la_transition_"
|
|
<< "\n # parametre_calcul_de_la_viscosite_ type_calcul_visqu_critique= 2 \\ "
|
|
<< "\n # opt_cal_C_critique= 1 f_= 0.9 "
|
|
<< "\n # mode_debug_= 100 "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # une fois typeCalRelaxation et les parametres generaux definis on trouve sur les lignes qui suivent "
|
|
<< "\n # (une ligne par paquet de parametres) "
|
|
<< "\n # 1) eventuellement les parametres permettant de controler le calcul de la pseudo-masse "
|
|
<< "\n # 2) eventuellement les parametres permettant de controler le calcul de la matrice visqueuse "
|
|
<< "\n # 3) eventuellement les parametres de controle du re-calcul de la matrice masse "
|
|
<< "\n # 4) eventuellement le parametre de controle du mode debug "
|
|
<< "\n # "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # --- parametres de controle du calcul de la masse ----------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ** PARAMETRES FACULTATIF ** "
|
|
<< "\n # on indique tout d'abord le mot cle : parametre_calcul_de_la_masse_ suivi des parametres associe "
|
|
<< "\n # "
|
|
<< "\n # =====> si type_calcul_mass= 1 : on a le fonctionnement suivant: "
|
|
<< "\n # la pseudo-masse elementaire est calculee avec la formule: "
|
|
<< "\n # mi=lambda*(ep/8)*(alpha*K+beta*mu+gamma*Isig/3+theta/2*Sig_mises "
|
|
<< "\n # Les parametres lambda, alpha, beta, gamma et theta permettent donc de ponderer le calcul de la masse "
|
|
<< "\n # ep: epaisseur, K module de compressibilite, mu: module de cisaillement, Isig trace de sigma, "
|
|
<< "\n # Sig_mises la contrainte de mises "
|
|
<< "\n # casMass_relax permet de choisir parmi differentes methodes de calcul de la matrice masse "
|
|
<< "\n # =1 on cumule la formule aux noeuds, en fonction de tous les elements qui entourent l'element"
|
|
<< "\n # =2 on prend le maximum de la formule aux noeuds, en fonction des elements l'entourant"
|
|
<< "\n # =3 on prend la moyenne de la formule aux noeuds, en fonction des elements l'entourant "
|
|
<< "\n # =4 on prend la moyenne et on divise par la section, comme dans la formule originale de Barnes "
|
|
<< "\n # =5 idem 1, et on divise par la section, comme dans la formule originale de Barnes "
|
|
<< "\n\n # l'algorithme a recours automatiquement a la relaxation cinetique. On peut donc "
|
|
<< "\n # aussi modifier les paramtetres de reglage de cette partie, sinon ce sont les parametres "
|
|
<< "\n # par defaut qui sont retenu (voir doc) "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## parametre_calcul_de_la_masse_ alpha= 1. beta= 1. gamma= 1. theta= 1. casMass_relax= 1 "
|
|
<< "\n # "
|
|
<< "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: "
|
|
<< "\n # alpha= 1 ; beta= 1. ; gamma= 1. ; theta= 1. ; casMass_relax= 3 ; "
|
|
<< "\n # "
|
|
<< "\n # =====> si type_calcul_mass= 2 : on a le fonctionnement suivant: "
|
|
<< "\n # la masse elementaire du noeud i est calculee a partir de la raideur reelle "
|
|
<< "\n # notation: ai c'est le a du noeud i, idem pour b "
|
|
<< "\n # m_(a_i) = lambda/2 * S(a_i) , a=1 a dim de l'espace "
|
|
<< "\n # casMass_relax= permet de choisir comment la matrice de masse est calculer. "
|
|
<< "\n # Sur l'ensemble de la matrice de raideur assemblee normalement "
|
|
<< "\n # casMass_relax= 0 : S(ai) = |K(ai,ai)| "
|
|
<< "\n # casMass_relax= 1 : S(bi) = sup_a ( |K(ai,ai)|), a=1 a dim , b=1 a dim "
|
|
<< "\n # pour chaque assemblage de matrice elementaire : "
|
|
<< "\n # casMass_relax= 2 : S(ai) = sum_{k,b} |K_loc(ai,bk)|, k=1,nbn; b=1,dim; (majoration du th de Gerschgorin) "
|
|
<< "\n # casMass_relax= 3 : S(ci) = sup_a (sum_{k,b} |K_loc(ai,bk)|), k=1,nbn; b=1,dim; c=1,dim; (majoration du th de Gerschgorin) "
|
|
<< "\n # casMass_relax= 4 : S(ai) = sup (2.*|K_loc(ai,ai)|, sum_{k,b} |K_loc(ai,bk)|, k=1,nbn; b=1,dim) "
|
|
<< "\n # casMass_relax= 5 : S(cj) = sup_a (sup (2.*|K_loc(ai,ai)|, sum_{k,b} |K_loc(ai,bk)|, k=1,nbn; b=1,dim)), c=1,dim;"
|
|
<< "\n # "
|
|
<< "\n # de nouveau sur l'ensemble de la matrice de raideur assemblee normalement K = K_globale "
|
|
<< "\n # casMass_relax= 6 : S(ai) = sum_{k,b} |K(ai,bk)|, k=1,nbn; b=1,dim; (th de Gerschgorin) "
|
|
<< "\n # casMass_relax= 7 : S(ci) = sup_a (sum_{k,b} |K(ai,bk)|), k=1,nbn; b=1,dim; c=1,dim; (th de Gerschgorin) "
|
|
<< "\n # casMass_relax= 8 : S(ai) = sup (2.*|K(ai,ai)|, sum_{k,b} |K(ai,bk)|, k=1,nbn; b=1,dim) "
|
|
<< "\n # casMass_relax= 9 : S(cj) = sup_a (sup (2.*|K(ai,ai)|, sum_{k,b} |K(ai,bk)|, k=1,nbn; b=1,dim)), c=1,dim;"
|
|
<< "\n # "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## parametre_calcul_de_la_masse_ casMass_relax= 3 "
|
|
<< "\n # "
|
|
<< "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: "
|
|
<< "\n # casMass_relax= 3 "
|
|
<< "\n # "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # --- parametres de controle du re-calcul de la masse ----------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ** PARAMETRES FACULTATIF ** "
|
|
<< "\n # on indique tout d'abord le mot cle : parametre_recalcul_de_la_masse_ "
|
|
<< "\n # suivi des parametres associes eventuelles "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # Attention: "
|
|
<< "\n # si option_recalcul_mass= -1 : la matrice masse est recalculee a chaque iteration "
|
|
<< "\n # si option_recalcul_mass= 0 : la matrice masse est calculée au debut du calcul de l'increment et ensuite elle reste fixe "
|
|
<< "\n # il n'y a pas de parametres associes supplementaire "
|
|
<< "\n # si option_recalcul_mass= 1 : apres un calcul au debut, mise a jour a chaque maxi de l'energie cinetique "
|
|
<< "\n # il n'y a pas de parametres associes supplementaire "
|
|
<< "\n # si option_recalcul_mass= 2 : idem le cas 1, mais on garde la valeur maxi de la raideur entre la nouvelle et l'ancienne"
|
|
<< "\n # il n'y a pas de parametres associes supplementaire "
|
|
<< "\n # si option_recalcul_mass= 3 : recalcul apres ncycles, valeur qui doit etre indiquee apres le mot cle ncycle_calcul= "
|
|
<< "\n # de la maniere suivante par exemple pour un calcul tous les 100 "
|
|
<< "\n ## parametre_recalcul_de_la_masse_ ncycle_calcul= 100 "
|
|
<< "\n # par defaut ncycle_calcul= 100 "
|
|
<< "\n # si option_recalcul_mass= 4 : recalcule de la matrice masse lorsque l'indicateur suivant "
|
|
<< "\n # \epsilon = MAX_{i=1}^{nbddl}{ ( 0.5*lambda * (Delta t)^2) (|Delta ddot X_i|) / (|Delta X_i|) } "
|
|
<< "\n # est superieur a 1*fac_epsilon "
|
|
<< "\n # par defaut fac_epsilon = 1, on peut le modifier a l'aide du parametre fac_epsilon= une valeur "
|
|
<< "\n # ( ce type de controle provient de l'amortissement visqueux critique) "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## parametre_recalcul_de_la_masse_ fac_epsilon= 1. "
|
|
<< "\n # "
|
|
<< "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: "
|
|
<< "\n # fac_epsilon= 1. ; "
|
|
<< "\n # "
|
|
<< "\n # Remarque: a la fin de ligne relative au mot cle parametre_recalcul_de_la_masse_ "
|
|
<< "\n # il est possible d'indiquer le mot cle et_pas_recalcul_masse_a_la_transition_ "
|
|
<< "\n # la presence de ce mot cle indique alors a l'algorithme de ne pas recalculer la masse "
|
|
<< "\n # lors de la transition cinetique - visqueux pour le cas: typeCalRelaxation= 4 "
|
|
<< "\n # pour les autres typeCalRelaxation la presence du mot cle "
|
|
<< "\n # et_recalcul_masse_a_la_transition_ n'a aucun effet "
|
|
<< "\n # le fonctionnement pas defaut est de recalculer la masse a la transition "
|
|
<< "\n # "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # --- parametres de pilotage de lambda ----------- "
|
|
<< "\n # ---------------------------------------------------------------------- "
|
|
<< "\n # ** PARAMETRES FACULTATIF ** "
|
|
<< "\n # trois types de pilotage sont disponibles au choix: "
|
|
<< "\n # "
|
|
<< "\n # 1) pilotage en fonction du temps physique: syntaxe "
|
|
<< "\n # lambdaAvecPonderation_temps_ suivi du nom d'une fonction 1D "
|
|
<< "\n # exemple de declaration: "
|
|
<< "\n # lambdaAvecPonderation_temps_ evolLambda # evolLambda est le nom d'une courbe 1D"
|
|
<< "\n # fonctionnement: a chaque increment de temps physique: "
|
|
<< "\n # lambda(t)= lambda(0) * evolLambda(t) "
|
|
<< "\n # avec lambda(0) le lambda fournit apres le mot clef: lambda="
|
|
<< "\n # "
|
|
<< "\n # 2) pilotage a l'aide d'une fonction nD: syntaxe "
|
|
<< "\n # lambdaAvecPonderation_Globale_ suivi du nom d'une fonction nD "
|
|
<< "\n # exemple de declaration: "
|
|
<< "\n # lambdaAvecPonderation_Globale_ fonct_cinetique # fonct_cinetique est le nom d'une courbe nD"
|
|
<< "\n # fonctionnement: a chaque iteration: "
|
|
<< "\n # lambda = lambda(0) * fonct_cinetique(grandeur(s) globale(s)) "
|
|
<< "\n # avec lambda(0) le lambda fournit apres le mot clef: lambda= "
|
|
<< "\n # "
|
|
<< "\n # 3) pilotage automatique: syntaxe "
|
|
<< "\n # pilotageAutolambda_ lambda_min= <une valeur> lambda_max= <une valeur> delta_lambda= <une valeur> "
|
|
<< "\n # exemple de declaration: "
|
|
<< "\n # pilotageAutolambda_ lambda_min= 0.6 lambda_max= 7 delta_lambda= 0.1 "
|
|
<< "\n # fonctionnement: on observe l'evolution des relaxations et lorsqu'il y a trop de relaxations "
|
|
<< "\n # lambda est augmente de delta_lambda a condition que la nouvelle valeur soit <= a lambda_max "
|
|
<< "\n # lambda_min ne sert pas pour l'instant "
|
|
<< "\n # Plus precisemment (version 6.799) soit la liste des iterations de relaxation "
|
|
<< "\n # le premier de la liste etant relatif a la derniere relaxation "
|
|
<< "\n # -> si le (3e - le premier) < 7 => augmentation de lambda "
|
|
<< "\n # -> si le (4e - le premier) < 10 => augmentation de lambda "
|
|
<< "\n # -> si le (5e - le premier) < 21 => augmentation de lambda "
|
|
<< "\n # "
|
|
<< "\n # ........................................................."
|
|
<< "\n # / parametre specifique au contact /"
|
|
<< "\n #........................................................."
|
|
<< "\n # ** PARAMETRES FACULTATIF ** "
|
|
<< "\n # on indique tout d'abord le mot cle : parametre_activation_du_contact_ suivi des parametres associes eventuelles "
|
|
<< "\n # type_activation_contact= 0 : la recherche de nouveaux contact est activee "
|
|
<< "\n # a la fin de chaque increment"
|
|
<< "\n # type_activation_contact= 1 : (valeur par defaut) la recherche de nouveaux contact est effectuee "
|
|
<< "\n # a la fin de chaque iteration "
|
|
<< "\n # type_activation_contact= 2 : la recherche de nouveaux contact est effectuee apres chaque amortissement cinetique "
|
|
<< "\n # et a la fin de chaque increment (s'il n'y a pas d'amortissement cinetique c'est "
|
|
<< "\n # equivalent au cas = 0 ) "
|
|
<< "\n # Exemple de declaration: "
|
|
<< "\n ## parametre_activation_du_contact_ type_activation_contact= 1 "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # Dans certain cas, la construction de la matrice masse conduit a des 0, il existe un parametre "
|
|
<< "\n # pour gerer le remplacement ou non de 0 sur la diagonale "
|
|
<< "\n # "
|
|
<< "\n # exemple de declaration: "
|
|
<< "\n # choix_mini_masse_nul= 0 "
|
|
<< "\n # "
|
|
<< "\n # Signification du parametre: "
|
|
<< "\n # =0 -> pas de modification du terme nul "
|
|
<< "\n # =1 -> remplacement du terme nul par le maxi des valeurs de la matrice masse deja calculee "
|
|
<< "\n # =2 -> remplacement du terme nul par la moyenne des valeurs de la matrice masse deja calculee "
|
|
<< "\n # "
|
|
|
|
<< "\n # ................................................................"
|
|
<< "\n # / mise en place des conditions limites a chaque iteration /"
|
|
<< "\n #.................................................................."
|
|
<< "\n # mot cle : cL_a_chaque_iteration_ suivi de 0 ou 1 "
|
|
<< "\n # par defaut == 0, c-a-d que les CL sont mises en place "
|
|
<< "\n # au debut de chaque increment et ensuite reste fixe pendant les iterations "
|
|
<< "\n # == 1 : a chaque iteration, les CL sont de nouveaux imposes "
|
|
|
|
<< "\n # "
|
|
<< "\n # "
|
|
<< "\n # "
|
|
;
|
|
|
|
// appel de la classe mère
|
|
Algori::Info_com_parametres(entreePrinc);
|
|
sort << "\n" << endl;
|
|
};
|
|
|
|
//------- 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 calculs
|
|
// certaines variables ont-été changés
|
|
// de même : MiseAJourAlgo a pour objectif de mettre à jour (vérif de la cohérence) des variables internes
|
|
// entre deux appels de CalEquilibre
|
|
|
|
// initialisation
|
|
void AlgoriRelaxDyna::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(RELAX_DYNA); // transfert info
|
|
|
|
#ifdef UTILISATION_MPI
|
|
int proc_en_cours = ParaGlob::Monde()->rank();
|
|
// 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,lesContacts);
|
|
tempsInitialisation.Arret_du_comptage(); // temps cpu
|
|
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
distribution_CPU_algo.Passage_Equilibrage_aux_CPU();
|
|
temps_transfert_court_algo.Arret_du_comptage(); // comptage cpu
|
|
tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
|
|
paraGlob->Init_tableau(distribution_CPU_algo.Tableau_element_CPU_en_cours()
|
|
,distribution_CPU_algo.Tab_indique_CPU_en_cours()
|
|
,distribution_CPU_algo.Tableau_noeud_CPU_en_cours()
|
|
,distribution_CPU_algo.Tab_indique_noeud_CPU_en_cours());
|
|
};
|
|
#endif
|
|
|
|
// avant toute chose, au cas où l'algo interviendrait après un autre algo
|
|
// on inactive tous les ddl existants
|
|
lesMail->Inactive_ddl();
|
|
// on regarde s'il s'agit d'un pb purement non méca, dans ce cas il faut cependant initialiser les positions
|
|
// à t et tdt pour le calcul de la métrique associée
|
|
{ const list <EnumElemTypeProblem >& type_pb = lesMail->Types_de_problemes();
|
|
bool purement_non_meca = true;
|
|
list <EnumElemTypeProblem >::const_iterator il,ilfin=type_pb.end();
|
|
for (il=type_pb.begin();il != ilfin; il++)
|
|
{switch (*il)
|
|
{ case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE:
|
|
purement_non_meca=false; break;
|
|
default: break; // sinon on ne fait rien
|
|
};
|
|
};
|
|
if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0
|
|
{lesMail->Init_Xi_t_et_tdt_de_0();}
|
|
else // sinon a minima on active X1
|
|
{ lesMail->Active_un_type_ddl_particulier(X1);
|
|
};
|
|
};
|
|
|
|
// cas du chargement, on verifie egalement la bonne adequation des references
|
|
charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD);
|
|
// on indique que l'on ne souhaite pas le temps fin stricte
|
|
// (sinon erreur non gérée après un changement de delta t), que l'on suppose négligeable
|
|
// après plusieurs incréments
|
|
// modif 21 juin 2017 : non on veut une gestion stricte (je ne sais pas pourquoi il y avait
|
|
// une telle gestion, sans doute une suite à un calcul explicite classique
|
|
charge->Change_temps_fin_non_stricte(0); //(1);
|
|
// dans le cas où l'on calcul des contraintes et/ou déformation et/ou un estimateur d'erreur
|
|
// à chaque incrément, initialisation
|
|
tenuXVG.Change_taille(3);tenuXVG(1)=X1;tenuXVG(2)=V1;tenuXVG(3)=GAMMA1;
|
|
prepa_avec_remont = Algori::InitRemont(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
|
|
if ( prepa_avec_remont)// remise enservice des ddl du pab
|
|
{lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);};
|
|
// dans le cas de l'algorithme de relaxation dynamique, le temps est normalement imposé à 1., donc n'intervient pas
|
|
// en fait dans l'algo d'avancement temporel !!
|
|
// Cependant comme le temps intervient également dans le chargement on le laisse à la valeur indiqué par l'utilisateur
|
|
this->Gestion_pas_de_temps(true,lesMail,1); // 1 signifie qu'il y a initialisation
|
|
|
|
// 00 --<ARD>-- on crée les ddl d'accélération et de vitesse non actif mais libres
|
|
// car les forces intérieures et extérieures sont les entitées duales
|
|
// des déplacements, qui sont donc les seules grandeurs actives à ce stade
|
|
lesMail->Plus_Les_ddl_Vitesse( HSLIBRE);
|
|
lesMail->Plus_Les_ddl_Acceleration( HSLIBRE);
|
|
// on défini globalement que l'on a une combinaison des ddl X V GAMMA en même temps
|
|
cas_combi_ddl=1;
|
|
// mise en place éventuelle du bulk viscosity
|
|
lesMail->Init_bulk_viscosity(pa.BulkViscosity(),pa.CoefsBulk());
|
|
// mise a zero de tous les ddl et creation des tableaux a t+dt
|
|
// les ddl de position ne sont pas mis a zero ! ils sont initialise
|
|
// a la position courante
|
|
lesMail->ZeroDdl(true);
|
|
// on vérifie que les noeuds sont bien attachés à un élément sinon on met un warning si niveau > 2
|
|
if (ParaGlob::NiveauImpression() > 2)
|
|
lesMail->AffichageNoeudNonReferencer();
|
|
// init des ddl avec les conditions initiales
|
|
// les conditions limites initiales de vitesse sont prise en compte
|
|
// de manière identiques à des ddl quelconques, ce ne sont pas des ddl fixé !!
|
|
// par contre l'accélération initiale est déterminée à l'aide de l'équilibre initiale
|
|
// donc les conditions d'accélérations initiale seront écrasées
|
|
lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl);
|
|
// mise à jour des différents pointeur d'assemblage et activation des ddl
|
|
// a) pour les déplacements qui sont à ce stade les seuls grandeurs actives
|
|
// on définit un nouveau cas d'assemblage pour les Xi
|
|
// à travers la définition d'une instance de la classe assemblage
|
|
if (Ass1_ == NULL) Ass1_ = new Assemblage(lesMail->InitNouveauCasAssemblage(1));
|
|
Assemblage& Ass1 = *Ass1_;
|
|
lesMail->MiseAJourPointeurAssemblage(Ass1.Nb_cas_assemb());// mise a jour des pointeurs d'assemblage
|
|
int nbddl_X = lesMail->NbTotalDdlActifs(X1); // nb total de ddl de déplacement
|
|
// qui est le même pour les accélérations et les vitesses
|
|
// b) maintenant le cas des vitesses qui doivent donc être activées
|
|
// on définit un nouveau cas d'assemblage pour les Vi
|
|
if (Ass2_ == NULL) Ass2_ = new Assemblage(lesMail->InitNouveauCasAssemblage(1));
|
|
Assemblage& Ass2 = *Ass2_;
|
|
lesMail->Inactive_un_type_ddl_particulier(X1); // on inactive les Xi
|
|
lesMail->Active_un_type_ddl_particulier(V1); // on active les Vi
|
|
lesMail->MiseAJourPointeurAssemblage(Ass2.Nb_cas_assemb()); // mise a jour des pointeurs d'assemblage
|
|
// c) idem pour les accélérations
|
|
// on définit le numéro de second membre en cours
|
|
// on définit un nouveau cas d'assemblage pour les pour GAMMAi
|
|
if (Ass3_ == NULL) Ass3_ = new Assemblage(lesMail->InitNouveauCasAssemblage(1));
|
|
Assemblage& Ass3 = *Ass3_;
|
|
lesMail->Inactive_un_type_ddl_particulier(V1); // on inactive les Vi
|
|
lesMail->Active_un_type_ddl_particulier(GAMMA1); // on active les GAMMAi
|
|
lesMail->MiseAJourPointeurAssemblage(Ass3.Nb_cas_assemb()); // mise a jour des pointeurs d'assemblage
|
|
// d) activation de tous les ddl, maintenant ils peuvent être les 3 actifs
|
|
lesMail->Active_un_type_ddl_particulier(X1);
|
|
lesMail->Active_un_type_ddl_particulier(V1);
|
|
// en fait ces trois pointeurs d'assemblage ne sont utils que pour la mise en place des conditions
|
|
// limites
|
|
// mise à jour du nombre de cas d'assemblage pour les conditions limites
|
|
// c-a-d le nombre maxi possible (intégrant les autres pb qui sont résolu en // éventuellement)
|
|
lesCondLim->InitNombreCasAssemblage(lesMail->Nb_total_en_cours_de_cas_Assemblage());
|
|
// définition d'un tableau globalisant les numéros d'assemblage de X V gamma
|
|
t_assemb.Change_taille(3);
|
|
t_assemb(1)=Ass1.Nb_cas_assemb();t_assemb(2)=Ass2.Nb_cas_assemb();t_assemb(3)=Ass3.Nb_cas_assemb();
|
|
// récupération des tableaux d'indices généraux des ddl bloqués, y compris les ddls associés
|
|
icas = 1; // pour indiquer au module Tableau_indice que l'on travaille avec l'association X V GAMMA
|
|
li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb,lesRef,charge->Temps_courant(),icas);
|
|
// on définit quatre tableaux qui serviront à stocker transitoirement les X V GAMMA correspondant au ddl imposés
|
|
int ttsi = li_gene_asso.size();
|
|
X_Bl.Change_taille(ttsi),V_Bl.Change_taille(ttsi),G_Bl.Change_taille(ttsi);
|
|
|
|
// def vecteurs globaux
|
|
vglobin.Change_taille(nbddl_X); // puissance interne : pour ddl accélération
|
|
vglobex.Change_taille(nbddl_X); // puissance externe
|
|
vglobaal.Change_taille(nbddl_X,0.); // puissance totale
|
|
// même si le contact n'est pas encore actif, il faut prévoir qu'il le deviendra peut-être !
|
|
if (lesMail->NbEsclave() != 0)
|
|
vcontact.Change_taille(nbddl_X); // puissance de contact
|
|
|
|
// 04 --<ARD>-- 6 vecteur pour une manipulation globale des positions vitesses et accélérations
|
|
// vecteur qui globalise toutes les positions de l'ensemble des noeuds
|
|
// dans le cas où on initialise les ddl_tdt(n) avec les ddl_t(n)+delta_ddl(n-1), def de grandeurs
|
|
X_t.Change_taille(nbddl_X);X_tdt.Change_taille(nbddl_X); delta_X.Change_taille(nbddl_X);
|
|
var_delta_X.Change_taille(nbddl_X);
|
|
// vecteur qui globalise toutes les vitesses de l'ensemble des noeuds
|
|
vitesse_t.Change_taille(nbddl_X);vitesse_tdt.Change_taille(nbddl_X);
|
|
// vecteur qui globalise toutes les accélérations
|
|
acceleration_t.Change_taille(nbddl_X);acceleration_tdt.Change_taille(nbddl_X) ;
|
|
|
|
// calcul des énergies
|
|
if (pa.Amort_visco_artificielle()) // dans le cas d'un amortissement artificiel
|
|
forces_vis_num.Change_taille(nbddl_X,0.);
|
|
E_cin_tdt = 0.; E_int_t = 0.; E_int_tdt = 0.; // init des différentes énergies
|
|
E_ext_t = 0.; E_ext_tdt = 0.; bilan_E = 0.; // " et du bilan
|
|
save_X_t.Change_taille(nbddl_X); // vecteur de sauvegarde
|
|
F_int_t.Change_taille(nbddl_X); F_ext_t.Change_taille(nbddl_X); // forces généralisées int et ext au pas précédent
|
|
F_int_tdt.Change_taille(nbddl_X); F_ext_tdt.Change_taille(nbddl_X); // forces généralisées int et ext au pas actuel
|
|
residu_final.Change_taille(nbddl_X); // pour la sauvegarde du résidu pour le post-traitement
|
|
|
|
// initialisation du compteur d'increments de charge
|
|
// au premier passage il y a un traitement spécial: pas d'incrémentation du temps, pas de sauvegarde
|
|
// in s'agit d'un incrément de mise en place, l'équilibre se faisant à la fin
|
|
// ici en relaxation dynamique on démarre à -1 car pour -1 et 0 on ne fait rien, on initialise (voir le calcul)
|
|
compteur_demarrage = -1; // pas vraiment utile, car sera redéfini dans CalEquilibre
|
|
icharge = 0; // par défaut
|
|
|
|
// definition des elements de frontiere, ces elements sont utilises pour le contact
|
|
lesMail->CreeElemFront();
|
|
// calcul éventuel des normales aux noeuds -> init des normales pour t=0
|
|
lesMail->InitNormaleAuxNoeuds(); //utilisé pour la stabilisation des membranes par ex
|
|
// --- init du contact ---
|
|
// doit-être avant la lecture d'un restart, car il y a une initialisation de conteneurs qui est faites
|
|
// qui ensuite est utilisée en restart
|
|
// par exemple il faut initialiser les frontières et la répartition esclave et maître
|
|
// pour préparer la lecture de restart éventuel
|
|
if (lesMail->NbEsclave() != 0)
|
|
{ // definition des elements de frontiere, ces elements sont utilises pour le contact
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t); //
|
|
// initialisation des zones de contacts éventuelles
|
|
lesContacts->Init_contact(*lesMail,*lesRef,lesFonctionsnD);
|
|
// verification qu'il n'y a pas de contact avant le premier increment de charge
|
|
lesContacts->Verification();
|
|
// definition des elements de contact eventuels
|
|
// et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
|
|
lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
|
|
if (pa.ContactType() == 4) // cas particulier du type 4 de contact où on utilise les forces internes
|
|
{// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
|
|
Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif pour un vecteur force à chaque noeud
|
|
TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
|
|
lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
|
|
};
|
|
};
|
|
|
|
//--cas de restart et/ou de sauvegarde------------
|
|
// tout d'abord récup du restart si nécessaire
|
|
// dans le cas ou un incrément différent de 0 est demandé -> seconde lecture à l'incrément
|
|
bool brestart=false; // booleen qui indique si l'on est en restart ou pas
|
|
if (this->Num_restart() != 0)
|
|
{ int cas = 2;
|
|
// ouverture de base info
|
|
entreePrinc->Ouverture_base_info("lecture");
|
|
this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,(this->Num_restart()));
|
|
icharge = this->Num_restart();//+1;
|
|
// récup du pas de temps, proposé par l'utilisateur, initialisation et vérif / pas critique
|
|
this->Gestion_pas_de_temps(true,lesMail,2); // 2 signifie cas courant
|
|
brestart = true;
|
|
// on oblige les ddls Vi GAMMAi a avoir le même statut que celui des Xi
|
|
// comme les conditions limites cinématiques peuvent être différentes en restart
|
|
// par rapport à celles sauvegardées, on commence par libérer toutes les CL imposées éventuelles
|
|
lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
|
|
lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
|
|
// dans le cas d'un calcul axisymétrique on bloque le ddl 3
|
|
if (ParaGlob::AxiSymetrie())
|
|
lesMail->Inactive_un_ddl_particulier(X3);
|
|
// on valide l'activité des conditions limites et condition linéaires, pour le temps initial
|
|
// en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
|
|
////--debug
|
|
//cout << "\n debug1: AlgoriRelaxDyna::InitAlgorithme(..";
|
|
//lesMail->Noeud_LesMaille(1,197).Affiche();cout << endl;
|
|
////--fin debug
|
|
li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb,lesRef,charge->Temps_courant(),icas);
|
|
int ttsi = li_gene_asso.size();
|
|
X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi);
|
|
|
|
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
// mise à jour pour le contact s'il y du contact présumé
|
|
if (pa.ContactType())
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
};
|
|
// vérif de cohérence pour le contact
|
|
if ((pa.ContactType()) && (lesMail->NbEsclave() == 0)) // là pb
|
|
{cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact "
|
|
<< " la definition d'un type contact possible est donc incoherente "
|
|
<< " revoir la mise en donnees !! "<< flush;
|
|
Sortie(1);
|
|
};
|
|
// on regarde s'il y a besoin de sauvegarde
|
|
if (this->Active_sauvegarde() && (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);
|
|
}
|
|
};
|
|
|
|
// ajout d'un conteneur pour les coordonnées à l'itération 0
|
|
{Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif à chaque noeud
|
|
TypeQuelconque typQ_gene_int(XI_ITER_0,X1,gt);
|
|
lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
|
|
};
|
|
|
|
// init pour var glob
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
//--fin cas de restart et/ou de sauvegarde--------
|
|
// on signale que l'on utilise un comportement matériel normal
|
|
lesLoisDeComp->Loi_simplifie(false);
|
|
|
|
// choix de la matrice de masse, qui est en fait celle qui correspond au ddl Xi
|
|
// ici le numéro d'assemblage est celui de X car on projette bien sur des vitesses virtuelles c-a-d ddl X*.
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (proc_en_cours == 0)
|
|
#endif
|
|
if (ParaGlob::NiveauImpression() > 2)
|
|
cout << "\n matrice masse principale: ";
|
|
mat_masse = Choix_matrice_masse(nbddl_X,mat_masse,lesMail,lesRef
|
|
,Ass1.Nb_cas_assemb(),lesContacts,lesCondLim);
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (proc_en_cours == 0)
|
|
#endif
|
|
if (ParaGlob::NiveauImpression() > 2)
|
|
cout << "\n matrice masse secondaire: ";
|
|
mat_masse_sauve = Choix_matrice_masse(nbddl_X,mat_masse_sauve,lesMail,lesRef
|
|
,Ass1.Nb_cas_assemb(),lesContacts,lesCondLim);
|
|
// choix de la résolution
|
|
if (mat_masse->Type_matrice() == DIAGONALE)
|
|
// dans le cas d'une matrice diagonale on force la résolution directe quelque soit l'entrée
|
|
mat_masse->Change_Choix_resolution(DIRECT_DIAGONAL,pa.Type_preconditionnement());
|
|
else
|
|
mat_masse->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
|
|
// initialisation par exemple au niveau des maillages (éléments) pour les calculs futurs de la matrice masse
|
|
InitCalculMatriceMasse(lesMail,*mat_masse,Ass1,*mat_masse_sauve,lesFonctionsnD);
|
|
(*mat_masse_sauve) = (*mat_masse); // sauvegarde avant la mise en place des conditions limites
|
|
|
|
if ((casMass_relax > 5) && (casMass_relax < 10)) // cas où on utilise la matrice de raideur réelle
|
|
{ // choix des matrices de raideur de sustitution éventuelles : par défaut matglob = tab_mato(1)
|
|
Tableau < Mat_abstraite*> tab_mato(1);
|
|
// choix de la matrice de raideur du système linéaire (calcul éventuellement d'une largeur de bande ad oc)
|
|
Choix_matriciel(nbddl_X,tab_mato,lesMail,lesRef,Ass1.Nb_cas_assemb(),lesCondLim);
|
|
matglob = tab_mato(1);
|
|
// choix de la résolution pour la première matrice
|
|
matglob->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
|
|
};
|
|
|
|
// on vérifie que le ddl statique a bien été définit
|
|
// on définit le Ddl_enum_etendu correspondant à la masse au noeud pour la méthode
|
|
if (type_calcul_mass == 1)
|
|
{if (masseRelax_1.Nom_vide() )
|
|
masseRelax_1 = (Ddl_enum_etendu(string("masse_relax_dyn")));
|
|
// introduction des conteneurs de masse particulier à la méthode, sert de manière générale
|
|
// également pour le post-traitement
|
|
{ List_io < Ddl_enum_etendu > lienu; // def uniquement pour le passage de param
|
|
lienu.push_back(masseRelax_1);
|
|
lesMail->AjoutConteneurAuNoeud(lienu);
|
|
};
|
|
}
|
|
else if (type_calcul_mass == 2)
|
|
{ if ( masseRelax_2.EnuTypeQuelconque().EnumTQ() == RIEN_TYPEQUELCONQUE )
|
|
{ int dim = ParaGlob::Dimension();
|
|
// def des grandeurs courantes de type coordonnee
|
|
Coordonnee coor(dim); // un type coordonnee typique
|
|
// maintenant on définit une grandeur typique de type Grandeur_coordonnee
|
|
Grandeur_coordonnee gt(coor);
|
|
// def d'un type quelconque représentatif pour un vecteur pseudomasse
|
|
TypeQuelconque typQ(MASSE_RELAX_DYN,X1,gt);
|
|
// on ajoute le conteneur au noeud
|
|
lesMail->AjoutConteneurAuNoeud(typQ);
|
|
// on met à jout le conteneur statique
|
|
masseRelax_2.ChangeGrandeur(typQ);
|
|
};
|
|
}
|
|
else
|
|
{ cout << "\n *** erreur :type_calcul_mass est different de 1 ou 2 ";
|
|
Sortie(1);
|
|
};
|
|
|
|
// dans le cas où l'on utilise de l'amortissement numérique visqueux classique
|
|
// en fait ici cela correspond à : forces_vis_num = c [M] V(n)
|
|
// pour le second membre il est également nécessaire de tenir compte du terme -[C] V(n)
|
|
// il nous faut donc la matrice de viscosité
|
|
// forces_vis_num: forces visqueuses d'origines numériques
|
|
if ((typeCalRelaxation == 2) || pa.Amort_visco_artificielle() || (typeCalRelaxation == 3)
|
|
|| (typeCalRelaxation == 4))
|
|
{ bool initial = true; // def de la matrice (place et valeurs)
|
|
mat_C_pt = Cal_mat_visqueux_num_expli(*mat_masse,mat_C_pt,delta_X,initial,vitesse_tdt);
|
|
forces_vis_num.Change_taille(nbddl_X);
|
|
if (Arret_A_Equilibre_Statique()) // si on veut un équilibre statique, on sauvegarde les forces statiques
|
|
{ if (vglob_stat != NULL)
|
|
{vglob_stat->Change_taille(vglobaal.Taille());}
|
|
else
|
|
{vglob_stat = new Vecteur(vglobaal.Taille());}
|
|
};
|
|
};
|
|
|
|
// mise en place des conditions limites
|
|
// ---- initialisation des sauvegardes sur matrice et second membre
|
|
// ce qui ne correspond à rien ici normalement
|
|
lesCondLim->InitSauve(Ass3.Nb_cas_assemb());
|
|
//
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,*mat_masse,vglobaal,Ass3.Nb_cas_assemb()
|
|
,cas_combi_ddl,vglob_stat);
|
|
// puis on prépare (si besoin est en fonction du type de matrice) la résolution
|
|
if (!(lesCondLim->ExisteCondiLimite()))
|
|
mat_masse->Preparation_resol();
|
|
type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
|
|
|
|
// on indique (si ça n'a pas été déjà fait) que l'on va utiliser la relaxation cinétique
|
|
if (typeCalRelaxation != 2)
|
|
{amortissement_cinetique=true; // paramètre définit dans Algori
|
|
Algori::InitialiseAmortissementCinetique(); // initialisation des compteurs pour l'amortissement
|
|
}
|
|
else {amortissement_cinetique=false; };
|
|
// dans le cas où les fonctions niveauF_grandeurGlobale ou/et niveauF_temps sont non nulles
|
|
// idem pour niveauLambda_grandeurGlobale ou/et niveauLambda_temps
|
|
// on finit l'affectation
|
|
if (niveauLambda_temps != NULL)
|
|
niveauLambda_temps->Affectation_fonctions(*lesCourbes1D);
|
|
if (niveauLambda_grandeurGlobale != NULL)
|
|
{niveauLambda_grandeurGlobale->Affectation_fonctions(*lesFonctionsnD);
|
|
// on vérifie que c'est bien une fonction scalaire
|
|
int nbcomp = niveauLambda_grandeurGlobale->C_proport()->NbComposante();
|
|
if (nbcomp != 1)
|
|
{cout << "\n erreur avec la fct " << niveauLambda_grandeurGlobale->Nom_fonction()
|
|
<< "definissant l'evolution de lambda, ce n'est pas une fct scalaire"
|
|
<< " elle retourne "<<nbcomp << "composantes ! verifier la mise en donnees ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
if (niveauF_temps != NULL)
|
|
niveauF_temps->Affectation_fonctions(*lesCourbes1D);
|
|
if (niveauF_grandeurGlobale != NULL)
|
|
{niveauF_grandeurGlobale->Affectation_fonctions(*lesFonctionsnD);
|
|
// on vérifie que c'est bien une fonction scalaire
|
|
int nbcomp = niveauF_grandeurGlobale->C_proport()->NbComposante();
|
|
if (nbcomp != 1)
|
|
{cout << "\n erreur avec la fct " << niveauF_grandeurGlobale->Nom_fonction()
|
|
<< "definissant la bascule cinetique-visqueux, ce n'est pas une fct scalaire"
|
|
<< " elle retourne "<<nbcomp << "composantes ! verifier la mise en donnees ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
// mise à jour variable globale: ici en initialisation
|
|
switch (typeCalRelaxation)
|
|
{ case 1: visqueux_activer = false; break;
|
|
case 2: visqueux_activer = true; break;
|
|
case 4: visqueux_activer = false; break; // au début en cinétique
|
|
default:
|
|
cout <<"\n typeCalRelaxation = " << typeCalRelaxation
|
|
<< " cas non pris en compte dans AlgoriRelaxDyna::Lecture_Base_info_Parametre( ";
|
|
Sortie(1);
|
|
break;
|
|
};
|
|
Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
// ---- on renseigne les pointeurs de fonctions nD éventuels
|
|
// on récupère éventuellement les fonctions qui correspondent à fct_nD_option_recalcul_mass
|
|
int nb_opt_cal_masse = nom_fct_nD_option_recalcul_mass.Taille();
|
|
for (int i=1;i<= nb_opt_cal_masse;i++)
|
|
{if (nom_fct_nD_option_recalcul_mass(i).length())
|
|
{fct_nD_option_recalcul_mass(i) = lesFonctionsnD->Trouve(nom_fct_nD_option_recalcul_mass(i));
|
|
if (fct_nD_option_recalcul_mass(i)->Nom_variables().Taille() == 0) // cas où il n'y a que des variables globales
|
|
{// on vérifie qu'en retour on a un scalaire
|
|
fct_nD_option_recalcul_mass(i)->Valeur_pour_variables_globales(); // pour simplifier
|
|
if (fct_nD_option_recalcul_mass(i)->NbComposante() != 1)
|
|
{cout << "\n *** erreur parametre algorithme: la fonction nD "
|
|
<< nom_fct_nD_option_recalcul_mass(i)
|
|
<< " qui permet de calculer la valeur du parametre recalcul_mass("<<i<<") "
|
|
<< " ne retourne pas un scalaire unique !! a priori ce n'est pas correct ";
|
|
Sortie(1);
|
|
};
|
|
}
|
|
else
|
|
{cout << "\n *** erreur parametre algorithme: la fonction nD "
|
|
<< nom_fct_nD_option_recalcul_mass(i)
|
|
<< " qui permet de calculer la valeur du parametre recalcul_mass("<<i<<") "
|
|
<< " utilise des variables autres que globales, ce n'est pas possible ! ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
};
|
|
|
|
// mise à jour au cas où
|
|
Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats);
|
|
|
|
tempsInitialisation.Arret_du_comptage(); // temps cpu
|
|
};
|
|
|
|
// mise à jour
|
|
void AlgoriRelaxDyna::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(RELAX_DYNA); // transfert info
|
|
|
|
// activation des ddl
|
|
lesMail->Inactive_ddl(); // on commence par inactiver tous les ddl
|
|
lesMail->Active_un_type_ddl_particulier(X1); // puis on active les ddl qu'ils faut ici
|
|
lesMail->Active_un_type_ddl_particulier(V1); // on active les Vi
|
|
lesMail->Active_un_type_ddl_particulier(GAMMA1); // on active les GAMMAi
|
|
|
|
// ici en relaxation dynamique on démarre à -1 car pour -1 et 0 on ne fait rien, on initialise (voir le calcul)
|
|
compteur_demarrage = -1; // mais en fait pas vraiment utile, car sera redéfini dans CalEquilibre
|
|
|
|
// mise à jour au cas où
|
|
Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,diversStockage,charge,lesCondLim,lesContacts,resultats);
|
|
// init indicateur
|
|
Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
tempsMiseAjourAlgo.Arret_du_comptage(); // temps cpu
|
|
};
|
|
|
|
// calcul
|
|
// si tb_combiner est non null -> un tableau de 2 fonctions
|
|
// - la première fct dit si on doit valider ou non le calcul à convergence ok,
|
|
// - la seconde dit si on doit sortir de la boucle ou non à convergence ok
|
|
//
|
|
// 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 AlgoriRelaxDyna::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* > * tb_combiner)
|
|
{
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(RELAX_DYNA); // transfert info
|
|
// on vérifie que le pas de temps est correcte: on propose le deltat actuel qui sera modifié s'il n'est pas bon
|
|
double deltat_actuel = pa.Deltat();
|
|
pa.Modif_Detat_dans_borne(deltat_actuel);
|
|
#ifdef UTILISATION_MPI
|
|
int proc_en_cours = ParaGlob::Monde()->rank();
|
|
#endif
|
|
|
|
// récup des entités
|
|
Assemblage& Ass1 = *Ass1_;
|
|
// Assemblage& Ass2 = *Ass2_;
|
|
Assemblage& Ass3 = *Ass3_;
|
|
|
|
// préparation pour les aspects validation du calcul et sortie contrôlée des incréments
|
|
int validation_calcul = 1; // init : par défaut la validation est effective si le calcul converge
|
|
int sortie_boucle_controler_par_fctnD = 0; // init : par défaut la sortie n'est pas contrôler
|
|
|
|
// boucle sur les increments de charge qui gère également les incréments de temps
|
|
// tant que la fin du chargement n'est pas atteinte
|
|
// dans le cas du premier chargement on calcul de toute manière, ce qui permet
|
|
// de calculer meme si l'utilisateur indique un increment de charge supérieur
|
|
// au temps final
|
|
|
|
// init de la valeur de lambda
|
|
lambda = Calcul_Lambda();
|
|
|
|
// on impose une accélération nulle compte tenu du fait qu'elle est ici purement numérique
|
|
acceleration_tdt.Zero();
|
|
vitesse_tdt.Zero(); // idem vitesses (pourrait poser des pb si l'on veut utiliser des vrais vitesses aux noeuds ?)
|
|
|
|
// ********* à améliorer
|
|
// un vecteur de travail qui devra être mieux dimensionné par la suite
|
|
Vecteur V_ext(F_int_tdt);
|
|
|
|
double max_delta_X=0.; // le maxi du delta X
|
|
double max_var_delta_X=0.; // idem d'une itération à l'autre
|
|
|
|
// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
|
|
int dim = ParaGlob::Dimension();if (ParaGlob::AxiSymetrie()) dim--;
|
|
Coordonnee coor(dim); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif pour un vecteur force à chaque noeud
|
|
TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
|
|
|
|
// on définit un type générique qui sert pour passer aux noeuds les positions à l'itération 0
|
|
TypeQuelconque typQ_XI_ITER_0(XI_ITER_0,X1,gt);
|
|
|
|
bool arret=false; // booleen pour arrêter indépendamment de la charge
|
|
bool arret_pilotage=false; // pour arrêt du calcul au niveau du pilotage
|
|
bool premier_calcul = true; // utilisé pour l'initialisation de l'incrément avec le pas précédent
|
|
int indicCycleContact = 0; // def d'un indicateur donnant la situation dans le cycle de contact
|
|
// un booléen pour uniquement gérer le fait que dans la boucle globale on fait le test après le test du while
|
|
// d'où pour le temps final, on peut sortir de la boucle globale sans avoir convergé, ce qui n'est pas bon
|
|
bool pas_de_convergence_pour_l_instant=1;
|
|
// ici en relaxation dynamique on démarre à -1 car pour -1 et 0 on ne fait rien, on initialise (voir le calcul)
|
|
compteur_demarrage=-1; // donc compteur pour les premiers incréments
|
|
icharge++; // on incrémente le chargement -> donne le num d'incr du prochain incr chargé
|
|
while ( ((!charge->Fin(icharge,((!pas_de_convergence_pour_l_instant)&&(compteur_demarrage < 1)))) // on n'affiche la sin
|
|
// que si on a eu convergence
|
|
|| pas_de_convergence_pour_l_instant ||(compteur_demarrage <= 1)
|
|
)
|
|
&& (charge->Fin(icharge,true)!=1) // si on a dépassé le temps fin on s'arrête
|
|
// si on a dépassé le nombre d'incrément permis on s'arrête dans tous les cas
|
|
&& ((compteur_demarrage < 1)? (charge->Fin(icharge,false)!=2) : (charge->Fin(icharge,true)!=2))
|
|
&& (charge->Fin(icharge,true)!=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())
|
|
)
|
|
{ double maxPuissExt; // maxi de la puissance des efforts externes
|
|
double maxPuissInt; // maxi de la puissance des efforts internes
|
|
double maxReaction; // maxi des reactions
|
|
int inReaction = 0; // pointeur d'assemblage pour le maxi de reaction
|
|
Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
|
|
lesLoisDeComp->MiseAJour_umat_nbincr(icharge); // init pour les lois Umat éventuelles
|
|
|
|
// --- en fait on doit faire 2 passages pour initialiser l'algo:
|
|
// * premier passage calcul de l'accélération à t=0
|
|
// --> on utilise un deltat = 0 et t = 0,
|
|
// * second passage --> on met un bon pas de temps, mais toujours pas
|
|
// d'accroissement du chargement ni de calcul de la relaxation dynamique
|
|
// (car il n'y a pas de référence), par contre on va
|
|
// calculer toutes les infos : accelération et vitesse à t = 0,
|
|
// * c'est seulement à partir de compteur_demarrage > 0 que
|
|
// l'on commence à calculer pour un t non nul et donc un accroissement
|
|
// du chargement non nul (mais il pouvait y avoir précédemment un chargement à t=0)
|
|
|
|
// bilan: on traite différamment selon que c'est le premier passage le second et les autres
|
|
bool aff_incr = true; // par défaut, est ensuite renseigné dans le switch qui suit
|
|
bool change_statut = false; // init des changements de statut
|
|
|
|
// mise à jour du calcul éventuel des normales aux noeuds -> mise à jour des normales à t
|
|
// mais ici, on calcule les normales à tdt, et on transfert à t
|
|
// comme on est au début de l'incrément, la géométrie à tdt est identique à celle à t
|
|
// sauf "au premier incrément", si l'algo est un sous algo d'un algo combiné
|
|
// et que l'on suit un précédent algo sur un même pas de temps
|
|
// qui a aboutit à une géométrie à tdt différente de celle de t
|
|
// du coup cela permet d'utiliser la nouvelle géométrie pour ce premier incrément
|
|
lesMail->MiseAjourNormaleAuxNoeuds_de_tdt_vers_T();
|
|
// passage aux noeuds des vecteurs globaux: F_INT, F_EXT
|
|
Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(lesMail);
|
|
|
|
// qui, pour provoquer un arrêt de la boucle sur les incrément
|
|
switch (compteur_demarrage)
|
|
{case -1:
|
|
{// gestion du pas de temps, mis transitoirement à 0
|
|
this->Gestion_pas_de_temps(false,lesMail,0); // 0 signifie cas du passage à vide
|
|
break;
|
|
}
|
|
case 0:
|
|
{// on remet les choses dans l'ordre et on continue sur le cas courant
|
|
// mais c'est toujours une passe d'initialisation
|
|
this->Gestion_pas_de_temps(false,lesMail,1); // 1 signifie premier pas
|
|
break;
|
|
}
|
|
default: // cas normal ou compteur_demarrage > 0
|
|
{// gestion du pas de temps
|
|
this->Gestion_pas_de_temps(false,lesMail,2); // 2 signifie cas courant
|
|
if (!indicCycleContact) // modification de la charge et du pas de temps qu'au premier passage
|
|
// mais pas après un changement de statut
|
|
{ bool modif_temps = Pilotage_du_temps(charge,arret_pilotage); // appel du Pilotage
|
|
//-- si le temps a changé il faut de nouveau appeler la gestion du pas de temps
|
|
// car il y a des grandeurs reliées au pas de temps qui y sont calculé
|
|
if (modif_temps)
|
|
this->Gestion_pas_de_temps(true,lesMail,2); // 2 signifie cas courant
|
|
if (arret_pilotage) break; // pilotage -> arret du calcul, on sort du switch
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// affichage de l'increment de charge
|
|
aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
|
|
if (aff_incr)
|
|
{ cout << "\n======================================================================"
|
|
<< "\nINCREMENT DE CHARGE : " << icharge
|
|
<< " intensite " << charge->IntensiteCharge()
|
|
<< " t= " << charge->Temps_courant()
|
|
<< " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
|
|
<< "\n======================================================================";
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
}
|
|
else {aff_incr = false;};
|
|
#endif
|
|
// -- initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
|
|
// dans le cas ou il y a changement de statut il faut remettre à jour
|
|
// le dimensionnement de variables intermédiaires
|
|
if (change_statut)
|
|
{ li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb
|
|
,lesRef,charge->Temps_courant(),icas);
|
|
int ttsi = li_gene_asso.size();
|
|
X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi);
|
|
// ---- initialisation des sauvegardes sur matrice et second membre
|
|
// ce qui ne correspond à rien ici normalement
|
|
lesCondLim->InitSauve(Ass3.Nb_cas_assemb());
|
|
};
|
|
|
|
// --- calcul des éléments de contact: (correspond à la définition de la surface de contact)
|
|
// dans le cas où type_activation_contact ne s'effectue pas à chaque itération
|
|
if (type_activation_contact != 1)
|
|
{ // definition ou mise à jour, des elements de contact eventuels
|
|
// - imposition (en fonction de l'algorithme de contact) de conditions particulières de penetration (nulle par exemple)
|
|
if (pa.ContactType()) // traitement différent lors du premier incément calculé (premier passage) puis des passages courants
|
|
{ if (premier_calcul)
|
|
{ // ici delta_X est nulle au premier passage ... on laisse quand même par cohérence avec les autres algo
|
|
lesContacts->DefElemCont(delta_X.Max_val_abs());
|
|
} // au début il n'y a pas de déplacement à priori
|
|
else
|
|
{ lesContacts->SuppressionDefinitiveElemInactif(); // on supprime les éléments inactifs testés à l'incr prec dans Actualisation()
|
|
// lesContacts->Nouveau(lesMail->Max_var_dep_t_a_tdt()); // on rajoute éventuellement de nouveau élément de contact
|
|
lesContacts->Nouveau(delta_X.Max_val_abs()); // idem mais je pense plus rapide
|
|
};
|
|
};
|
|
};
|
|
}
|
|
else
|
|
{ if (arret_pilotage) break; // pilotage -> arret du calcul
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (proc_en_cours == 0)
|
|
#endif
|
|
cout << "\n============================================================================="
|
|
<< "\n ....... re-analyse du contact ........ "
|
|
<< "\nINCREMENT DE CHARGE : " << icharge << " intensite " << charge->IntensiteCharge()
|
|
<< " t= " << charge->Temps_courant()
|
|
<< " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
|
|
<< "\n============================================================================";
|
|
};
|
|
};
|
|
}; // fin du switch sur compteur_demarrage
|
|
#ifdef UTILISATION_MPI
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
broadcast(*ParaGlob::Monde(), arret_pilotage, 0);
|
|
temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
#endif
|
|
|
|
if (arret_pilotage) break; // si dans le switch précédent on a un arret de pilotage qui est demandé
|
|
|
|
lesLoisDeComp->MiseAJour_umat_nbincr(icharge); // init pour les lois Umat éventuelles
|
|
// mise à jour éventuelle de la matrice de raideur en fonction de l'existence du contact et du type de modèle de contact
|
|
// if (pa.ContactType())
|
|
// Mise_a_jour_Choix_matriciel_contact(mato,Ass.Nb_cas_assemb(),lesContacts);
|
|
|
|
// --- récupération (initialisation) des ddl position, vitesse et accélération
|
|
// récupe X_t initiale
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
|
|
save_X_t=X_t; // sauvegarde
|
|
|
|
// dans le cas particulier d'une succesion de sous-algo, avec non validation du précédent algo
|
|
// on utilise pour démarrer la situation finale précédemment calculée
|
|
if ((tb_combiner != NULL) && ((*tb_combiner)(3) != NULL))
|
|
{// on initialise les valeurs globales à t, par contre on ne change pas les grandeurs locales à t !!
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
X_t = X_tdt;
|
|
// on récupère la situation
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1);
|
|
vitesse_t = vitesse_tdt;
|
|
acceleration_t = acceleration_tdt;
|
|
};
|
|
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,V1,vitesse_t,V1);
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,GAMMA1,acceleration_t,GAMMA1);
|
|
|
|
// on commence ici la boucle avec relaxation
|
|
int relax_vit_acce = 0; // variable de retour de la relaxation cinétique
|
|
// qui indique s'il y a relaxation ou pas, sert éventuellement pour le calcul de la masse
|
|
if (amortissement_cinetique)
|
|
{Algori::InitialiseAmortissementCinetique(); // initialisation des compteurs pour l'amortissement au cas ou
|
|
list_iter_relax.clear();
|
|
};
|
|
|
|
// on met à jour l'indicateur visqueux_activer
|
|
switch (typeCalRelaxation)
|
|
{ case 1: visqueux_activer = false; break;
|
|
case 2: visqueux_activer = true; break;
|
|
case 4: visqueux_activer = false; break; // au début en cinétique
|
|
default: break; // on ne doit pas arriver ici !! et a déjà été testé à la lecture
|
|
};
|
|
|
|
// force_recalcul_masse : un indicateur de retour pour la méthode Cinetique_ou_visqueux:
|
|
bool force_recalcul_masse= false; // par défaut on ne force pas
|
|
|
|
// on démarre avec le compteur à 0 et on sauvegarde la position finale à l'itération 0
|
|
lesMail->Quelconque_glob_vers_local(X1,X_tdt,typQ_XI_ITER_0);
|
|
// boucle de convergence sur un increment
|
|
Vecteur * sol; // pointeur du vecteur solution
|
|
|
|
for (compteur = 0; (compteur<= pa.Iterations())&&(!pa.EtatSortieEquilibreGlobal()); compteur++)
|
|
//---//\\//\\// début de la boucle sur les itérations d'équilibres //\\//\\//
|
|
{
|
|
// calcul de l'increment
|
|
// initialisation des deux partie du second membre
|
|
vglobin.Zero();
|
|
vglobex.Zero();
|
|
if (pa.ContactType())
|
|
vcontact.Zero();
|
|
vglobaal.Zero(); // puissance totale
|
|
// init pour var glob
|
|
Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(compteur);
|
|
|
|
// prise en compte du cas particulier ou l'utilisateur demande
|
|
// une mise à jour des conditions limites à chaque itération
|
|
if (cL_a_chaque_iteration)
|
|
{// -- initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// dans le cas ou il y a changement de statut il faut remettre à jour
|
|
// le dimensionnement de variables intermédiaires
|
|
if (change_statut)
|
|
{ li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb
|
|
,lesRef,charge->Temps_courant(),icas);
|
|
int ttsi = li_gene_asso.size();
|
|
X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi);
|
|
// ---- initialisation des sauvegardes sur matrice et second membre
|
|
// ce qui ne correspond à rien ici normalement
|
|
lesCondLim->InitSauve(Ass3.Nb_cas_assemb());
|
|
};
|
|
// on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
save_X_t=X_t; // sauvegarde
|
|
};
|
|
|
|
|
|
// passage aux noeuds des vecteurs globaux: F_INT, F_EXT
|
|
Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(lesMail);
|
|
// renseigne les variables définies par l'utilisateur via les valeurs déjà calculées par Herezh
|
|
Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(lesMail,varExpor,Ass1.Nb_cas_assemb(),*lesRef);
|
|
varExpor->RenseigneVarUtilisateur(*lesMail,*lesRef);
|
|
lesMail->CalStatistique(); // calcul éventuel de statistiques
|
|
// on met à jour la valeur de lambda
|
|
lambda = Calcul_Lambda();
|
|
lesMail->Force_Ddl_aux_noeuds_a_une_valeur(R_X1,0.0,TEMPS_tdt,true); // mise à 0 des ddl de réactions, qui sont uniquement des sorties
|
|
lesMail->Force_Ddl_etendu_aux_noeuds_a_zero(Ddl_enum_etendu::Tab_FN_FT()); // idem pour les composantes normales et tangentielles
|
|
// affichage ou non de l'itération
|
|
bool aff_iteration = (pa.freq_affich_iter() > 0) ?
|
|
(aff_incr && (compteur % pa.freq_affich_iter()==0) &&(compteur!=0)) : false ;
|
|
// (aff_incr && (compteur % pa.freq_affich_iter()==0) ) : false ;
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (proc_en_cours != 0) aff_iteration=false;
|
|
#endif
|
|
|
|
/* // --- imposition des ddls bloqués
|
|
// initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement et des conditions linéaires imposées
|
|
// bool change_statut = false; // init des changements de statut
|
|
// lesCondLim->MiseAJour_tdt
|
|
// (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
// ,lesCourbes1D,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// mise en place des conditions linéaires
|
|
// on ne met pas en place les conditions linéaires ici, car en fait on veut avoir la répercution du précédent calcul
|
|
// or, due au fait que ce sont des conditions linéaires, elles interviennent sur plusieurs ddl en même temps
|
|
// dans le repère globale. Mais quand on met les CL linéaires, on bloque une direction dans le nouveau repère !!
|
|
// or le couplage X V gamma n'est valide que dans le repère global !! donc on appplique les CL linéaires après ce couplage
|
|
// ***** pour l'instant, ce fonctionnement est ok pour les CL en gamma, il faudra regarder comment cela ce passe
|
|
// ***** dans le cas de CL linéaire en V et X */
|
|
// récupération au niveau global des ddl locaux à tdt avec conditions limite
|
|
// on ne s'occupe pas du vecteur accélération qui lui va être calculé !, car il dépend de
|
|
// l'équilibre dynamique (ici pseudo-dynamique)
|
|
// pour le vecteur accélération, seules les ddl avec CL sont différents de la précédente
|
|
// récupération
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
// lesMail->Vect_loc_vers_glob(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1);
|
|
|
|
// maintenant on met les conditions limites sur les ddls bloqués secondaires c-a-d associés
|
|
// aux ddl bloqués par l'utilisateur, leur calcul dépend de l'algorithme d'où un calcul global
|
|
list <LesCondLim::Gene_asso>::iterator ie,iefin=li_gene_asso.end(); // def d'un iterator adoc
|
|
int ih=1; // indice
|
|
for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++)
|
|
// comme les valeurs des X V Gamma vont être écrasé par le calcul global, on utilise
|
|
// des conteneurs intermédiaires
|
|
{//trois cas
|
|
LesCondLim::Gene_asso & s = (*ie); // pour simplifier
|
|
int ix=s.pointe(1); // début des Xi
|
|
int iv=s.pointe(2); // début des Vi
|
|
int ig=s.pointe(3); // début des gammai
|
|
// on utilise le schéma des différences finis, mais avec un pas de temps = 1.
|
|
// centrés pour calculer les valeurs des ddl dans le cas de ddl bloqué
|
|
switch (PremierDdlFamille(s.ty_prin))
|
|
{ case X1: // cas ou les Xi sont imposés, calcul approché des V_tdt
|
|
{ X_Bl(ih) = X_tdt(ix); // on récupère la nouvelle position
|
|
// pour les vitesses en fait il faudrait la valeur à t+2*deltat, donc on fait l'approximation t+1/2 deltat
|
|
V_Bl(ih) = (X_tdt(ix)-X_t(ix));
|
|
// pour l'accélération, a priori elle n'intervient pas dans le calcul d'équilibre, on la met donc
|
|
G_Bl(ih) = acceleration_t(ig); // identique à celle à t
|
|
break;
|
|
}
|
|
case V1: // cas où les Vi sont imposées, calcul directe des Xi_tdt et Gammai_tdt
|
|
{ V_Bl(ih) = vitesse_tdt(iv);
|
|
G_Bl(ih) = (vitesse_tdt(iv)-vitesse_t(iv))*2. - acceleration_t(ig);
|
|
X_Bl(ih) = X_t(ix) + vitesse_t(iv) + 0.5 * acceleration_t(ig);
|
|
break;
|
|
}
|
|
case GAMMA1: // cas où les gammai sont imposées, calcul directe des Xi_tdt et Vi_tdt
|
|
{ G_Bl(ih) = acceleration_tdt(ig);
|
|
X_Bl(ih) = X_t(ix) + vitesse_t(iv) + 0.5 * acceleration_t(ig);
|
|
V_Bl(ih) = vitesse_t(iv)+0.5*(acceleration_tdt(ig)+acceleration_t(ig));
|
|
break;
|
|
}
|
|
default:
|
|
cout << "\n ERREUR bizarre de resolution :PremierDdlFamille(s.ty_prin)= " << Nom_ddl(PremierDdlFamille(s.ty_prin))
|
|
<< "\n AlgoriRelaxDyna::CalEquilibre(...) ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
// ---- calcul des champs de vitesse et de position
|
|
// position calculée de manière exacte par rapport au schéma
|
|
X_tdt = X_t + vitesse_t + 0.5 * acceleration_t;
|
|
// pour la vitesse, il s'agit d'une prédiction explicite, qui sera affinée après résolution
|
|
vitesse_tdt = vitesse_t + acceleration_t;
|
|
|
|
// pilotage éventuelle des positions et vitesses
|
|
Pilotage_maxi_X_V(X_t,X_tdt,vitesse_t,vitesse_tdt);
|
|
|
|
// -- maintenant on met réellement en place les CL a partir de la sauvegarde
|
|
for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++)
|
|
{LesCondLim::Gene_asso & s = (*ie); // pour simplifier
|
|
int ix=s.pointe(1); // début des Xi
|
|
int iv=s.pointe(2); // début des Vi
|
|
int ig=s.pointe(3); // début des gammai
|
|
X_tdt(ix) = X_Bl(ih);
|
|
vitesse_tdt(iv) = V_Bl(ih);
|
|
acceleration_tdt(ig) = G_Bl(ih);
|
|
};
|
|
|
|
// ---- passage des valeurs calculées aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_tdt,X1);
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
// accélération à t : seules celles correspondantes au CL ont variées
|
|
// lesMail->Vect_glob_vers_local(TEMPS_t,GAMMA1,acceleration_t,GAMMA1);
|
|
|
|
lesLoisDeComp->MiseAJour_umat_nbiter(compteur); // init pour les lois Umat éventuelles
|
|
//debug ------
|
|
// #ifdef UTILISATION_MPI
|
|
// if (proc_en_cours == 0) // cas d'un calcul //, seule la matrice du CPU 0 est concernée
|
|
// #endif
|
|
// { cout << "\n ***1 AlgoriRelaxDyna::CalEquilibre( ";
|
|
// cout << "\n X_tdt= "; X_tdt.Affiche();
|
|
//// lesMail->Noeud_LesMaille(1,483).Affiche();
|
|
// cout << endl ;
|
|
// };
|
|
//fin debug ------
|
|
// mise en place des conditions linéaires
|
|
lesCondLim->MiseAJour_condilineaire_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// il n'y a pas de changement de largeur de bande pour les conditions linéaires, car on a mis la largeur maxi
|
|
// au moment de la création de la matrice masse
|
|
|
|
// recherche de nouveaux contacts si c'est demandé
|
|
if ((type_activation_contact == 1)&&(compteur_demarrage > 0))
|
|
{ if (pa.ContactType()) // réexamen du contact pour voir
|
|
// il faut mettre le contact ici, car il utilise le déplacement de t à tdt
|
|
{ lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_tdt); //s'il n'y a pas
|
|
if (premier_calcul)
|
|
{ lesContacts->DefElemCont(delta_X.Max_val_abs());
|
|
premier_calcul=false;} // au début il n'y a pas de déplacement à priori, on prend 2. * le delta noeud mini
|
|
else
|
|
{ lesContacts->SuppressionDefinitiveElemInactif(); // on supprime les éléments inactifs testés à l'incr prec dans Actualisation()
|
|
lesContacts->Nouveau(delta_X.Max_val_abs()); // idem mais je pense plus rapide
|
|
};
|
|
};
|
|
};
|
|
|
|
// -+-+ si la recherche de nouveaux contact n'est pas effectuée à chaque itération
|
|
// actualisation des conditions de contact qui peuvent changer la largeur de bande,
|
|
// quand un noeud glisse d'une facette sur une voisine, peut changer la position du noeud
|
|
// qui est projeté sur la facette dans le cas de l'algorithme cinématique
|
|
if (((compteur != 0)&&(pa.ContactType()))&&(compteur_demarrage > 0))
|
|
{ lesContacts->Actualisation(0); // en particulier: pour le type 4 on a projection
|
|
// des noeuds sur les facettes maîtres
|
|
// mise à jour éventuelle des répercussions du contact sur les noeuds en contact
|
|
AlgoriRelaxDyna::Repercussion_algo_sur_cinematique(lesContacts,X_tdt,vitesse_tdt);
|
|
// lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// lesMail->Vect_loc_vers_glob(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
// mise à jour éventuelle de la matrice de raideur en fonction du contact
|
|
// Mise_a_jour_Choix_matriciel_contact(mato,Ass.Nb_cas_assemb(),lesContacts);
|
|
};
|
|
// -+-+ sinon l'actualisation du contact s'effectue à la fin de l'itération (un peu plus loin)
|
|
|
|
// ---- calcul des puissances internes et externe
|
|
|
|
// appel du calcul de la puissance interne et des énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
if (!SecondMembreEnerg(lesMail,Ass1,vglobin)) break;
|
|
// calcul des maxi des puissances internes
|
|
maxPuissInt = vglobin.Max_val_abs();
|
|
F_int_tdt_prec = F_int_tdt; // sauvegarde des valeurs de l'itération précédente
|
|
F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures
|
|
if (pa.ContactType()==4) // dans le cas d'un contact de type 4
|
|
// on transfert les forces internes aux noeuds
|
|
lesMail->Quelconque_glob_vers_local(X1,F_int_tdt,typQ_gene_int);
|
|
|
|
// mise en place du chargement impose, c-a-d calcul de la puissance externe
|
|
// si pb on sort de la boucle
|
|
//// debug
|
|
//cout << "\n debug algo relax "
|
|
// << " barriere avant chargement , proc= "<< ParaGlob::Monde()->rank()
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
//// fin debug
|
|
// ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
|
|
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
|
|
(Ass1,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
|
|
{ Change_PhaseDeConvergence(-10);break;};
|
|
//// debug
|
|
//cout << "\n debug algo relax "
|
|
// << " après chargement , proc= "<< ParaGlob::Monde()->rank()
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
//// fin debug
|
|
|
|
//// autre essai !!
|
|
//if (pa.ContactType()==4) // dans le cas d'un contact de type 4
|
|
//{V_ext = F_int_tdt; V_ext += F_ext_tdt;
|
|
// lesMail->Quelconque_glob_vers_local(X1,V_ext,typQ_gene_int);
|
|
//};
|
|
|
|
// calcul des reactions de contact éventuelles (contact et frottement)
|
|
if ((pa.ContactType())&&(compteur_demarrage > 0)) // et des énergies développées pendant le contact
|
|
{// dans le cas où le calcul est inexploitable (pb dans le calcul) arrêt de la boucle
|
|
if (!SecondMembreEnergContact(lesContacts,Ass1,vcontact,aff_iteration)) break;
|
|
};
|
|
|
|
F_ext_tdt_prec = F_ext_tdt; // sauvegarde des valeurs de l'itération précédente
|
|
|
|
if (pa.ContactType())
|
|
vglobex += vcontact;
|
|
maxPuissExt = vglobex.Max_val_abs();
|
|
F_ext_tdt = vglobex; // sauvegarde des forces généralisées extérieures
|
|
// second membre total
|
|
vglobaal += vglobex ;vglobaal += vglobin ;
|
|
// on calcul la matrice de masse qui est très particulière dans le cas de la relaxation dynamique
|
|
// c'est la partie la plus importante de l'algo: l'adaptation de la masse en continue
|
|
//-- *** dans le cas historique : type_calcul_mass ==1
|
|
// on utilise le volume de chaque élément, donc il doit avoir été calculé
|
|
// -- ** ce qui est le cas au moment du calcul des forces internes
|
|
// sauf en MPI
|
|
CalculEnContinuMatriceMasse
|
|
(relax_vit_acce,lesMail,Ass1,compteur
|
|
,diversStockage,lesRef,X1,premier_calcul,lesContacts
|
|
,force_recalcul_masse,lesFonctionsnD);
|
|
|
|
// calcul des reactions de contact pour les noeuds esclaves
|
|
// dans le repere absolu ( pour la sortie des infos sur le contact)
|
|
// et test s'il y a decollement de noeud en contact (pour les contacts actifs)
|
|
// mais ici, il n'y a pas de modification des éléments de contact (elles ont été faites dans lesContacts->Actualisation())
|
|
bool decol=false; // création et init de decol
|
|
if ((pa.ContactType())&&(compteur_demarrage > 0))
|
|
lesContacts->CalculReaction(vglobin,decol,Ass1.Nb_cas_assemb(),aff_iteration);
|
|
// - definition éventuelle de conditions limites linéaires de contact, en fonction des éléments du contact existant à ce niveau
|
|
// (certains contacts (par pénalisation par exemple) ne produise pas de conditions linéaires)
|
|
list <Condilineaire> *listCondLine = NULL; // init donc sans élément
|
|
if (((pa.ContactType()==1) || (pa.ContactType()==3))&&(compteur_demarrage > 0))
|
|
listCondLine = &(lesContacts->ConditionLin(Ass1.Nb_cas_assemb()));
|
|
|
|
// -- dans le cas d'un amortissement visqueux critique ou
|
|
// dans le cas où l'on utilise de l'amortissement numérique le second membre est modifiée
|
|
if ((typeCalRelaxation == 2)
|
|
|| (typeCalRelaxation == 3)
|
|
|| (typeCalRelaxation == 4)
|
|
|| (pa.Amort_visco_artificielle())
|
|
)
|
|
{ if (Arret_A_Equilibre_Statique()) // si on veut un équilibre statique, on sauvegarde les forces statiques, dans (*vglob_stat) qui est différent de (*vglobaal)
|
|
// en amortissement cinétique, ce n'est pas le cas
|
|
(*vglob_stat) = vglobaal;
|
|
};
|
|
if ((typeCalRelaxation == 2)
|
|
|| (pa.Amort_visco_artificielle()&& !(Cinetique_ou_visqueux(force_recalcul_masse)))
|
|
|| (typeCalRelaxation == 3)
|
|
|| ((typeCalRelaxation == 4) && !(Cinetique_ou_visqueux(force_recalcul_masse)))
|
|
)
|
|
{
|
|
/* if (Arret_A_Equilibre_Statique()) // si on veut un équilibre statique, on sauvegarde les forces statiques
|
|
// (*vglob_stat) = (*vglobaal); */
|
|
Cal_mat_visqueux_num_expli(*mat_masse_sauve,mat_C_pt,delta_X,false,vitesse_tdt);
|
|
/* else { mat_C_pt->Initialise(0.);};
|
|
// if (typeCalRelaxation == 2)
|
|
// CalculEnContinuMatriceViscositeCritique(*mat_masse_sauve,*mat_C_pt,delta_X,vitesse_tdt); */
|
|
#ifdef UTILISATION_MPI
|
|
if (proc_en_cours == 0) // cas d'un calcul //, seule la matrice du CPU 0 est concernée
|
|
#endif
|
|
vglobaal -= mat_C_pt->Prod_mat_vec(vitesse_t,forces_vis_num);
|
|
};
|
|
|
|
// initialisation des sauvegardes sur second membre (uniquement pour les gammai)
|
|
lesCondLim->InitSauve(Ass3.Nb_cas_assemb());
|
|
|
|
////---- debug
|
|
//cout << "\n debug algo relax ";
|
|
//vglobaal.Affiche();
|
|
////--- fin debug
|
|
|
|
// on récupère les réactions avant changement de repère et calcul des torseurs de réaction
|
|
lesCondLim->ReacAvantCHrepere(vglobaal,lesMail,lesRef,Ass3.Nb_cas_assemb(),cas_combi_ddl);
|
|
|
|
|
|
// -->> expression de la matrice masse et du second membre dans un nouveau repere
|
|
// mais ici on n'impose pas les conditons, on fait simplement le changement de repère
|
|
//modif_repere = indicateur si réellement il y a un changement
|
|
bool modif_repere = lesCondLim->CoLinCHrepere_int(*mat_masse,vglobaal,Ass3.Nb_cas_assemb(),vglob_stat);
|
|
if ((pa.ContactType()==1)&&(compteur_demarrage > 0)) // idem pour le contact conduisant à des conditions linéaires
|
|
modif_repere = modif_repere ||
|
|
lesCondLim->CoLinCHrepere_ext(*mat_masse,vglobaal,*listCondLine,Ass3.Nb_cas_assemb(),vglob_stat);
|
|
|
|
// sauvegarde des reactions pour les ddl bloques (simplement)
|
|
// ***dans le cas statique il semble (cf. commentaire dans l'algo) que ce soit inutile donc a voir
|
|
// ***donc pour l'instant du a un bug je commente
|
|
// sauvegarde des reactions aux ddl bloque (uniquement pour les Xi)
|
|
// lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass3.Nb_cas_assemb(),cas_combi_ddl);
|
|
|
|
////---- debug
|
|
//#ifdef UTILISATION_MPI
|
|
// if (proc_en_cours == 0) // cas d'un calcul //, seule la matrice du CPU 0 est concernée
|
|
//#endif
|
|
//{cout << "\n debug algo relax: mat_masse avec CL";
|
|
// mat_masse->Affiche();
|
|
//}
|
|
////--- fin debug
|
|
// mise en place des conditions limites sur la matrice masse et le second membre
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,*mat_masse,vglobaal
|
|
,Ass3.Nb_cas_assemb(),cas_combi_ddl,vglob_stat);
|
|
////---- debug
|
|
//#ifdef UTILISATION_MPI
|
|
// if (proc_en_cours == 0) // cas d'un calcul //, seule la matrice du CPU 0 est concernée
|
|
//#endif
|
|
//{cout << "\n debug algo relax: mat_masse après CL";
|
|
// mat_masse->Affiche();
|
|
//}
|
|
////--- fin debug
|
|
// puis on prépare (si besoin est en fonction du type de matrice) la résolution
|
|
// s'il n'y a pas de condition linéaire et pas de chg de repère,
|
|
// on peut déjà inverser par exemple la matrice masse
|
|
if ((!modif_repere) && (!(lesCondLim->ExisteCondiLimite())))
|
|
mat_masse->Preparation_resol();
|
|
|
|
// (blocage de toutes les conditions lineaires, quelque soit leur origines ext ou int donc contact éventuel)
|
|
lesCondLim->CoLinBlocage(*mat_masse,vglobaal,Ass3.Nb_cas_assemb(),vglob_stat);
|
|
// calcul du maxi des reactions (pour les xi)
|
|
maxReaction = lesCondLim->MaxEffort(inReaction,Ass3.Nb_cas_assemb());
|
|
// sortie d'info sur l'increment concernant les réactions
|
|
if ( aff_iteration)
|
|
{ if (ParaGlob::NiveauImpression() > 2) cout << "\n IT:" << compteur;
|
|
InfoIncrementReac(lesMail,inReaction,maxReaction,Ass3.Nb_cas_assemb());
|
|
};
|
|
|
|
bool arretResidu = false; // pour gérer le cas particulier ou on veut un arrêt et sur le résidu et sur le déplacement
|
|
bool demande_de_break=false; // pour gestion du break en tenant compte ou non du MPI
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la convergence
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// examen de la convergence si nécessaire, utilisant le résidu
|
|
if (ArretEquilibreStatique() && (compteur>1) && (compteur_demarrage != 0) )// cas d'une convergence en utilisant le résidu
|
|
{ double toto=0.; int itera = 0; // valeur par defaut pour ne pas se mettre dans un cas itératif de type algo de Newton
|
|
bool arret_demande = false; // normalement n'intervient pas ici, car il n'y a pas de prise en compte d'iteration
|
|
// bool affiche = aff_incr && (ParaGlob::NiveauImpression() > 2);
|
|
arret = Convergence(aff_iteration ,toto,vglobaal,maxPuissExt,maxPuissInt,maxReaction,itera,arret_demande);
|
|
if (arret)
|
|
{ // sortie des itérations sauf si l'on est en loi simplifiée
|
|
if (lesLoisDeComp->Test_loi_simplife() )
|
|
{lesLoisDeComp->Loi_simplifie(false); // cas d'une loi simplifié on remet normal
|
|
arret = false;
|
|
}
|
|
else
|
|
{if ((ArretEquilibreStatique() == 2)
|
|
&& ((typeCalRelaxation == 1)||(typeCalRelaxation == 3)
|
|
|| ((typeCalRelaxation == 4) && (Cinetique_ou_visqueux(force_recalcul_masse)))
|
|
)
|
|
)
|
|
{ arretResidu=true;} // cas relaxation avec amortissement cinétique
|
|
else {demande_de_break=true;}//break;}; // cas normal,
|
|
};
|
|
};
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
// TroisEntiers les_arrets(arretResidu,arret,demande_de_break);
|
|
Vecteur trois_faux_entiers(3);
|
|
trois_faux_entiers(1) = (double) arretResidu;
|
|
trois_faux_entiers(2) = (double) arret;
|
|
trois_faux_entiers(3) = (double) demande_de_break;
|
|
|
|
|
|
////---- debug
|
|
//cout << "\n debug algo relax : barriere avant transfert les_arrets proc = " << ParaGlob::Monde()->rank()
|
|
// << " les_arrets= " << les_arrets << " compteur= " << compteur << " compteur_demarrage= " << compteur_demarrage << flush;
|
|
////--- fin debug
|
|
//// debug
|
|
//cout << "\n debug algo relax "
|
|
// << " barriere avant transfert les_arrets , proc= "<< ParaGlob::Monde()->rank() << flush;
|
|
//// fin debug
|
|
// ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
|
|
// broadcast(*ParaGlob::Monde(), les_arrets, 0);
|
|
// broadcast(*ParaGlob::Monde(), trois_faux_entiers, 0);
|
|
trois_faux_entiers.Broadcast(0);
|
|
|
|
// operator MPI_Comm() const;
|
|
|
|
if (ParaGlob::Monde()->rank() != 0)
|
|
{arretResidu= (int) trois_faux_entiers(1); //les_arrets.un;
|
|
arret = (int) trois_faux_entiers(2); //les_arrets.deux;
|
|
demande_de_break = (int) trois_faux_entiers(3); //les_arrets.trois;
|
|
};
|
|
////---- debug
|
|
//cout << "\n debug algo relax : proc = " << ParaGlob::Monde()->rank()
|
|
// << " après transfer: les_arrets= " << les_arrets << " compteur= " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
////--- fin debug
|
|
////---- debug
|
|
//cout << "\n debug algo relax : proc = " << ParaGlob::Monde()->rank()
|
|
// << "\n on continue "<< flush;
|
|
////--- fin debug
|
|
temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
#endif
|
|
if (demande_de_break)
|
|
break;
|
|
|
|
// 4 --<ARD>-- calcul des nouvelles accélérations
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 fait la résolution globale
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// resolution simple (fonction du type de matrice)
|
|
// ou non suivant modif_repere
|
|
tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu
|
|
residu_final = vglobaal; // sauvegarde pour le post-traitement
|
|
// ici il y a deux conditions équivalentes, mais on les laisse car on pourrait peut-être
|
|
// avoir un changement de repère sans
|
|
if ((!modif_repere) && (!(lesCondLim->ExisteCondiLimite())))
|
|
{mat_masse->Simple_Resol_systID_2 (vglobaal,acceleration_tdt,pa.Tolerance()
|
|
,pa.Nb_iter_nondirecte(),pa.Nb_vect_restart());}
|
|
else // cas où on a eu des changements de repère, il faut une résolution complète
|
|
{acceleration_tdt = (mat_masse->Resol_systID(vglobaal,pa.Tolerance()
|
|
,pa.Nb_iter_nondirecte(),pa.Nb_vect_restart()));};
|
|
tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu
|
|
// affichage éventuelle du vecteur solution : accélération
|
|
if (ParaGlob::NiveauImpression() >= 10)
|
|
{ string entete = " affichage du vecteur solution acceleration ";
|
|
acceleration_tdt.Affichage_ecran(entete);
|
|
};
|
|
// retour des accélération dans les reperes generaux, dans le cas où ils ont ete modifie
|
|
// par des conditions linéaires
|
|
lesCondLim->RepInitiaux( acceleration_tdt,Ass3.Nb_cas_assemb());
|
|
#ifdef UTILISATION_MPI
|
|
}
|
|
// s'il s'agit d'un process de calcul élémentaire ou non
|
|
// sol = &vglobaal; // il faut affecter sol pour récupérer ensuite la solution
|
|
// le process 0 transmet aux autres process le vecteur résultat
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
temps_transfert_long_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
// sol->Broadcast(0);
|
|
//// debug
|
|
//cout << "\n debug algo relax "
|
|
// << " barriere avant transfert acceleration_tdt , proc= "<< ParaGlob::Monde()->rank()
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
//// fin debug
|
|
// ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
|
|
acceleration_tdt.Broadcast(0);
|
|
//// debug
|
|
// if (proc_en_cours == 0) // cas d'un calcul //, seule la matrice du CPU 0 est concernée
|
|
// {cout << "\n debug algo relax "
|
|
// << " barriere après transfert acceleration_tdt , proc= "<< ParaGlob::Monde()->rank()
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
// cout << "\n acceleration_tdt ";acceleration_tdt.Affiche();
|
|
// };
|
|
//// fin debug
|
|
|
|
|
|
temps_transfert_long_algo.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
// // debug
|
|
// cout << "\n debug algo relax , proc= "<< ParaGlob::Monde()->rank()
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage << " acceleration: "
|
|
// << acceleration_tdt << flush;
|
|
// // fin debug
|
|
#else
|
|
//// // debug
|
|
// {cout << "\n debug algo relax "
|
|
// << " barriere après transfert acceleration_tdt "
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage<< flush;
|
|
// cout << "\n acceleration_tdt ";acceleration_tdt.Affiche();
|
|
// };
|
|
//// cout << "\n debug algo relax "
|
|
// << " compteur = " << compteur << " compteur_demarrage= " << compteur_demarrage << " acceleration: ";
|
|
// acceleration_tdt.Affiche(); cout << flush;
|
|
// // fin debug
|
|
#endif
|
|
|
|
// effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
|
|
lesCondLim->EffMarque();
|
|
if (pa.ContactType()) lesContacts->EffMarque();
|
|
|
|
// -- calcul de la vitesse exacte à t+dt selon le schéma DFC avec un delta t =1.
|
|
vitesse_tdt = vitesse_t + 0.5 * (acceleration_t+acceleration_tdt);
|
|
// -- on remet réellement en place les CL a partir de la sauvegarde sur les vitesses (seulement)
|
|
for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++)
|
|
{LesCondLim::Gene_asso & s = (*ie); // pour simplifier
|
|
vitesse_tdt(s.pointe(2)) = V_Bl(ih);
|
|
};
|
|
|
|
// passage des accélérations et des vitesses calculées aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1);
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
|
|
// dans le cas ou la recherche de nouveaux contacts est effectuée à chaque itération
|
|
if (((type_activation_contact== 1) && (pa.ContactType()))&&(compteur_demarrage > 0))
|
|
{ // actualisation des éléments de contact et éventuellement inactivation d'éléments
|
|
lesContacts->Actualisation(0); // si on n'a plus de projection
|
|
// on inactive les éléments de contact qui se relache: testé soit via la réaction
|
|
lesContacts->RelachementNoeudcolle(); // ou via la sortie d'une zone d'accostage (dépend de l'algo)
|
|
};
|
|
|
|
if (compteur_demarrage != -1)
|
|
{// mise à jour de delta_X, var_delta_X et passage en global des maxi
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
CalEnergieAffichage(1.,vitesse_tdt,*mat_masse_sauve,delta_X
|
|
,icharge,brestart,acceleration_tdt,forces_vis_num);
|
|
if (compteur_demarrage==0)// dans le cas du premier incrément on considère que la balance vaut l'énergie
|
|
// cinétique initiale, car vu que l'on ne met pas de CL à t=0, E_cin_0 est difficile à calculer
|
|
{E_cin_0 = E_cin_tdt - bilan_E + E_int_tdt - E_ext_tdt; };
|
|
};
|
|
// calcul de l'amortissement cinétique dans le cas ou ce n'est pas de l'amortissement visqueux critique
|
|
if ((typeCalRelaxation == 1)||(typeCalRelaxation == 3)
|
|
|| ((typeCalRelaxation == 4) && (Cinetique_ou_visqueux(force_recalcul_masse)))
|
|
)
|
|
{ relax_vit_acce = AmortissementCinetique(delta_X,1.,X_tdt,*mat_masse_sauve,compteur,vitesse_tdt);
|
|
////---- debug
|
|
//cout << "\n debug algo relax : proc = " << ParaGlob::Monde()->rank()
|
|
// << "\n sortie relaxation: relax_vit_acce= " << relax_vit_acce << " compteur= " << compteur << flush;
|
|
////--- fin debug
|
|
|
|
// il faut re-updater les vitesses
|
|
// if (Abs(relax_vit_acce) == 1)
|
|
if (relax_vit_acce == 1) // il y a eu relaxation
|
|
{lesMail->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
list_iter_relax.push_front(compteur); // on sauvegarde l'iter relaxé
|
|
};
|
|
// examen de la convergence éventuelle, utilisant le déplacement et/ou le résidu
|
|
if (Pilotage_fin_relaxation_et_ou_residu(relax_vit_acce,1,compteur,arretResidu,arret))
|
|
break;
|
|
};
|
|
|
|
// on incrémente les valeurs globales à t, par contre on ne change pas les grandeurs locales à t !!
|
|
X_t = X_tdt;
|
|
vitesse_t = vitesse_tdt;
|
|
acceleration_t = acceleration_tdt;
|
|
// dans le cas du mode debug on sort éventuellement les infos au fil du calcul (un peu bricolé)
|
|
if ((mode_debug > 0)||(pa.EtatSortieEtatActuelDansCVisu()))
|
|
{ bool a_sortir_debug=false; // pour éviter une division par 0 du test (compteur % mode_debug == 0)
|
|
if (pa.EtatSortieEtatActuelDansCVisu()) {a_sortir_debug=true;}
|
|
else if (compteur % mode_debug == 0) {a_sortir_debug=true;};
|
|
if (a_sortir_debug)
|
|
{ // on passe les déplacements de tdt à t
|
|
lesMail->Vect_glob_vers_local(TEMPS_t,X1,X_tdt,X1);
|
|
// visualisation éventuelle au fil du calcul: essentiellement la déformée
|
|
tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,(icharge*1000000+compteur));
|
|
// on remet les choses dans l'ordre initial
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
|
|
lesMail->Vect_glob_vers_local(TEMPS_t,X1,save_X_t,X1);
|
|
};
|
|
};
|
|
|
|
// cas du calcul des énergies, passage des grandeurs de tdt à t
|
|
if (compteur_demarrage != -1) Algori::TdtversT();
|
|
// si compteur_demarrage = -1 ou 0 on a un traitement spécial, on sort de la boucle
|
|
// car ce sont en fait des passages d'initialisation
|
|
if (compteur_demarrage < 1)
|
|
break;
|
|
|
|
|
|
//---//\\//\\// fin de la boucle sur les itérations d'équilibres //\\//\\//
|
|
};
|
|
// effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
|
|
// car ici on n'est pas passé par cette endroit si l'on a convergé
|
|
lesCondLim->EffMarque();
|
|
if (pa.ContactType()) lesContacts->EffMarque();
|
|
|
|
// mise à jour des indicateurs contrôlés par le tableau: *tb_combiner
|
|
if (tb_combiner != NULL) // cas d'un contrôle via des fonctions nD
|
|
{if ((*tb_combiner)(1) != NULL)
|
|
validation_calcul = (*tb_combiner)(1)->Valeur_pour_variables_globales()(1);
|
|
if ((*tb_combiner)(2) != NULL)
|
|
sortie_boucle_controler_par_fctnD = (*tb_combiner)(2)->Valeur_pour_variables_globales()(1);
|
|
};
|
|
|
|
// gestion de la fin des itérations
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 a fait la résolution globale
|
|
// il gère seul également la convergence, mais il doit tenir au courant les autres process
|
|
tempsCalEquilibre.Arret_du_comptage(); // fin comptage cpu
|
|
Algori::Passage_indicConvergenceAuxProcCalcul();
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
// ce qui permet le déroulement correct de la suite pour tous les process
|
|
#endif
|
|
|
|
if ( ((compteur_demarrage > 0) && (!Pilotage_fin_iteration_implicite(compteur))))
|
|
{ // cas d'une non convergence
|
|
pas_de_convergence_pour_l_instant = 1;
|
|
// comme on incrémente pas les ddl on remet cependant les ddl
|
|
// et les grandeurs actives de tdt aux valeurs de ceux de t
|
|
lesMail->TversTdt();
|
|
// ------ cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
|
|
if (Algori::PhaseDeConvergence() == -8)
|
|
{ int nb_incr_en_arriere = 3; // !!!!! nombre actuellement arbitraire -> par la suite mettre dans les para
|
|
if (Controle_retour_sur_un_increment_enregistre(nb_incr_en_arriere,icharge))
|
|
{ // cas ou on a réussi à trouver un incrément sauvegardé adoc = maintenant icharge
|
|
int cas=2;
|
|
this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,icharge);
|
|
// comme les conditions limites cinématiques peuvent être différentes en restart
|
|
// on libére toutes les CL imposées éventuelles
|
|
lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
|
|
lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
|
|
// dans le cas d'un calcul axisymétrique on bloque le ddl 3
|
|
if (ParaGlob::AxiSymetrie())
|
|
lesMail->Inactive_un_ddl_particulier(X3);
|
|
// on valide l'activité des conditions limites et condition linéaires, pour le temps initial
|
|
// en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb,lesRef,charge->Temps_courant(),icas);
|
|
int ttsi = li_gene_asso.size();
|
|
X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi);
|
|
// on remet à jour les éléments pour le contact s'il y du contact présumé
|
|
if (pa.ContactType())
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
brestart = true; // on signale que l'on repars avec un restart
|
|
};
|
|
// sinon on ne fait rien, on se contente du pilotage de divergence existant
|
|
};
|
|
// ------ fin cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
|
|
}
|
|
else
|
|
{// --- sinon calcul correcte
|
|
pas_de_convergence_pour_l_instant = 0;
|
|
#ifdef UTILISATION_MPI
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
#endif
|
|
if ((ParaGlob::NiveauImpression() > 0)&&(compteur_demarrage > 0))
|
|
cout << " \n ... convergence en " << compteur << " iterations "<< endl ;
|
|
// traitement du contact dans le cas où son activation n'a pas été faite à chaque itération
|
|
if ((pa.ContactType()) && (type_activation_contact != 1))
|
|
{ lesContacts->Actualisation(0); // actualisation du contact en fonction du dernier incrément
|
|
// mise à jour éventuelle de la matrice de raideur en fonction du contact
|
|
// Mise_a_jour_Choix_matriciel_contact(mato,Ass.Nb_cas_assemb(),lesContacts);
|
|
// réexamen du contact pour voir s'il n'y a pas de nouveau element de contact
|
|
// en fait on fera au plus deux passages supplémentaire, sinon la boucle peut être infini,
|
|
// à la fin du second passage, on regarde s'il y a décollement, si oui on relâche et on refait un passage
|
|
// sinon on valide
|
|
//I)--------------
|
|
//cout << "\n avant test: indicCycleContact= " << indicCycleContact << endl;
|
|
if (indicCycleContact == 0 )
|
|
{ if (lesContacts->Nouveau(lesMail->Max_var_dep_t_a_tdt()))
|
|
{indicCycleContact=1;} // on a de nouveau contact on refait le deuxième cycle
|
|
else
|
|
// sinon, on n'a pas de nouveau contact, on regarde s'il y a du relachement
|
|
{ indicCycleContact=2;};
|
|
}
|
|
else if (indicCycleContact == 1)
|
|
{indicCycleContact=2;} // pour regarder le relachement
|
|
else
|
|
{indicCycleContact=0;}; // pas de newcontact, ni de relachement donc c'est ok
|
|
//II)---------------
|
|
if (indicCycleContact == 2)
|
|
{ if (lesContacts->RelachementNoeudcolle())
|
|
{indicCycleContact=3;} // pour une dernière boucle d'équilibre
|
|
else
|
|
{indicCycleContact=0;};// pas de relachement donc ok
|
|
};
|
|
//cout << "\n après test: indicCycleContact= " << indicCycleContact << endl;
|
|
}
|
|
else
|
|
// concerne ici: soit le cas où c'est un problème sans contact (=contact non activé)
|
|
// soit le cas où l'activation du contact s'effectue à chaque itération
|
|
{ indicCycleContact = 0; }; //pour le prochain increment
|
|
|
|
if (!(pa.ContactType()) || (indicCycleContact == 0))
|
|
{// on impose une accélération nulle compte tenu du fait qu'elle est ici purement numérique
|
|
acceleration_tdt.Zero();
|
|
vitesse_tdt.Zero(); // idem vitesses (pourrait poser des pb si l'on veut utiliser des vrais vitesses aux noeuds ?)
|
|
// passage des accélérations et des vitesses calculées aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1);
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1);
|
|
|
|
// si on est sans validation, on ne fait rien, sinon on valide l'incrément
|
|
// avec sauvegarde éventuelle
|
|
// lesMail->TdtversT(); // ******* essai
|
|
// // on valide l'activité des conditions limites et condition linéaires
|
|
// lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
|
|
if (validation_calcul)
|
|
{// actualisation des ddl et des grandeurs actives de t+dt vers t
|
|
lesMail->TdtversT();
|
|
lesContacts->TdtversT();
|
|
// cas du calcul des énergies, passage des grandeurs de tdt à t
|
|
if (compteur_demarrage != -1) Algori::TdtversT();
|
|
// actualisation des éléments de contact et éventuellement suppression
|
|
if (pa.ContactType()) lesContacts->Actualisation(0); // des éléments qui ne sont plus en contact
|
|
if (compteur_demarrage != -1)
|
|
{// on valide l'activité des conditions limites et condition linéaires
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
//s'il y a remonté des sigma et/ou def aux noeuds et/ou calcul d'erreur
|
|
bool change =false; // calcul que s'il y a eu initialisation
|
|
if(prepa_avec_remont) {change = Algori::CalculRemont(lesMail,type_incre,icharge);};
|
|
if (change) // dans le cas d'une remonté il faut réactiver les bon ddls
|
|
{lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(tenuXVG);};
|
|
|
|
// 3 mai 2019: je commente la suite, car 1) ne sert pas ici car on initialise jamais le prochain
|
|
// incr avec le précédent, 2) cela change le delta_X qui ne représente plus le vrai delta X du coup
|
|
// tous les calculs qui utilise ce delta X sont faux (matrice viscosité par exemple !)
|
|
// // on regarde si l'on doit initialiser le prochain incrément avec le pas précédent
|
|
// if (pa.IniIncreAvecDeltaDdlPrec()) // si oui on sauvegarde le delta_X actuel / delta_t
|
|
// {// récupération (initialisation) des ddl position à t et t+dt
|
|
// lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
|
|
// lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// // calcul de la variation de ddl / delta t
|
|
// delta_X = X_tdt; delta_X -= X_t; delta_X /= pa.Deltat();
|
|
// };
|
|
|
|
// cas du calcul des énergies, passage des grandeurs de tdt à t
|
|
Algori::TdtversT();
|
|
if (compteur_demarrage > 0)
|
|
{
|
|
tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
|
|
// sauvegarde de l'incrément si nécessaire
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
// visualisation éventuelle au fil du calcul
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
|
|
};
|
|
}; //- fin de la condition if (compteur_demarrage != -1)
|
|
}; // -- fin du test: if (validation_calcul)
|
|
|
|
if (compteur_demarrage != -1) // de nouveau le test qui est indépendant de la valeur de "validation_calcul" (??)
|
|
premier_calcul = false;// -- on enregistre le fait que l'on n'est plus au premier passage
|
|
brestart = false; // dans le cas où l'on était en restart, on passe l'indicateur en cas courant
|
|
if (validation_calcul)
|
|
{ if (compteur_demarrage > 0) // si > 0 : calcul normal donc on incrémente icharge
|
|
icharge++;
|
|
// init de var glob
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
};
|
|
}; // -- fin du cas ou le calcul converge
|
|
}; // fin du calcul correcte : if // gestion de la fin des itérations
|
|
|
|
// cas particulier où la sortie de la boucle est pilotée
|
|
if (sortie_boucle_controler_par_fctnD
|
|
&& (!pas_de_convergence_pour_l_instant)
|
|
&& (compteur_demarrage > 0)
|
|
)
|
|
break;
|
|
compteur_demarrage++; // dans tous les cas on incrémente le compteur de démarrage
|
|
|
|
////------- debug
|
|
//cout << "\n debug calequilibre relaxdyna";
|
|
//cout << "\n (!charge->Fin(icharge,!pas_de_convergence_pour_l_instant))= "<< (!charge->Fin(icharge,!pas_de_convergence_pour_l_instant))
|
|
// << "\n pas_de_convergence_pour_l_instant= "<< pas_de_convergence_pour_l_instant
|
|
// << " compteur_demarrage= "<< compteur_demarrage
|
|
// << " charge->Fin(icharge,true= "<< charge->Fin(icharge,true)
|
|
// << " charge->Fin(icharge,false)= "<< charge->Fin(icharge,false)
|
|
// << " (!pa.EtatSortieEquilibreGlobal())= "<< (!pa.EtatSortieEquilibreGlobal())
|
|
// << "\n le resultat = " << ( ((!charge->Fin(icharge,!pas_de_convergence_pour_l_instant))
|
|
// || pas_de_convergence_pour_l_instant ||(compteur_demarrage < 1)
|
|
// )
|
|
// && (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())
|
|
// )
|
|
// << "\n\n\n "
|
|
// << endl;
|
|
|
|
//--- fin debug
|
|
// while ( ((!charge->Fin(icharge,!pas_de_convergence_pour_l_instant)) // on n'affiche la sin
|
|
// // que si on a eu convergence
|
|
// || pas_de_convergence_pour_l_instant ||(compteur_demarrage < 1)
|
|
// )
|
|
// && (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())
|
|
// )
|
|
|
|
}; // -- fin du while sur les incréments de charge
|
|
// test de fin de calcul effectue dans charge via : charge->Fin()
|
|
// on remet à jour le nombre d'incréments qui ont été effectués qui a été incrémenté en fin de while
|
|
// donc qui ne donne pas le vrai incrément futur
|
|
if (validation_calcul)
|
|
{if (compteur_demarrage > 0) // si <= 1 cela signifie qu'il n'a pas eu d'incrémentation auparavant
|
|
icharge--;
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
// dans le cas d'une suite de sous algo on signale qu'il y a validation
|
|
if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
|
|
(*tb_combiner)(3) = NULL;
|
|
}
|
|
else // si on ne valide pas le calcul, on reinitialise la charge
|
|
// c-a-d l'avancement en temps, incrément et facteur multiplicatif
|
|
// de manière à avoir les mêmes conditions de départ pour le prochain calcul
|
|
{ charge->Precedant(true);
|
|
// dans le cas d'une suite de sous algo on signale qu'il n'y a pas validation
|
|
if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
|
|
(*tb_combiner)(3) = (*tb_combiner)(1);
|
|
} ;
|
|
////------ debug
|
|
//cout << "\n ********* debug calequilibre RD: "
|
|
// << " double deltat_actuel = pa.Deltat()= " << pa.Deltat() << flush;
|
|
////--- fin debug
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
};
|
|
|
|
// dernière passe
|
|
void AlgoriRelaxDyna::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)
|
|
{ // passage finale dans le cas d'une visualisation au fil du calcul
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(RELAX_DYNA); // transfert info
|
|
type_incre = OrdreVisu::DERNIER_INCRE;
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
// sauvegarde de l'incrément si nécessaire
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
|
|
,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
};
|
|
|
|
// initialisation pour le calcul de la matrice masse dans le cas de l'algorithme de relaxation dynamique
|
|
void AlgoriRelaxDyna::InitCalculMatriceMasse(LesMaillages * lesMail
|
|
,Mat_abstraite& mat_mass,Assemblage& Ass
|
|
,Mat_abstraite& mat_mass_sauve
|
|
,LesFonctions_nD* lesFonctionsnD)
|
|
{tempsCalMasse.Mise_en_route_du_comptage();
|
|
switch (type_calcul_mass)
|
|
{ case 1: // cas historique
|
|
{// on définit un vecteur de dimension le nombre de noeud = celui de mat_mass / dim
|
|
v_mass.Change_taille(mat_mass.Nb_ligne() / ParaGlob::Dimension());
|
|
// boucle sur les elements et on ne fait qu'une initialisation
|
|
int nbMailMax = lesMail->NbMaillage();
|
|
for (int nbMail =1; nbMail<= nbMailMax; nbMail++)
|
|
{ int nemax = lesMail->Nombre_element(nbMail);
|
|
for (int ne=1; ne<= nemax;ne++)
|
|
{ Element & el = lesMail->Element_LesMaille(nbMail,ne); // l'element
|
|
((ElemMeca&) el).InitCalculMatriceMassePourRelaxationDynamique (casMass_relax);
|
|
};
|
|
};
|
|
break;
|
|
}
|
|
case 2: // ---cas ou on utilise la matrice de raideur réelle
|
|
// premier dimentionnement
|
|
{mat_mass.Initialise(0.);
|
|
// ici le vecteur v_mass à la taille du nb de ddl
|
|
v_mass.Change_taille(mat_mass.Nb_ligne());
|
|
v_mass.Zero(); // idem: un vecteur intermédiaire de calcul
|
|
if ( ((casMass_relax > 3) && (casMass_relax < 6)) //4-5 cas où on a besoin de deux assemblages
|
|
||((casMass_relax > 7) && (casMass_relax < 10))
|
|
)
|
|
v_mass1.Change_taille(mat_mass.Nb_ligne() / ParaGlob::Dimension());
|
|
break;
|
|
};
|
|
default:
|
|
{ cout << "\n **** erreur le cas type_calcul_mass= " << type_calcul_mass
|
|
<< "\n pour l'instant n'est pas implante "
|
|
<< "\n AlgoriRelaxDyna::InitCalculMatriceMasse( ... ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
tempsCalMasse.Arret_du_comptage();
|
|
};
|
|
|
|
|
|
// calcul de la matrice masse dans le cas de l'algorithme de relaxation dynamique
|
|
void AlgoriRelaxDyna::CalculMatriceMasse
|
|
(const int& relax_vit_acce,LesMaillages * lesMail,Assemblage& Ass
|
|
, int compteur, const DiversStockage* divStoc,LesReferences* lesRef
|
|
,const Enum_ddl & N_ddl ,LesContacts* lesContacts
|
|
,LesFonctions_nD* lesFonctionsnD)
|
|
{ tempsCalMasse.Mise_en_route_du_comptage();
|
|
int dima = ParaGlob::Dimension();
|
|
// dans le cas où on est en axisymétrie il faut diminuer de 1
|
|
if (ParaGlob::AxiSymetrie())
|
|
dima--;
|
|
int nbddl_X = mat_masse->Nb_ligne();
|
|
int nbNoe = nbddl_X / dima;
|
|
#ifdef UTILISATION_MPI
|
|
int proc_en_cours = ParaGlob::Monde()->rank();
|
|
// seule le process 0 s'occupe du calcul de la masse
|
|
// et celui-ci ne peut pas être le type historique : 1, car le volume de chaque élément
|
|
// n'est pas dispo (il est dispo dans les processus != 0)
|
|
if (type_calcul_mass == 1)
|
|
{ cout << "\n erreur : en calcul MPI, le type 1 de calcul de la masse n'est pas implante ";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
|
|
|
|
switch (type_calcul_mass)
|
|
{ case 1: // cas historique, on effectue le calcul effectif de la matrice masse
|
|
{// on initialise la matrice masse à 0
|
|
mat_masse->Initialise(0.);
|
|
// vue que le v_mass a une taille qui n'est pas la même pour tous les paramétres, on vérifie
|
|
// on définit un vecteur de dimension le nombre de noeud = celui de mat_mass / dim
|
|
v_mass.Change_taille(nbNoe);
|
|
|
|
v_mass.Zero(); // idem: un vecteur intermédiaire qui sert pour la construction de la matrice masse
|
|
// de dimension le nombre de noeud
|
|
// initialisation des updates du ddl_étendu de masse sur les noeuds: on met à 0 le ddl_etendu correspondant,
|
|
// le compteur, comptant le nombre de fois où le noeuds est modifiés, est mis à 0
|
|
lesMail->InitUpdateAuNoeud(masseRelax_1);
|
|
|
|
// --- boucle sur les elements, pour définir la grandeur "masse_relax_dyn" aux noeuds de chaque éléments
|
|
for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
|
|
for (int ne=1; ne <= lesMail->Nombre_element(nbMail); ne++)
|
|
{ Element & el = lesMail->Element_LesMaille(nbMail,ne); // l'element
|
|
// Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
|
|
// on calcul aux noeuds, la valeur des masses nécessaires
|
|
((ElemMeca&) el).CalculMatriceMassePourRelaxationDynamique (alph,beta,lambda,gamma,theta,casMass_relax);
|
|
// cout << "numéro =" << ne << endl;
|
|
// mat_masse_loc->Affiche();
|
|
// mat_masse_loc->Affiche1(1,8,1,1,8,1);
|
|
};
|
|
|
|
// si on est dans le cas 3 ou 4, on fait la moyenne aux noeuds
|
|
if ((casMass_relax == 3) || (casMass_relax == 4))
|
|
lesMail->MoyenneCompteurAuNoeud(masseRelax_1);
|
|
|
|
// maintenant on balaie les noeuds pour définir les valeurs de la matrice masse
|
|
// on boucle sur les noeuds du maillage, on regarde si les ddl de déplacement sont actifs
|
|
// si oui, on renseigne la matrice masse
|
|
lesMail->Scalaire_loc_vers_glob(GAMMA1,v_mass,masseRelax_1);
|
|
// construction des termes de la matrice
|
|
for (int inn = 1; inn<= nbNoe; inn++)
|
|
switch (dima)
|
|
// { case 3: mat_d.set_element((inn-1)*dima+3,(inn-1)*dima+3,v_mass(inn));
|
|
// case 2: mat_d.set_element((inn-1)*dima+2,(inn-1)*dima+2,v_mass(inn));
|
|
// case 1: mat_d.set_element((inn-1)*dima+1,(inn-1)*dima+1,v_mass(inn));
|
|
// };
|
|
{ case 3: (*mat_masse)((inn-1)*dima+3,(inn-1)*dima+3) = v_mass(inn);
|
|
case 2: (*mat_masse)((inn-1)*dima+2,(inn-1)*dima+2) = v_mass(inn);
|
|
case 1: (*mat_masse)((inn-1)*dima+1,(inn-1)*dima+1) = v_mass(inn);
|
|
};
|
|
|
|
// transfert dans la matrice de masse
|
|
// MatDiag & mat_d = *((MatDiag*) & mat_masse); // récup de la matrice diagonale
|
|
|
|
break;
|
|
}
|
|
case 2: // ---cas ou on utilise la matrice de raideur réelle
|
|
// **** le calcul effectif de la matrice masse se fait ici
|
|
{
|
|
#ifdef UTILISATION_MPI
|
|
// 1) partie classique pour K et sm
|
|
{
|
|
mpi::request reqs1;
|
|
mpi::request reqs2;
|
|
mpi::request reqs3;
|
|
bool premier_passage = true;
|
|
|
|
#endif
|
|
mat_masse->Initialise(0.);
|
|
v_mass.Change_taille(nbddl_X);
|
|
v_mass.Zero(); // idem: v_mass1 un vecteur intermédiaire de calcul
|
|
if ( ((casMass_relax > 3) && (casMass_relax < 6)) //4-5 cas où on a besoin de deux assemblages
|
|
||((casMass_relax > 7) && (casMass_relax < 10))
|
|
)
|
|
{v_mass1.Change_taille(nbddl_X);v_mass1.Zero();};
|
|
if ((casMass_relax > 5) && (casMass_relax < 10))
|
|
matglob->Initialise(0.);
|
|
|
|
// boucle sur les elements
|
|
#ifndef UTILISATION_MPI
|
|
int nbMailMax = lesMail->NbMaillage();
|
|
// cas d'un calcul mono CPU
|
|
for (int nbMail =1; nbMail<= nbMailMax; nbMail++)
|
|
{int nemax = lesMail->Nombre_element(nbMail);
|
|
for (int ne=1; ne<= nemax;ne++)
|
|
{
|
|
#else
|
|
// cas d'un calcul multi-CPU
|
|
// on va parcourir les éléments associés au cpu
|
|
// on récupère la distribution d'éléments concernant le cpu en cours
|
|
const Tableau < list <int > >& tab_list_elem_cpu = distribution_CPU_algo.List_element_CPU_en_cours();
|
|
// la taille est identique à nbMailMax, sauf si c'est le cpu 0, là le tableau est vide et il n'y
|
|
// aura pas de boucle, (ou plutôt on sortira directement de la boucle
|
|
// le cas CPU 0 est traité à part
|
|
int nb_mail_distrib = tab_list_elem_cpu.Taille();
|
|
for (int nbMail =1; nbMail<= nb_mail_distrib; nbMail++)
|
|
{const list <int >& list_elem_cpu= tab_list_elem_cpu(nbMail); // pour simplifier
|
|
// on balaie les éléments nécessaires
|
|
list <int >::const_iterator il,ilfin=list_elem_cpu.end();
|
|
for (il = list_elem_cpu.begin();il != ilfin;il++)
|
|
{ int ne = (*il);
|
|
// on récupère un signal du process 0
|
|
tempsCalMasse.Arret_du_comptage();
|
|
temps_attente_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
if (premier_passage) {premier_passage = false;}
|
|
else // on attend que les transferts soient finis
|
|
{reqs1.wait();
|
|
reqs2.wait();
|
|
reqs3.wait();
|
|
};
|
|
temps_attente_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
|
|
#endif
|
|
//calcul de la raideur local et du residu local
|
|
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne)); // l'element
|
|
////------- debug ---
|
|
// if (ne == 15)
|
|
// cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse( ";
|
|
////resu.raid->Affiche();cout << endl;
|
|
////------ fin debug -----
|
|
|
|
Element::ResRaid resu = el.Calcul_implicit(pa);
|
|
|
|
////------- debug ---
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse( ";
|
|
//resu.raid->Affiche();cout << endl;
|
|
////------ fin debug -----
|
|
#ifndef UTILISATION_MPI
|
|
{// assemblage
|
|
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
|
|
if (casMass_relax < 2) // 0 1 : on ne retient que la diagonale
|
|
{ Ass.AssembDiagonale (v_mass,*(resu.raid),el.TableauDdl(),taN);}
|
|
else if (casMass_relax < 6) // sinon c'est la somme des valeurs absolues de la ligne
|
|
{ Ass.AssembDiagoMajorValPropre (v_mass,*(resu.raid),el.TableauDdl(),taN);}
|
|
// maintenant on s'occupe du cas où on utilise une matrice de raideur complète assemblée
|
|
else if ((casMass_relax > 5) && (casMass_relax < 10))
|
|
{if (pa.Symetrie_matrice())
|
|
Ass.AssembMatSym (*matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
|
|
else
|
|
Ass.AssembMatnonSym (*matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
|
|
}
|
|
else
|
|
{ cout << "\n *** attention le cas casMass_relax = " << casMass_relax
|
|
<< " n'est pas encore pris en compte !! se plaindre !! ";
|
|
Sortie(1);
|
|
};
|
|
|
|
// cas où on fait un deuxième assemblages
|
|
if ((casMass_relax > 3) && (casMass_relax < 6)) //4-5
|
|
{ Ass.AssembDiagonale (v_mass1,*(resu.raid),el.TableauDdl(),taN);};
|
|
};
|
|
////------- debug ---
|
|
//{cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse( ";
|
|
// cout << "\n -- info vecteur masse diagonale sur la raideur uniquement -- ";
|
|
// Coordonnee3 moy=v_mass.MinMaxMoy(true);
|
|
//};
|
|
////------ fin debug -----
|
|
#else
|
|
// cas d'un calcul parallèle, et CPU != 0
|
|
int num_process = ParaGlob::Monde()->rank();
|
|
if (num_process != 0)
|
|
{tempsCalMasse.Arret_du_comptage();
|
|
temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
DeuxEntiers num_el_et_mail(el.Num_elt(),el.Num_maillage());
|
|
// on transmet les numéros d'élément et de maillage
|
|
reqs1 = ParaGlob::Monde()->isend(0, 2401, num_el_et_mail);
|
|
// puis on transmets le vecteur résidu
|
|
reqs2 = resu.res->Ienvoi_MPI(0,2501);
|
|
//puis la matrice
|
|
reqs3 = resu.raid->Ienvoi_MPI(0, 2601);
|
|
temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
};
|
|
|
|
#endif
|
|
|
|
}; // fin boucle sur les éléments
|
|
};// fin boucle sur les maillages
|
|
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// récupération des grandeurs locales par le proc 0
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
{ // récup du nombre total d'éléments, cumul sur tous les maillages
|
|
int total_elem = distribution_CPU_algo.NB_total_element();
|
|
// on va boucler sur les éléments récupérés des différents process
|
|
// jusqu'au nombre maxi d'élément
|
|
int nb_elem_deja_calcule = 0; // init
|
|
while (nb_elem_deja_calcule < total_elem)
|
|
{ // on récupère un résultat de calcul
|
|
tempsCalMasse.Arret_du_comptage();
|
|
temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
DeuxEntiers num_el_et_mail;
|
|
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 2401, num_el_et_mail);
|
|
temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
temps_attente_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
|
|
temps_attente_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
temps_transfert_court_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
int ne = num_el_et_mail.un; // numero d'identification de l'element
|
|
int nbMail = num_el_et_mail.deux; // numéro de maillage
|
|
// d'où l'élément
|
|
ElemMeca & el = *((ElemMeca*) &lesMail->Element_LesMaille(nbMail,ne));
|
|
// récupération des conteneurs ad hoc vecteur et raideur
|
|
int source = stat.source(); // récupération du numéro de la source
|
|
Vecteur * residu = el.Conteneur_Residu();
|
|
mpi::request reqs2 = residu->Irecup_MPI(source, 2501);
|
|
Mat_pleine* raideur = el.Conteneur_raideur();
|
|
mpi::request reqs3 = raideur->Irecup_MPI(source, 2601);
|
|
temps_transfert_court_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
|
|
temps_attente_matSm.Mise_en_route_du_comptage(); // comptage cpu
|
|
reqs2.wait(); // on attend que le conteneur soit rempli
|
|
reqs3.wait(); // on attend que le conteneur soit rempli
|
|
temps_attente_matSm.Arret_du_comptage(); // fin comptage cpu
|
|
|
|
tempsCalMasse.Mise_en_route_du_comptage(); // comptage cpu
|
|
|
|
// assemblage
|
|
Tableau<Noeud *>& taN = el.Tab_noeud(); // tableau de noeuds de l'el
|
|
if (casMass_relax < 2) // 0 1 : on ne retient que la diagonale
|
|
{ Ass.AssembDiagonale (v_mass,*raideur,el.TableauDdl(),taN);}
|
|
else if (casMass_relax < 6) // sinon c'est la somme des valeurs absolues de la ligne
|
|
{ Ass.AssembDiagoMajorValPropre (v_mass,*raideur,el.TableauDdl(),taN);}
|
|
// maintenant on s'occupe du cas où on utilise une matrice de raideur complète assemblée
|
|
else if ((casMass_relax > 5) && (casMass_relax < 10))
|
|
{if (pa.Symetrie_matrice())
|
|
Ass.AssembMatSym (*matglob,*raideur,el.TableauDdl(),taN); // de la raideur
|
|
else
|
|
Ass.AssembMatnonSym (*matglob,*raideur,el.TableauDdl(),taN); // de la raideur
|
|
}
|
|
else
|
|
{ cout << "\n *** attention le cas casMass_relax = " << casMass_relax
|
|
<< " n'est pas encore pris en compte !! se plaindre !! ";
|
|
Sortie(1);
|
|
};
|
|
|
|
// cas où on fait un deuxième assemblages
|
|
if ((casMass_relax > 3) && (casMass_relax < 6)) //4-5
|
|
{ Ass.AssembDiagonale (v_mass1,*raideur,el.TableauDdl(),taN);};
|
|
tempsCalMasse.Arret_du_comptage(); // fin comptage cpu
|
|
// on incrémente le nombre d'élément traité
|
|
nb_elem_deja_calcule++;
|
|
};
|
|
//
|
|
};
|
|
}; // fin partie classique K sm
|
|
#endif
|
|
|
|
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5 )) || (permet_affichage > 2))
|
|
{// on affiche les min max du vecteur
|
|
cout << "\n -- info vecteur masse diagonale sur la raideur uniquement -- ";
|
|
Coordonnee3 moy=v_mass.MinMaxMoy(true);
|
|
};
|
|
|
|
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
////----- debug
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse ";
|
|
//{ string entete = " affichage de la matrice masse avant prise en compte du contact ";
|
|
// cout << "\n " << entete;
|
|
// v_mass.Affiche();
|
|
// cout << endl;
|
|
//};
|
|
////---fin debug
|
|
|
|
|
|
// prise en compte éventuelle de la raideur des éléments de contact
|
|
if (pa.ContactType()) // et des énergies développées pendant le contact
|
|
|
|
{
|
|
#ifdef UTILISATION_MPI
|
|
// 2) partie contact dont seuls les proc != 0 savent calculer Kloc et smloc
|
|
mpi::request reqs1;
|
|
mpi::request reqs2;
|
|
mpi::request reqs3;
|
|
bool premier_passage = true;
|
|
// mise à jour de la liste des contacts pour proc 0: il s'agit des infos minimales
|
|
// qui permettent ensuite de faire un assemblage
|
|
lesContacts->Mise_a_jour_liste_contacts_actif_interProc();
|
|
int proc_en_cours = ParaGlob::Monde()->rank();
|
|
// en // ce sont les proc i>0 qui gèrent les éléments de contact
|
|
if (proc_en_cours != 0)
|
|
{
|
|
#endif
|
|
// on récupère la liste des éléments de contact
|
|
LaLIST <ElContact>& listElContact = lesContacts->LesElementsDeContact();
|
|
LaLIST <ElContact>::iterator il,ilfin=listElContact.end();
|
|
// on gère les exceptions éventuelles en mettant le bloc sous surveillance
|
|
try
|
|
{// boucle sur les elements de contact
|
|
for (il=listElContact.begin();il != ilfin; il++)
|
|
{
|
|
if ((*il).Actif()) // on n'intervient que si le contact est actif
|
|
{
|
|
#ifdef UTILISATION_MPI
|
|
// on récupère un signal du process 0
|
|
tempsCalMasse.Arret_du_comptage();
|
|
temps_attente_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
if (premier_passage) {premier_passage = false;}
|
|
else // on regarde l'activité , car au début avant le balayage de tous les éléments des tableaux
|
|
{if (reqs1.active()) reqs1.wait(); // les requests ne sont pas alimentés
|
|
if (reqs2.active()) reqs2.wait(); // car aucun transfert n'a encore été effectué
|
|
if (reqs3.active()) reqs3.wait(); //
|
|
};
|
|
temps_attente_contact.Arret_du_comptage();
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
#endif
|
|
|
|
//calcul de la raideur locale et du residu local
|
|
ElContact& elcontact = (*il); // pour simplifier
|
|
// calcul effectif de la raideur et résidu locals
|
|
Element::ResRaid resu = elcontact.SM_K_charge_contact();
|
|
// cout << "numéro =" << ne << endl;
|
|
// (resu.res)->Affiche();
|
|
// (resu.raid)->Affiche(); //1,8,1,1,8,1);
|
|
#ifndef UTILISATION_MPI
|
|
Tableau<Noeud *>& taN = elcontact.TabNoeud_pour_assemblage(); // tableau de noeuds
|
|
// assemblage
|
|
// dans le cas où le retour est un pointeur nul, cela signifie qu'il n'y a pas de second membre et raideur calculés
|
|
if (resu.res != NULL)
|
|
{ if (casMass_relax < 2) // 0 1 : on ne retient que la diagonale
|
|
{ Ass.AssembDiagonale (v_mass,*(resu.raid),elcontact.TableauDdlCont(),taN);}
|
|
else if ((casMass_relax > 1) && (casMass_relax < 6)) // sinon c'est la somme
|
|
// des valeurs absolues de la ligne
|
|
{ Ass.AssembDiagoMajorValPropre (v_mass,*(resu.raid),elcontact.TableauDdlCont(),taN);
|
|
////--debug
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse ";
|
|
////string entete = " affichage de la matrice masse avant prise en compte du contact ";
|
|
//// cout << "\n " << entete;
|
|
//cout << "\n el contact: "; elcontact.Affiche(1);
|
|
//cout <<"\n *(resu.raid)= ";(resu.raid)->Affiche();
|
|
//// v_mass.Affiche();
|
|
// cout << endl;
|
|
////--- fin debug
|
|
}
|
|
else
|
|
{ cout << "\n *** attention le cas du contact avec le casMass_relax = " << casMass_relax
|
|
<< " (c-a-d entre 6 a 9) "
|
|
<< " n'est pas encore pris en compte !! se plaindre !! "
|
|
<< " \n --> cas de la prise en compte de la raideur des elements de contact ";
|
|
Sortie(1);
|
|
};
|
|
// cas où on fait un deuxième assemblages
|
|
if ((casMass_relax > 3) && (casMass_relax < 6)) //4-5
|
|
{ Ass.AssembDiagonale (v_mass1,*(resu.raid),elcontact.TableauDdlCont(),taN);};
|
|
};
|
|
#else
|
|
// cas d'un calcul parallèle, et CPU != 0
|
|
{// on va transmettre les infos permettant au proc 0 de récupérer
|
|
// l'élément de contact ad hoc et de préparer la place
|
|
tempsCalMasse.Arret_du_comptage();
|
|
temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
// on commence par transmettre les infos de l'élément de contact
|
|
QuatreEntiers nums;
|
|
nums.un = elcontact.Esclave()->Num_Mail();
|
|
nums.deux = elcontact.Esclave()->Num_noeud();
|
|
nums.trois = elcontact.Elfront()->NumUnique();
|
|
nums.quatre = resu.res->Taille();
|
|
if (resu.res == NULL)
|
|
// il n'y a rien de calculé, donc on définit un indicateur ad hoc
|
|
nums.quatre = -1; // ici une taille négative
|
|
// on transmet les infos permettants de récupérer l'élément de contact
|
|
reqs1 = ParaGlob::Monde()->isend(0, 2400, nums);
|
|
// puis on transmets éventuellement le vecteur résidu et raideur
|
|
if (resu.res != NULL)
|
|
{reqs2 = resu.res->Ienvoi_MPI(0,2500);
|
|
//puis la matrice
|
|
reqs3 = resu.raid->Ienvoi_MPI(0, 2600);
|
|
};
|
|
temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
};
|
|
#endif
|
|
}; //-- fin du test sur l'activité
|
|
}; //-- fin de la boucle sur les éléments de contact
|
|
} //-- fin du try
|
|
catch (ErrSortieFinale)
|
|
// cas d'une direction voulue vers la sortie
|
|
// on relance l'interuption pour le niveau supérieur
|
|
{ ErrSortieFinale toto;
|
|
throw (toto);
|
|
}
|
|
catch ( ... )
|
|
{ if (ParaGlob::NiveauImpression() >= 1)
|
|
{cout << "\n warning: exception generee par un element de contact mais dont la prise en compte "
|
|
<< " n'est pas prevu !, on ne fait rien et on continue le calcul"
|
|
<< " \n --> cas de la prise en compte de la raideur des elements de contact ";
|
|
if (ParaGlob::NiveauImpression() >= 4) cout << "\n AlgoriRelaxDyna::CalculMatriceMasse(..";
|
|
};
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
}; // fin du cas des proc i>0
|
|
#endif
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// cas du proc 0
|
|
// récupération des grandeurs locales par le proc 0
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
{ // récup du nombre total d'éléments de contact, cumulé sur tous les maillages
|
|
int total_elem_contact = lesContacts->Nb_actifs();
|
|
// on va boucler sur les éléments récupérés des différents process
|
|
// jusqu'au nombre maxi d'élément
|
|
int nb_elem_deja_calcule = 0; // init
|
|
while (nb_elem_deja_calcule < total_elem_contact)
|
|
{ // on récupère un résultat de calcul
|
|
tempsCalMasse.Arret_du_comptage();
|
|
temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
QuatreEntiers nums;
|
|
mpi::request reqs1 = ParaGlob::Monde()->irecv(mpi::any_source, 2400, nums);
|
|
temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
|
|
temps_attente_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
mpi::status stat = reqs1.wait(); // on attend que le conteneur soit rempli
|
|
temps_attente_contact.Arret_du_comptage(); // fin comptage cpu
|
|
int numMailEsclave = nums.un;
|
|
int numNoeudEsclave = nums.deux;
|
|
int numUnique = nums.trois;
|
|
int taille_res = nums.quatre;
|
|
// on ne continue que si la taille n'est pas négative
|
|
if (taille_res > 0)
|
|
{// on récupére l'élément de contact
|
|
ElContact* elcontact = lesContacts->RecupElContactActif
|
|
(numMailEsclave,numNoeudEsclave,numUnique);
|
|
if (elcontact == NULL )
|
|
{cout << "\n erreur *** en calcul parallele, le proc 0 ne parvient pas a recuperer"
|
|
<< " l'element de contact pour les infos suivantes: "
|
|
<< "\n numMailEsclave= "<< numMailEsclave
|
|
<< " numNoeudEsclave= "<< numNoeudEsclave
|
|
<< " numUnique= "<< numUnique
|
|
<< "\n la suite n'est pas possible ";
|
|
Sortie(1);
|
|
};
|
|
// récupération des conteneurs ad hoc vecteur et raideur
|
|
int source = stat.source(); // récupération du numéro de la source
|
|
|
|
// récup uniquement des conteneurs raideurs et résidu (pas forcément remplis, mais de la bonne taille)
|
|
Element::ResRaid resRaid = elcontact->Conteneur_ResRaid();
|
|
Vecteur * residu = resRaid.res;
|
|
if (residu->Taille() != taille_res )
|
|
{cout << "\n erreur *** en calcul parallele, le proc 0 ne parvient pas a recuperer"
|
|
<< " la bonne taille pour le résidu de contact avec les infos suivantes: "
|
|
<< "\n numMailEsclave= "<< numMailEsclave
|
|
<< " numNoeudEsclave= "<< numNoeudEsclave
|
|
<< " numUnique= "<< numUnique
|
|
<< "\n taille_residu transmis : "<<taille_res
|
|
<< " taille actuelle pour le proc 0 "<< residu->Taille()
|
|
<< "\n ce n'est pas normal ==> erreur "
|
|
<< "\n on arrete ";
|
|
Sortie(1);
|
|
};
|
|
|
|
temps_transfert_court_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
mpi::request reqs2 = residu->Irecup_MPI(source, 2500);
|
|
Mat_pleine* raideur = resRaid.raid;
|
|
mpi::request reqs3 = raideur->Irecup_MPI(source, 2600);
|
|
temps_transfert_court_contact.Arret_du_comptage(); // fin comptage cpu
|
|
|
|
temps_attente_contact.Mise_en_route_du_comptage(); // comptage cpu
|
|
reqs2.wait(); // on attend que le conteneur soit rempli
|
|
reqs3.wait(); // on attend que le conteneur soit rempli
|
|
temps_attente_contact.Arret_du_comptage(); // fin comptage cpu
|
|
tempsCalMasse.Mise_en_route_du_comptage();
|
|
// assemblage
|
|
Tableau<Noeud *>& taN = elcontact->TabNoeud_pour_assemblage(); // tableau de noeuds
|
|
if (casMass_relax < 2) // 0 1 : on ne retient que la diagonale
|
|
{ Ass.AssembDiagonale (v_mass,*(raideur),elcontact->TableauDdlCont(),taN);}
|
|
else if ((casMass_relax > 1) && (casMass_relax < 6)) // sinon c'est la somme
|
|
// des valeurs absolues de la ligne
|
|
{ Ass.AssembDiagoMajorValPropre (v_mass,*(raideur),elcontact->TableauDdlCont(),taN);
|
|
////--debug
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse ";
|
|
////string entete = " affichage de la matrice masse avant prise en compte du contact ";
|
|
//// cout << "\n " << entete;
|
|
//cout << "\n el contact: "; elcontact->Affiche(1);
|
|
//cout <<"\n *(resu.raid)= ";raideur->Affiche();
|
|
//// v_mass.Affiche();
|
|
// cout << endl;
|
|
////--- fin debug
|
|
|
|
}
|
|
else
|
|
{ cout << "\n *** attention le cas du contact avec le casMass_relax = " << casMass_relax
|
|
<< " (c-a-d entre 6 a 9) "
|
|
<< " n'est pas encore pris en compte !! se plaindre !! "
|
|
<< " \n --> cas de la prise en compte de la raideur des elements de contact ";
|
|
Sortie(1);
|
|
};
|
|
// cas où on fait un deuxième assemblages
|
|
if ((casMass_relax > 3) && (casMass_relax < 6)) //4-5
|
|
{ Ass.AssembDiagonale (v_mass1,*(raideur),elcontact->TableauDdlCont(),taN);};
|
|
};
|
|
// on incrémente le nombre d'élément traité
|
|
nb_elem_deja_calcule++;
|
|
};
|
|
};
|
|
#endif
|
|
|
|
|
|
}; // fin du test: if (pa.ContactType())
|
|
////----- debug
|
|
//#ifdef UTILISATION_MPI
|
|
// // la suite ne concerne que le proc 0
|
|
// if (proc_en_cours == 0)
|
|
//#endif
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculMatriceMasse ";
|
|
//{ string entete = " affichage de la matrice masse après prise en compte du contact ";
|
|
// cout << "\n " << entete;
|
|
// v_mass.Affiche();
|
|
// cout << endl;
|
|
//};
|
|
////---fin debug
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// la suite ne concerne que le proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
|
|
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5 )) || (permet_affichage > 2))
|
|
{// on affiche les min max du vecteur
|
|
cout << "\n -- info vecteur masse diagonale sur la raideur + contact -- ";
|
|
Coordonnee3 moy=v_mass.MinMaxMoy(true);
|
|
};
|
|
|
|
// --- dans le cas où on utilise la matrice de raideur réelle on calcul la diagonale
|
|
// condensée
|
|
if ((casMass_relax > 5) && (casMass_relax < 10))
|
|
{
|
|
if (casMass_relax > 7) // ici on a besoin de v_mass1
|
|
{for (int i=1;i<= nbddl_X; i++)
|
|
{v_mass(i)=0.;v_mass1(i)=0.;
|
|
Vecteur li = matglob->Ligne(i); // récup de la ligne
|
|
int taille_li = li.Taille();
|
|
for (int j=1;j<=taille_li;j++)
|
|
v_mass(i) += Dabs(li(j));
|
|
v_mass1(i) += 2. * Dabs((*matglob)(i,i));
|
|
};
|
|
}
|
|
else // on a besoin uniquement de v_mass
|
|
{for (int i=1;i<= nbddl_X; i++)
|
|
{v_mass(i)=0.;
|
|
Vecteur li = matglob->Ligne(i); // récup de la ligne
|
|
int taille_li = li.Taille();
|
|
for (int j=1;j<=taille_li;j++)
|
|
v_mass(i) += Dabs(li(j));
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
// maintenant pour certain cas, on va balayer sur la dimension (dima) les termes diagonaux de la masse
|
|
// et retenir le maxi selon les dima directions pour chaque noeud
|
|
// et ainsi construire la matrice masse correspondant à un pas de pseudo-temps critique de 1.
|
|
for (int inoeu = 1; inoeu <= nbNoe; inoeu++)
|
|
{ // on passe en revue les dima ddl, pour récupérer la raideur la plus élevée
|
|
int deb_indice = (inoeu-1)*dima; // deb_indice+1 = l'indice de x1
|
|
double raidmax = Dabs(v_mass(deb_indice+1)); // on récup la raideur (x1,x1)
|
|
for (int ix=2;ix<=dima;ix++) // on parcours les deux autres indices (si 3D), pour ne garder que la plus grande raideur
|
|
if (raidmax < Dabs(v_mass(deb_indice+ix)))
|
|
{raidmax = Dabs(v_mass(deb_indice+ix));};
|
|
// arrivée ici, raidmax contient le maxi selon les dima directions
|
|
// on calcule la matrice masse
|
|
if ((casMass_relax == 1) || (casMass_relax == 3) || (casMass_relax == 5)
|
|
|| (casMass_relax == 7) || (casMass_relax == 9)
|
|
)
|
|
{for (int jx=1;jx<=dima;jx++)
|
|
{(*mat_masse)(deb_indice+jx,deb_indice+jx) = 0.5 * lambda * raidmax;}
|
|
}
|
|
else // cas == 0 ou 2 ou 4 : dans ce cas on a une raideur différentes pour chaque direction
|
|
// == 6 ou 7
|
|
{ for (int jx=1;jx<=dima;jx++)
|
|
{(*mat_masse)(deb_indice+jx,deb_indice+jx) = 0.5 * lambda * v_mass(deb_indice+jx);}
|
|
};
|
|
};
|
|
// dans le cas casMass_relax == 4 ou 5, on utilise le maxi entre deux assemblages
|
|
// et casMass_relax == 8 ou 9
|
|
if ( (casMass_relax == 5) // pour le second second assemblage on récup le maxi sur les dima direction
|
|
|| (casMass_relax == 9)
|
|
)
|
|
{ for (int inoeu = 1; inoeu <= nbNoe; inoeu++)
|
|
{ // on passe en revue les dima ddl, pour récupérer la raideur la plus élevée
|
|
int deb_indice = (inoeu-1)*dima; // deb_indice+1 = l'indice de x1
|
|
double raidmax = v_mass1(deb_indice+1); // on récup la raideur (x1,x1)
|
|
for (int ix=2;ix<=dima;ix++) // on parcours les deux autres indices
|
|
// (si 3D), pour ne garder que la plus grande raideur
|
|
if (raidmax < v_mass1(deb_indice+ix))
|
|
{raidmax = v_mass1(deb_indice+ix);};
|
|
// arrivée ici, raidmax contient le maxi du second assemblage selon les dima directions
|
|
// maintenant pour la masse, on retiend la maxi entre les deux assemblages
|
|
for (int jx=1;jx<=dima;jx++)
|
|
(*mat_masse)(deb_indice+jx,deb_indice+jx) = DabsMaX((*mat_masse)(deb_indice+jx,deb_indice+jx)
|
|
, lambda * raidmax); // 1.*lambda et non 0.5, car on doit * 2
|
|
};
|
|
}
|
|
else if ((casMass_relax == 4) || (casMass_relax == 8) )
|
|
{ for (int i=1;i<=nbddl_X;i++) // ici on retiend simplement le maximum entre les deux assemblages
|
|
(*mat_masse)(i,i) = DabsMaX((*mat_masse)(i,i), lambda *v_mass1(i));
|
|
};
|
|
//v_mass.Affiche();
|
|
|
|
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5 )) || (permet_affichage > 2))
|
|
{// on affiche les min max du vecteur
|
|
cout << "\n -- info matrice masse finale -- ";
|
|
Coordonnee3 moy=mat_masse->MinMaxMoy(true);
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
#endif
|
|
break;
|
|
} // fin du case 2:
|
|
|
|
default:
|
|
{ cout << "\n **** erreur le cas type_calcul_mass= " << type_calcul_mass
|
|
<< "\n pour l'instant n'est pas implante "
|
|
<< "\n AlgoriRelaxDyna::CalculMatriceMasse( ... ";
|
|
Sortie(1);
|
|
};
|
|
};
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// la suite concerne seulement le process 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// prise en compte de masses ponctuelles
|
|
// ---- cas des masses concentrées -----
|
|
Algori::Ajout_masses_ponctuelles(lesMail,Ass,(*mat_masse),divStoc,lesRef,N_ddl,lesFonctionsnD);
|
|
// ---- fin cas des masses concentrées -----
|
|
|
|
// maintenant on va transférer les valeurs aux noeuds, ce qui pourra être utile pour post-traiter
|
|
v_mass.Change_taille(nbddl_X); // au cas où car il n'a pas la même dim pour les différents cas de masse
|
|
for (int i=1;i<=nbddl_X;i++)
|
|
v_mass(i) = (*mat_masse)(i,i); // on utilise v_mass comme stockage intermédiaire
|
|
lesMail->Quelconque_glob_vers_local(X1,v_mass,masseRelax_2);
|
|
|
|
// si jamais on a une masse nulle on l'affiche éventuellement
|
|
if (ParaGlob::NiveauImpression() > 0)
|
|
for (int i=1;i<=nbddl_X;i++)
|
|
{if (Abs(v_mass(i)) < ConstMath::trespetit)
|
|
{// on récupère les informations
|
|
// retrouver le ddl correspondant a un pointeur de position
|
|
// d'assemblage, le nb du noeud et du maillage
|
|
// insol = le pointeur d'assemblage;
|
|
// ddl = le ddl en sortie; a t+dt si elle il existe
|
|
// sinon la valeur a t
|
|
// casAssemb : donne le cas d'assemblage qui est a considérer
|
|
int nbNoeud=0; int nbMaillage=0; // init
|
|
Ddl toto = lesMail->NoeudIndice(i,nbNoeud,nbMaillage
|
|
,Ass.Nb_cas_assemb());
|
|
int ne = (i-1)/dima+1;int coor = i - (ne-1)*dima;
|
|
cout << "\n *** attention : le noeud "<<nbNoeud
|
|
<< " du maillage "<< nbMaillage
|
|
<<" a une masse nulle en coordonnee " << coor ;
|
|
}
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
#endif
|
|
tempsCalMasse.Arret_du_comptage();
|
|
};
|
|
|
|
|
|
// calcul de la matrice masse dans le cas de l'algorithme de relaxation dynamique avec optimisation en continu
|
|
// de la matrice masse
|
|
// force_recalcul_masse : un indicateur pour forcer le calcul éventuellement
|
|
// en retour est mis à false s'il était true en entrée
|
|
void AlgoriRelaxDyna::CalculEnContinuMatriceMasse
|
|
(const int& relax_vit_acce,LesMaillages * lesMail,Assemblage& Ass
|
|
, int compteur, const DiversStockage* divStoc,LesReferences* lesRef
|
|
,const Enum_ddl & N_ddl
|
|
,bool premier_calcul,LesContacts* lesContacts
|
|
,bool & force_recalcul_masse,LesFonctions_nD* lesFonctionsnD)
|
|
{ // on regarde en fonction de option_recalcul_mass et des parametres associés éventuels s'il faut calculer la matrice masse
|
|
bool calcul_a_effectuer = false;
|
|
// --- étude des différents cas de contrôle du recalcul de masse ---
|
|
int option_recalcul_mass_en_cours = option_recalcul_mass(1);
|
|
double epsilon = 0.;
|
|
#ifdef UTILISATION_MPI
|
|
int proc_en_cours = ParaGlob::Monde()->rank();
|
|
// partie uniquement dédiée au proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// init principal (convient s'il n'y a pas d'option spécifique visqueuse
|
|
if (fct_nD_option_recalcul_mass(1) != NULL)
|
|
{option_recalcul_mass_en_cours = (fct_nD_option_recalcul_mass(1)->Valeur_pour_variables_globales())(1);
|
|
if (option_recalcul_mass_en_cours != option_recalcul_mass(1))
|
|
{if (ParaGlob::NiveauImpression() > 2)
|
|
cout << "\n >>> changement : option_recalcul_mass "<< option_recalcul_mass(1) <<" en "
|
|
<< option_recalcul_mass_en_cours << std::flush;
|
|
option_recalcul_mass(1) = option_recalcul_mass_en_cours; // on sauvegarde par cohérence
|
|
};
|
|
};
|
|
// >> on regarde s'il y a plusieurs options
|
|
if (option_recalcul_mass.Taille() == 2)
|
|
{ // cas où on peut avoir du visqueux et/ou du cinétique
|
|
if (visqueux_activer)
|
|
{if (fct_nD_option_recalcul_mass(2) != NULL)
|
|
{option_recalcul_mass_en_cours = (fct_nD_option_recalcul_mass(2)->Valeur_pour_variables_globales())(1);
|
|
if (option_recalcul_mass_en_cours != option_recalcul_mass(2))
|
|
{if (ParaGlob::NiveauImpression() > 2)
|
|
cout << "\n >>> changement : option_recalcul_mass en visqueux "<< option_recalcul_mass(2) <<" en "
|
|
<< option_recalcul_mass_en_cours << std::flush;
|
|
option_recalcul_mass(2) = option_recalcul_mass_en_cours; // on sauvegarde par cohérence
|
|
}
|
|
}
|
|
else // sinon c'est la valeur fixe qu'il faut prendre
|
|
{option_recalcul_mass_en_cours = option_recalcul_mass(2);};
|
|
};
|
|
};
|
|
// --- fin étude des différents cas de contrôle du recalcul de masse ---
|
|
//cout << "\n option_recalcul_mass " << option_recalcul_mass_en_cours;
|
|
// on fait un premier passage pour voir si le calcul est a effectuer
|
|
switch (option_recalcul_mass_en_cours)
|
|
{case -1: // cas où la matrice est recalculée à chaque itération
|
|
{ calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 0: // cas où la matrice est calculée au début et ensuite elle est gardée constante
|
|
{ if (compteur == 0) // cas du premier calcul
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 1: // apres un calcul au debut, mise a jour a chaque maxi de l'énergie cinétique
|
|
{ if ( (compteur == 0) // cas du premier calcul
|
|
|| (relax_vit_acce == 1)) // cas où on est à un maxi de l'énergie cinétique
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 2: // idem le cas 1, mais on garde la valeur maxi de la raideur entre la nouvelle et l'ancienne
|
|
{ if ( (compteur == 0) // cas du premier calcul
|
|
|| (relax_vit_acce == 1)) // cas où on est à un maxi de l'énergie cinétique
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 3: // recalcul apres ncycles, valeur qui est indiquée par ncycle_calcul
|
|
{ if ( (compteur == 0) // cas du premier calcul
|
|
|| ((compteur % ncycle_calcul)==0) ) // cas où on est au début de ncycle_calcul
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 4: // recalcule de la matrice masse lorsque l'indicateur suivant "
|
|
// \epsilon = MAX_{i=1}^{nbddl}{ ( 0.5*lambda * (Delta t)^2) (|Delta ddot X_i|) / (|Delta X_i|) } "
|
|
// est superieur a 1*fac_epsilon "
|
|
{ int nbddl_X = delta_X.Taille();
|
|
epsilon = 0.;
|
|
for (int i=1; i<= nbddl_X;i++)
|
|
{ double denominateur = Dabs(delta_X(i));
|
|
if(denominateur > ConstMath::petit)
|
|
epsilon = MaX(epsilon,Dabs(acceleration_t(i))/denominateur);
|
|
};
|
|
epsilon *= 0.5 * lambda;
|
|
// on effectue le calcul conditionnel
|
|
if ( (compteur == 0) // cas du premier calcul
|
|
|| (epsilon > fac_epsilon) ) // cas ou la condition de recalcul est satisfaite
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
case 5: // cas où on calcule la matrice au tout début du calcul et ensuite jamais
|
|
{ if ((compteur == 0) && premier_calcul) // cas du tout premier calcul
|
|
calcul_a_effectuer = true;
|
|
break;
|
|
}
|
|
default:
|
|
{ cout << "\n **** erreur le cas option_recalcul_mass= " << option_recalcul_mass_en_cours
|
|
<< "\n pour l'instant n'est pas implante "
|
|
<< "\n AlgoriRelaxDyna::CalculEnContinuMatriceMasse( ... ";
|
|
Sortie(1);
|
|
};
|
|
break;
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
#endif
|
|
|
|
// dans le cas ou on est à la première itération, le contact est updaté et
|
|
// on peut statuer s'il y a un pb avec des conditions linéaires de contact
|
|
if (((compteur <= 1 )&&(pa.ContactType()==1)))
|
|
{// mise à jour éventuelle du type et/ou de la taille de la matrice de masse
|
|
// retourne un pointeur sur la nouvelle matrice, s'il y a eu une modification
|
|
// l'ancienne est supprimée
|
|
// sinon retour d'un pointeur NULL
|
|
// en // tous les proc doivent passer ici
|
|
Mat_abstraite* mat_inter = Mise_a_jour_type_et_taille_matrice_masse_en_explicite
|
|
(delta_X.Taille(),mat_masse,lesMail,lesRef,(Ass.Nb_cas_assemb()).n,lesContacts);
|
|
#ifdef UTILISATION_MPI
|
|
// partie uniquement dédiée au proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
if (mat_inter != NULL)
|
|
{ mat_masse = mat_inter; // c'est le nouveau stockage
|
|
// il faut dans ce cas également changer le stockage de la copie
|
|
delete (mat_masse_sauve);
|
|
mat_masse_sauve = mat_masse->NouvelElement(); // création d'un nouvel élément identique
|
|
calcul_a_effectuer=true;
|
|
}
|
|
else if (mat_masse->Place() != mat_masse_sauve->Place())
|
|
{// c'est le cas où la taille à diminuée sans changement de type de matrice
|
|
delete (mat_masse_sauve);
|
|
mat_masse_sauve = mat_masse->NouvelElement(); // création d'un nouvel élément identique
|
|
calcul_a_effectuer=true;
|
|
}
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
#endif
|
|
};
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// partie uniquement dédiée au proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// on prend en compte un cas de forçage éventuel
|
|
if (force_recalcul_masse)
|
|
{calcul_a_effectuer = true;
|
|
force_recalcul_masse = false;
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
// on transmet à tous les proc l'indicateur calcul_a_effectuer
|
|
broadcast(*ParaGlob::Monde(), calcul_a_effectuer, 0);
|
|
#endif
|
|
|
|
|
|
// on calcul la matrice masse si nécessaire
|
|
if (calcul_a_effectuer)
|
|
{ // en // tous les proc doivent passer ici
|
|
CalculMatriceMasse(relax_vit_acce,lesMail,Ass,compteur,divStoc
|
|
,lesRef,N_ddl,lesContacts,lesFonctionsnD);
|
|
#ifdef UTILISATION_MPI
|
|
// partie uniquement dédiée au proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// ici on va quand même éviter d'avoir des masses nulles sur la diagonale
|
|
// on commence par calculer la valeur moyenne
|
|
Coordonnee3 moy=mat_masse->MinMaxMoy((ParaGlob::NiveauImpression() > 3));
|
|
if ((ParaGlob::NiveauImpression() > 2) && (Dabs(moy(1))< ConstMath::petit))
|
|
{ cout << "\n warning la masse diagonale minimale est "<<moy(1)
|
|
<< " ??";
|
|
};
|
|
// on corrige la matrice masse avec le maxi ?
|
|
bool modif = false;
|
|
switch (choix_mini_masse_nul)
|
|
{case 1: modif = mat_masse->Limitation_min_diag(ConstMath::petit, moy(2)); break;
|
|
case 2: modif = mat_masse->Limitation_min_diag(ConstMath::petit, moy(3)); break;
|
|
default: // par défaut on ne fait rien
|
|
break;
|
|
};
|
|
// bool modif = mat_masse->Limitation_min_diag(ConstMath::petit, moy(1));
|
|
if (modif && (ParaGlob::NiveauImpression() > 2))
|
|
{ cout << "\n warning modification d'une masse diagonal initialement calculee a 0 "
|
|
<< " et mise a la valeur";
|
|
switch (choix_mini_masse_nul)
|
|
{case 1: cout << " maxi "; break;
|
|
case 2: cout << " moyenne "; break;
|
|
default: // par défaut on ne fait rien
|
|
break;
|
|
};
|
|
cout << " de la diag matrice = (min,max,moy= "; moy.Affiche_1(cout);
|
|
cout << ") "<< endl;
|
|
if (ParaGlob::NiveauImpression() >= 8)
|
|
{ string entete = " affichage de la matrice masse utilisee en relaxation dynamique";
|
|
cout << "\n " << entete;
|
|
mat_masse->Affiche();
|
|
cout << endl;
|
|
};
|
|
};
|
|
*mat_masse_sauve = *mat_masse;
|
|
#ifdef UTILISATION_MPI
|
|
}
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
#ifdef UTILISATION_MPI
|
|
if (proc_en_cours == 0) // partie uniquement dédiée au proc 0
|
|
#endif
|
|
*mat_masse = *mat_masse_sauve ;}; // on reprend l'ancienne sans les CL, si on n'a rien calculé
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// partie uniquement dédiée au proc 0
|
|
if (proc_en_cours == 0)
|
|
{
|
|
#endif
|
|
// info si voulu, dans le cas où option_recalcul_mass_en_cours ==-1 c'est un calcul à chaque itération donc on n'affiche rien
|
|
if ((calcul_a_effectuer && (ParaGlob::NiveauImpression() > 2)) && (option_recalcul_mass_en_cours != -1))
|
|
{ if (option_recalcul_mass_en_cours != 4)
|
|
{ cout << "\n recalcul de la pseudo-masse (type: "<< option_recalcul_mass_en_cours <<") "; }
|
|
else { cout << "\n recalcul de la pseudo-masse; epsilon=" << epsilon << endl ; };
|
|
};
|
|
|
|
// affichage éventuelle de la matrice de masse
|
|
if (ParaGlob::NiveauImpression() >= 10)
|
|
//cout << "\n debug AlgoriRelaxDyna::CalculEnContinuMatriceMasse ";
|
|
{ string entete = " affichage de la matrice masse utilisee en relaxation dynamique";
|
|
cout << "\n " << entete;
|
|
mat_masse->Affiche();
|
|
cout << endl;
|
|
};
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
#endif
|
|
};
|
|
|
|
|
|
//---- 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 AlgoriRelaxDyna::ActionInteractiveAlgo()
|
|
{ cout << "\n commande? ";
|
|
return false;
|
|
};
|
|
|
|
// sortie du schemaXML: en fonction de enu
|
|
void AlgoriRelaxDyna::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 dynamique relaxation 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;
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
// dans le cas d'une relaxation de type 4 (mixte cinétique et visqueuse, on test pour savoir
|
|
// s'il faut du visqueux ou du cinétique
|
|
// ramène true si on continue en cinétique
|
|
// false si on bascule
|
|
// force_recalcul_masse : un indicateur de retour qui s'applique uniquement si
|
|
// et_recalcul_masse_a_la_transition = 1
|
|
// et que l'on est juste à la transition, sinon il est toujours false
|
|
bool AlgoriRelaxDyna::Cinetique_ou_visqueux(bool & force_recalcul_masse)
|
|
{ bool retour = true; // init en cinétique par défaut
|
|
force_recalcul_masse = false; // init par défaut
|
|
if (visqueux_activer)
|
|
// dans le cas ou la viscosité a été activé, on ne revient pas en arrière
|
|
{Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
return false;
|
|
};
|
|
if (typeCalRelaxation==4)
|
|
{// dans le cas où il n'y a pas de fonction d'évolution, par défaut on utilise la précision
|
|
if ((niveauF_temps == NULL) && (niveauF_grandeurGlobale==NULL))
|
|
{ // on récupère le pointeur correspondant à NORME_CONVERGENCE
|
|
const void* pointe = (ParaGlob::param->GrandeurGlobal(NORME_CONVERGENCE));
|
|
TypeQuelconque* gr_quelc = (TypeQuelconque*) (pointe);
|
|
// le type est scalaire double
|
|
Grandeur_scalaire_double& gr
|
|
= *((Grandeur_scalaire_double*) gr_quelc->Grandeur_pointee()); // pour simplifier
|
|
double norme_actuelle = *(gr.ConteneurDouble());
|
|
double precision_seuil = Algori::Precision_equilibre(); // initialisation de la précision demandé
|
|
|
|
if (norme_actuelle * proportion_cinetique > precision_seuil)
|
|
retour = true; // on continue en cinétique
|
|
else
|
|
retour = false; // on demande la bascule
|
|
}
|
|
else // sinon cela signifie qu'au moins une fonction est définie
|
|
{// cas d'une dépendance au temps
|
|
if (niveauF_temps != NULL)
|
|
{ // on récupère le temps
|
|
const VariablesTemps& tempo = pa.Variables_de_temps();
|
|
double temps = tempo.TempsCourant();
|
|
// on filtre avec retour et la version int de la fonction
|
|
retour = retour && (int (niveauF_temps->C_proport()->Valeur(temps)) );
|
|
};
|
|
// cas d'une dépendance à des variables globales
|
|
if (niveauF_grandeurGlobale != NULL)
|
|
{ // on appel la fonction
|
|
Tableau <double> & tab_val = niveauF_grandeurGlobale->C_proport()->Valeur_pour_variables_globales();
|
|
// on n'utilise que la première valeur
|
|
// on filtre avec retour et la version int de la fonction
|
|
retour = retour && (int (tab_val(1)));
|
|
};
|
|
};
|
|
};
|
|
// if (ParaGlob::NiveauImpression()>2 && !retour)
|
|
// cout << "\n ==> relaxation dynamique: bascule de cinetique a visqueux " << endl;
|
|
if (retour == false)
|
|
{visqueux_activer = true; // init pour le prochain passage
|
|
if (et_recalcul_masse_a_la_transition)
|
|
force_recalcul_masse = true; // on indique que l'on vient juste de changer
|
|
if (ParaGlob::NiveauImpression() >= 1)
|
|
{ cout << "\n\n $$$$$$$$$ bascule vers amortissement visqueux $$$$$$$$ "
|
|
<< "\n $$$$$$$$$ (iteration: "<<compteur << " ) $$$$$$$$ \n" << endl ;
|
|
};
|
|
}
|
|
Transfert_ParaGlob_AMOR_CINET_VISQUEUX();
|
|
return retour;
|
|
};
|
|
|
|
|
|
// calcul du facteur lambda en fonction de ce qui est demandé (automatique ou via une fonction etc.)
|
|
double AlgoriRelaxDyna::Calcul_Lambda()
|
|
{ double retour = lambda; // init via la valeur par défaut
|
|
double retour_initial = lambda; // pour voir si on a réellement changé
|
|
bool a_changer=false; // indicateur pour savoir si on doit augmenter
|
|
// --- on regarde s'il y a une dépendance à une fonction d'évolution
|
|
if ( (niveauLambda_temps != NULL) || (niveauLambda_grandeurGlobale != NULL))
|
|
{// on a une fonction d'évolution donc on n'utilise pas le lambda_initiale
|
|
// retour = 1.; // init pour les multiplications
|
|
// dans ce cas on initialise avec la valeur initiale de lambda
|
|
retour = lambda_initial;
|
|
// on regarde s'il y a une fonction d'évolution
|
|
if (niveauLambda_temps != NULL)
|
|
{ // on récupère le temps
|
|
const VariablesTemps& tempo = pa.Variables_de_temps();
|
|
double temps = tempo.TempsCourant();
|
|
retour *= (niveauLambda_temps->C_proport()->Valeur(temps));
|
|
a_changer=true;
|
|
};
|
|
// cas d'une dépendance à des variables globales
|
|
if (niveauLambda_grandeurGlobale != NULL)
|
|
{ // on appel la fonction
|
|
Tableau <double> & tab_val = niveauLambda_grandeurGlobale->C_proport()->Valeur_pour_variables_globales();
|
|
double facteur = tab_val(1); // pour simplifier
|
|
if (facteur != 1.) // cela veut qu'il y a du changement voulu
|
|
{ a_changer=true;
|
|
retour *= facteur;
|
|
};
|
|
};
|
|
};
|
|
// --- on regarde s'il y a une gestion automatique de lambda
|
|
if (pilotage_auto_lambda)
|
|
{int iter_maxi = 25; // une limite arbitraire pour l'instant figé
|
|
|
|
|
|
bool a_augmenter=false; // indicateur pour savoir si on doit augmenter
|
|
// on va parcourir les itérations de relaxation
|
|
List_io<int>::iterator ili,ilifin=list_iter_relax.end();
|
|
|
|
// l'idée est d'explorer sur 5*5 iter = 25,
|
|
|
|
// si on a 1 relax tous les 2 iter, 3 fois à suivre, cela veut dire que l'on a 3 relax sur 6 iter
|
|
// et donc 3 enregistrements tel que le (3ième - le premier) < 5 par exemple
|
|
// ex de suite: 14, 12, 10 --> 14-10 = 4 < 7
|
|
// si on a moins de 3 relax on sort
|
|
|
|
// idem pour 1 relax tous les 3 iter, 3 fois à suivre
|
|
// ex: 19, 16, 13 --> 19-13 = 6 < 10
|
|
|
|
// idem pour 1 relax tous les 3 iter, 4 fois à suivre
|
|
// ex: 17, 14, 11, 8 --> 17-8 = 9 < 21
|
|
|
|
if (list_iter_relax.size() > 3)
|
|
{ili=list_iter_relax.begin();
|
|
int incre_deb = *ili; // c'est le plus grand car on empile par l'avant
|
|
|
|
int compt_1R_2iter = 1;
|
|
for (;ili != ilifin; ili++,compt_1R_2iter++)
|
|
{ if (compt_1R_2iter == 3)
|
|
{if ((incre_deb - (*ili)) < 7)
|
|
{// on doit augmenter lambda
|
|
retour += delta_lambda;
|
|
// il faut que l'on supprime tous les éléments qui sont sup et = à iter
|
|
// peut-être pas suffisant list_iter_relax.erase(ili,ilifin);
|
|
a_augmenter = a_changer = true;
|
|
//--- debug
|
|
//cout << "\n debug AlgoriRelaxDyna::Calcul_Lambda() " << lambda << " --> " << retour ;
|
|
//--- fin debug
|
|
};
|
|
};
|
|
if (compt_1R_2iter == 4)
|
|
{if ((incre_deb - (*ili)) < 10)
|
|
{// on doit augmenter lambda
|
|
retour += delta_lambda;
|
|
// il faut que l'on supprime tous les éléments qui sont sup et = à iter
|
|
// peut-être pas suffisant list_iter_relax.erase(ili,ilifin);
|
|
a_augmenter = a_changer = true;
|
|
//--- debug
|
|
//cout << "\n debug AlgoriRelaxDyna::Calcul_Lambda() " << lambda << " --> " << retour ;
|
|
//--- fin debug
|
|
};
|
|
};
|
|
if (compt_1R_2iter == 5)
|
|
{if ((incre_deb - (*ili)) < 21)
|
|
{// on doit augmenter lambda
|
|
retour += delta_lambda;
|
|
// il faut que l'on supprime tous les éléments qui sont sup et = à iter
|
|
// peut-être pas suffisant list_iter_relax.erase(ili,ilifin);
|
|
a_augmenter = a_changer = true;
|
|
//--- debug
|
|
//cout << "\n debug AlgoriRelaxDyna::Calcul_Lambda() " << lambda << " --> " << retour ;
|
|
//--- fin debug
|
|
};
|
|
};
|
|
|
|
// si on a augmenté,
|
|
if (a_augmenter)
|
|
{ list_iter_relax.clear(); // en test pour l'instant car c'est radical
|
|
break;
|
|
}
|
|
|
|
};
|
|
|
|
// si on a plus d'incrément que le nombre limite, on supprime les 3 plus vieux
|
|
if (list_iter_relax.size() > iter_maxi)
|
|
for (int j= 1; j<=3;j++)
|
|
{ili=list_iter_relax.end(); ili--;
|
|
list_iter_relax.erase(ili);
|
|
};
|
|
|
|
}
|
|
else if (list_iter_relax.size() == 2)
|
|
// sinon cas de 2 éléments, on supprime éventuellement les éléments s'ils sont trop éloignés
|
|
{ ili=list_iter_relax.begin();
|
|
int incre_deb = *ili;
|
|
ili++;
|
|
if ((incre_deb - (*ili)) > iter_maxi)
|
|
list_iter_relax.erase(ili);
|
|
};
|
|
// on regarde les mini et maxi
|
|
if (retour > lambda_max) retour = lambda_max;
|
|
if (retour < lambda_min) retour = lambda_min;
|
|
};
|
|
|
|
// si on a augmenté,
|
|
if ((a_changer)&&(retour != retour_initial))
|
|
{ if (ParaGlob::NiveauImpression() >= 1)
|
|
{ cout << "\n modification de lambda " << lambda << " --> " << retour
|
|
<<" (delta= "<< (retour-retour_initial)<<") " ;
|
|
};
|
|
};
|
|
|
|
// retour
|
|
return retour;
|
|
};
|
|
|
|
|
|
|
|
// fonction virtuelle permettant de mettre à jour les infos aux noeuds
|
|
// à cause de certains contact (ex: cas_contact = 4)
|
|
// Les vecteurs Xtdt et Vtdt sont mis à jour par la méthode
|
|
// la vitesse locale du noeud est mis à jour en fonction de la position locale et de l'algo
|
|
void AlgoriRelaxDyna::Repercussion_algo_sur_cinematique(LesContacts* lesContacts,Vecteur& Xtdt,Vecteur& Vtdt)
|
|
{ // on récupère la liste des noeuds éventuellement modifiés par le contact
|
|
list <Noeud * > li_noe; // init
|
|
lesContacts->Liste_noeuds_position_changer(li_noe);
|
|
// maintenant on parcours la liste (qui peut-être vide )
|
|
list <Noeud * >::iterator il,ilfin = li_noe.end();
|
|
for (il = li_noe.begin();il != ilfin; il++)
|
|
{Noeud & noe = *(*il); // pour simplifier
|
|
const Coordonnee& Mtdt = noe.Coord2(); // récup des positions
|
|
const Coordonnee& Mt = noe.Coord1();
|
|
//cout << "\n Mtdt: "<< Mtdt << ", Mt: "<< Mt;
|
|
int dim = Mtdt.Dimension();
|
|
int nb_assemb = (Ass1_->Nb_cas_assemb()).n; // cas d'assemblage pour les X mais
|
|
// qui correspond à la même position
|
|
// dans le vecteur global que les vitesses
|
|
// on met à jour localement les vitesse, et globalement positions et vitesses
|
|
switch (dim)
|
|
{ case 3:if (!(noe.Ddl_fixe(X3)))
|
|
{ double v3 = Mtdt(3) - Mt(3);
|
|
noe.Change_val_tdt(V3,v3);
|
|
int posi = noe.Pointeur_assemblage(X3,nb_assemb);
|
|
Xtdt(posi) = Mtdt(3); Vtdt(posi) = v3;
|
|
}
|
|
case 2:if (!(noe.Ddl_fixe(X2)))
|
|
{ double v2 = Mtdt(2) - Mt(2);
|
|
noe.Change_val_tdt(V2,v2);
|
|
int posi = noe.Pointeur_assemblage(X2,nb_assemb);
|
|
//cout << "\n posi= "<<posi<< " Mtdt(2)="<<Mtdt(2);
|
|
Xtdt(posi) = Mtdt(2); Vtdt(posi) = v2;
|
|
}
|
|
case 1:if (!(noe.Ddl_fixe(X1)))
|
|
{ double v1 = Mtdt(1) - Mt(1);
|
|
noe.Change_val_tdt(V1,v1);
|
|
int posi = noe.Pointeur_assemblage(X1,nb_assemb);
|
|
Xtdt(posi) = Mtdt(1); Vtdt(posi) = v1;
|
|
}
|
|
default:
|
|
break;
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|