Herezh_dev/Algo/AlgoRef/Algori3.cc
Gérard Rio ce2d011450 - mise en place calcul parallèle (MPI) dans algo RD
- idem pour le calcul des second membres (Algori)
- idem pour le chargement pression en explicite
- tests ok pour calcul MPI en RD avec pression
2023-09-03 10:10:17 +02:00

2356 lines
131 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.h"
#include "string"
#include "MathUtil.h"
#include <iostream> // pour utiliser la classe istrstream
#include <strstream> // nouveau dans CW5.3
//======================================================================================================
// troisième fichier pour l'implantation des méthodes d'Algori
//======================================================================================================
// lecture des paramètres du calcul généraux pour tous les algos (dans le cas où il y en a)
// qui peuvent éventuellement ne pas servir !!
void Algori::lecture_Parametres(UtilLecture& entreePrinc)
{ bool a_lire = false;
MotCle motCle; // ref aux mots cle
// dans le cas où l'entête des paramètres n'a pas été lue par l'algorithme spécifique
// on regarde s'il existe
if (deja_lue_entete_parametre == 2)
// on peut directement lire
{a_lire = true;}
else // sinon
{ // deux cas suivant que l'algo spécifique a une méthode de lecture de paramètre ou non
if (deja_lue_entete_parametre == 0)
{ // cas ou l'algo spécifique n'a pas de méthode de lecture de paramètre donc il n'y a pas
// eu d'essai de lecture de l'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 une zone de paramètre éventuellement à lire
if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL)
{entreePrinc.NouvelleDonnee();
a_lire = true;
}
else // sinon le mot clé ne concerne pas les paramètres il n'y a rien n'a lire
{a_lire = false;
};
}
else if (deja_lue_entete_parametre == 1)
{ // cas ou l'algo spécifique a une méthode de lecture de paramètre donc il a
// déjà essayer de lire l'entête et n'a rien trouvé: il n'y a rien n'a lire
a_lire = false;
}
else
{ cout << "\n erreur deja_lue_entete_parametre = " << deja_lue_entete_parametre
<< " alors qu'il devrait etre soit 1 ou 0 ou 2 !! "
<< "\n Algori::lecture_Parametres(....";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
// maintenant on lit en fonction du booléen a_lire
if (a_lire)
{// on s'arrête lorsqu'il n'y a plus de mot clé spécifique à lire
while ( (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL)
|| (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL)
|| (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL)
|| (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL)
|| (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL)
|| (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL)
|| (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL)
)
{bool lecture_effective = false;
string nom_class_methode("Algori::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
//=== parametres de controle du calcul de la matrice de viscosite =====
if (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL)
{ mot_cle="parametre_calcul_de_la_viscosite_";
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_viscosite_"
// 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_calcul_visqu_critique
int_defaut=0; mot_cle="type_calcul_visqu_critique="; min=1;max=3;
entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,type_calcul_visqu_critique);
// on change le paramètre de viscosité numérique général en conséquence
if (type_calcul_visqu_critique)
pa.Change_amort_visco_artificielle(4); // on indique qu'il s'agit d'une gestion par un amortissement visqueux critique
// utilisé par de la relaxation dynamique
// --- lecture éventuelle de opt_cal_C_critique
int_defaut=-1; mot_cle="opt_cal_C_critique="; min=-1;max=2;
entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,opt_cal_C_critique);
// --- lecture éventuelle de f_
double_defaut=1.; mot_cle="f_="; min=1;max=0;
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,f_);
// --- lecture éventuelle de ampli_visco
double_defaut=1.; mot_cle="ampli_visco_="; min=1;max=0;
entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,ampli_visco);
};
// else // sinon on met les valeurs par défaut
// { type_calcul_visqu_critique= 0;
// opt_cal_C_critique= 1; f_= 1.; ampli_visco= 1.;
// };
//=== cas où l'on veut de l'amortissement cinétique global avec éventuellement des paramètres particuliers de contrôle
if (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL)
{ mot_cle="avec_amortissement_cinetique_";
entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
amortissement_cinetique=true; // on active l'amortissement cinétique
string st1;
// lecture des paramètres de l'amortissement cinétique
while (st1 != "fi_parametre_amortissement_cinetique_")
{ entreePrinc.NouvelleDonnee();
*(entreePrinc.entree) >> st1;
if (st1 == "max_nb_decroit_pourRelaxDyn_")
{*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn; }
else if (st1 == "inter_nb_entre_relax_")
{// il faut que l'on regarde s'il y a éventuellement un remplacement par une
// fonction nD
if (strstr(entreePrinc.tablcar,"nom_fct_nD_inter_nb_entre_relax_")!=NULL)
{mot_cle="nom_fct_nD_inter_nb_entre_relax_";
entreePrinc.Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_fct_nD_inter_nb_entre_relax);
}
else // cas sans fonction nD
{nom_fct_nD_inter_nb_entre_relax="";
*(entreePrinc.entree) >> inter_nb_entre_relax;
};
}
else if (st1 == "taille_moyenne_glissante_")
{*(entreePrinc.entree) >> taille_moyenne_glissante;}
else if (st1 == "test_fraction_energie_")
{*(entreePrinc.entree) >> test_fraction_energie;}
else if (st1 == "coef_arret_pourRelaxDyn_")
{*(entreePrinc.entree) >> coef_arret_pourRelaxDyn; }
else if (st1 == "coef_redemarrage_pourRelaxDyn_")
{*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn; }
else if (st1 == "max_deltaX_pourRelaxDyn_")
{*(entreePrinc.entree) >> max_deltaX_pourRelaxDyn; }
else if (st1 == "nb_max_dX_OK_pourRelaxDyn_")
{*(entreePrinc.entree) >> nb_max_dX_OK_pourRelaxDyn; }
else if (st1 == "nb_deb_testfin_pourRelaxDyn_")
{*(entreePrinc.entree) >> nb_deb_testfin_pourRelaxDyn; }
else if (st1 == "nb_deb_test_amort_cinetique_")
{*(entreePrinc.entree) >> nb_deb_test_amort_cinetique;};
if ((st1 != "max_nb_decroit_pourRelaxDyn_")
&& (st1 != "inter_nb_entre_relax_")
&& (st1 != "taille_moyenne_glissante_")
&& (st1 != "test_fraction_energie_")
&& (st1 != "coef_arret_pourRelaxDyn_")
&& (st1 != "coef_redemarrage_pourRelaxDyn_")
&& (st1 != "max_deltaX_pourRelaxDyn_")
&& (st1 != "nb_max_dX_OK_pourRelaxDyn_")
&& (st1 != "nb_deb_testfin_pourRelaxDyn_")
&& (st1 != "nb_deb_test_amort_cinetique_")
&& (st1 != "fi_parametre_amortissement_cinetique_"))
{ cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique"
<< "\n on attendait un mot cle , au lieu de " << st1
<< "\n Algori::lecture_Parametres( ... ";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
// préparation pour une nouvelle donnée
lecture_effective= true;
};
//=== idem mais pour de l'amortissement cinétique à chaque noeud
if (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL)
{ mot_cle="avec_au_noeud_amortissement_cinetique_";
entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle);
amortissement_cinetique_au_noeud=true; // on active l'amortissement cinétique
string st1;
// lecture des paramètres de l'amortissement cinétique
while (st1 != "fi_parametre_au_noeud_amortissement_cinetique_")
{ entreePrinc.NouvelleDonnee();
*(entreePrinc.entree) >> st1;
if (st1 == "max_nb_decroit_pourRelaxDyn_noe_")
{*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn_noe; }
else if (st1 == "coef_arret_pourRelaxDyn_noe_")
{*(entreePrinc.entree) >> coef_arret_pourRelaxDyn_noe; }
else if (st1 == "coef_redemarrage_pourRelaxDyn_noe_")
{*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn_noe; }
else if (st1 == "nb_deb_test_amort_cinetique_noe_")
{*(entreePrinc.entree) >> nb_deb_test_amort_cinetique_noe;};
if ((st1 != "max_nb_decroit_pourRelaxDyn_noe_")
&& (st1 != "coef_arret_pourRelaxDyn_noe_")
&& (st1 != "coef_redemarrage_pourRelaxDyn_noe_")
&& (st1 != "nb_deb_test_amort_cinetique_noe_")
&& (st1 != "fi_parametre_au_noeud_amortissement_cinetique_"))
{ cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique"
<< "\n on attendait un mot cle , au lieu de " << st1
<< "\n Algori::lecture_Parametres( ... ";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage();
if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage();
Sortie(1);
};
};
// préparation pour une nouvelle donnée
lecture_effective= true;
};
//=== contrôle éventuel d'un arrêt sur équilibre statique
if (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL)
{ // on commence par regarder si l'on est en dynamique, si non on met un warning
if (Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE)
cout << "\n *** Attention, on demande un arret sur l'equilibre statique, (cf. para de l'algo) "
<< " alors que l'algorithme n'est pas dynamique ?????? il y a peut-etre une erreur de parametres " << endl;
// --- lecture éventuelle de opt_cal_C_critique
int_defaut=0; mot_cle="ARRET_A_EQUILIBRE_STATIQUE_"; min=0;max=2; lecture_effective= false;
lecture_effective = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,arret_a_equilibre_statique);
// sert aussi en fait pour retirer éventuellement la partie visqueuse numérique
};
//=== contrôle d'un mode débug éventuel
// cas où le paramètre de mode débug existe
if (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL)
{ int_defaut=0; mot_cle="mode_debug_=";min=1;max=ConstMath::tresgrand;
{ bool lec_eff = entreePrinc.Lecture_un_parametre_int
(int_defaut,nom_class_methode,min,max,mot_cle,mode_debug);
lecture_effective = lecture_effective || lec_eff;
};
};
//=== contrôle d'un niveau de commentaire spécifique à l'algo
if (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL)
{ int_defaut=0; mot_cle="permet_affichage_";min=1;max=ConstMath::tresgrand;
{ bool lec_eff = entreePrinc.Lecture_un_parametre_int
(int_defaut,nom_class_methode,min,max,mot_cle,permet_affichage);
lecture_effective = lecture_effective || lec_eff;
};
};
//=== cas où on veut moduler la précision de la convergence globale via une fct nD
if (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL)
{ mot_cle="modulation_precision_equilibre_=";
{ bool lec_eff = entreePrinc.Lecture_mot_cle_et_string
(nom_class_methode,mot_cle,nom_modulation_precision);
lecture_effective = lecture_effective || lec_eff;
};
};
if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar)))
{entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante
lecture_effective=false;
};
};
// si le paramètre est activé, on définit le vecteur intermédiaire de sauvegarde du résidu statique
// un pb cependant, la lecture de l'amortissement artificielle n'est éventuellement pas encore fait
// c'est le cas d'une première lecture du .info, l'amortissement visqueux s'effectue au niveau des paramètres
// de contrôle donc bien après l'algo, dans ce cas il faut prévoir dans l'initialisation des algo spécifiques
// le dimensionnement de vglob_stat
if ( (arret_a_equilibre_statique ) // le dimensionnement se fera à l'affectation (=)
&& (type_calcul_visqu_critique || pa.Amort_visco_artificielle()))
{ if (vglob_stat == NULL) vglob_stat = new Vecteur();}
else // dans le cas on ne veut pas un arret statique spécifique sans viscosité numérique
{ if (vglob_stat != NULL) {delete vglob_stat; vglob_stat=NULL ;};};
// on se positionne éventuellement sur le prochain mot clé si on n'y est pas déjà
while ( !motCle.SimotCle(entreePrinc.tablcar))
entreePrinc.NouvelleDonnee();
}; //-- fin du cas où on a regardé
};
// création d'un fichier de commande: cas des paramètres spécifiques
// par défaut on indique qu'il n'y a pas de paramètres.
void Algori::Info_com_parametres(UtilLecture& entreePrinc)
{ // écriture dans le fichier de commande
ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
cout << "\n# exemple para facultatifs generaux d'algorithme (rep o ou n defaut) ? ";
string rep;
rep = "_";
// procédure de lecture avec prise en charge d'un retour chariot
rep = lect_return_defaut(true,"n");
// si la taille de rep == 0 cela veut dire que c'est un retour chariot
if (rep.size()==0)
{rep = "n";
cout << "--> valeur par defaut : n "<<endl;
};
if ((rep == "o") || (rep == "O") ||(rep == "0"))
{ rep=" "; // init
while ((Minuscules(rep) != "f")&&(Minuscules(rep) != "0"))
{
try
{
cout
<< "\n (0 ou f) (fin) "
<< "\n (1) amortissement cinetique "
<< "\n (2) calcul d'une matrice de viscosite numerique "
<< "\n pour de l'amortissement critique par exemple "
<< "\n (3) parametres supplementaires de controle du type d'arret de l'algo "
<< "\n (4) parametres de controle du mod debug "
<< "\n (5) def de fichiers externes contenant des contraintes, deformations ..."
<< "\n preexistantes avant le debut du calcul "
<< "\n (6) niveau de commentaire specifique aux algos "
<< "\n ";
// procédure de lecture avec prise en charge d'un retour chariot
rep = lect_return_defaut(false,"f");
if ((Minuscules(rep) == "f") || (Minuscules(rep) == "0"))// sortie directe
break;
int num = ChangeEntier(rep);
bool choix_valide=false;
if ((num >= 0)&&(num< 7))
{ choix_valide=true; }
else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour arreter le programme";
choix_valide=false;
}
switch (num)
{ case 0: //fin
{ break;} // normalement cela a déjà été filtré avant
case 1: // amortissement cinetique
{
sort << "\n#---------------------------------------------------------------------"
<< "\n| parametres communs a differents algorithmes (voir doc specifique) |"
<< "\n#---------------------------------------------------------------------"
<< "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # --- parametres de controle du calcul de l'amortissement cinetique --- "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # Il est possible de prendre en compte un amortissement cinetique, dont l'objectif "
<< "\n # est d'obtenir une solution statique a l'aide d'un algorithme dynamique."
<< "\n # Pour cela on introduit le mot cle: avec_amortissement_cinetique_ suivi "
<< "\n # de mots cles eventuels qui precisent des parametres. Ce groupe de parametres "
<< "\n # se termine par le mot cle fi_parametre_amortissement_cinetique_ "
<< "\n # Chaque parametre est suivi d'un nombre. Chaque parametre + nombre, doit etre sur une ligne a part."
<< "\n # deux techniques pour appliquer le test, qui conduit a mettre les vitesses à 0 "
<< "\n # 1) on regarde si l'|energie cinetique| diminue n1 fois (consécutives) "
<< "\n # ou est inferieure n1 fois fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle "
<< "\n # NB: le test ne se declanche que lorsque l'on a scrute au moins n1 valeurs de l'energie cinetique "
<< "\n # 2) on regarde si la moyenne glissante de n2 |energie cinetique| consecutive diminue n1 fois (consecutives) "
<< "\n # ou est inferieure n1 fois fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle "
<< "\n # NB: le test ne se declanche que lorsque l'on a au moins n2 valeurs consecutives disponibles de l'energie cinetique "
<< "\n # NB: le cas 1) est en fait un cas particulier du 2) pour lequel n2 == 1 "
<< "\n # Les parametres sont: "
<< "\n # max_nb_decroit_pourRelaxDyn_ : nombre n2 de diminution de de la moyenne glissante de l'energie cinetique a"
<< "\n # (Par exemple si = 3, cela signifie qu'il faut attendre 3 baisses de "
<< "\n # l'energie cinetique pour valider la relaxation. Ces 3 baisses peuvent apparaître au "
<< "\n # cours de n iterations, n etant plus grand que 3 ! De plus pendant ces en iterations,"
<< "\n # on peut egalement avoir des elevations de l'energie cinetique suivi de diminutions."
<< "\n # Seules les diminutions sont prises en compte. Apres une relaxation, le compteur de "
<< "\n # diminution est remis à 0 "
<< "\n # )"
<< "\n # partir de laquelle on met les vitesses a 0 "
<< "\n # inter_nb_entre_relax_ : intervalle autorise entre deux relaxation "
<< "\n # (Par exemple si = 10, cela signifie qu'apres une relaxation, une nouvelle relaxation"
<< "\n # ne sera accepte qu'apres 10 nouvelles iterations. "
<< "\n # Il est egalement possible de remplacer la valeur numerique par le resultat d'une fonction nD "
<< "\n # pour cela on indique le mot cle : nom_fct_nD_inter_nb_entre_relax_ "
<< "\n # suivi du nom de la fonction nD qui sera appelee a chaque fois que l'on aura besoin "
<< "\n # du parametre inter_nb_entre_relax_ "
<< "\n # )"
<< "\n # taille_moyenne_glissante_ : valeur du nombre n2 de la moyenne glissante d'energie cinetique "
<< "\n # test_fraction_energie_ : si diff de 0, indique la valeur de fraction "
<< "\n # coef_arret_pourRelaxDyn_ : arret de l'amortissement lorsque l'energie cinetique est"
<< "\n # inferieur à ce coef * le dernier pic d'energie cinetique "
<< "\n # coef_redemarrage_pourRelaxDyn_ : redemarrage de l'amortissement lorsque l'energie cinetique"
<< "\n # est sup a ce coef * le maxi des pic d'energie enregistre"
<< "\n # max_deltaX_pourRelaxDyn_ : limite inferieur de delta x_(t->tdt) a partir de laquelle"
<< "\n # on arrete le calcul"
<< "\n # nb_max_dX_OK_pourRelaxDyn_ : nombre de fois que le critere precedent doit etre satisfait"
<< "\n # pour que le calcul s'arrete"
<< "\n # nb_deb_testfin_pourRelaxDyn_ : le nombre mini de passage dans l'amortissement, a partir duquel on test la fin"
<< "\n # nb_deb_test_amort_cinetique_ : le nombre mini d'iteration, a partir duquel on demarre l'algorithme"
<< "\n # fi_parametre_amortissement_cinetique_ : mot cle obligatoire indiquant la fin des parametres"
<< "\n # exemple de declaration"
<< "\n # "
<< "\n # avec_amortissement_cinetique_ "
<< "\n # max_nb_decroit_pourRelaxDyn_ 1 "
<< "\n # inter_nb_entre_relax_ 1 "
<< "\n # ou "
<< "\n # inter_nb_entre_relax_ nom_fct_nD_inter_nb_entre_relax_ toto "
<< "\n # taille_moyenne_glissante_ 1 "
<< "\n # coef_arret_pourRelaxDyn_ 0. "
<< "\n # coef_redemarrage_pourRelaxDyn_ 0.01 "
<< "\n # max_deltaX_pourRelaxDyn_ 0.4 "
<< "\n # nb_max_dX_OK_pourRelaxDyn_ 5 "
<< "\n # nb_deb_testfin_pourRelaxDyn_ 100 "
<< "\n # nb_deb_test_amort_cinetique_ 100 "
<< "\n # fi_parametre_amortissement_cinetique_ "
<< "\n # "
<< endl;
break;}
case 2: // calcul d'une matrice de viscosite numerique
{
sort << "\n#---------------------------------------------------------------------"
<< "\n| parametres communs a differents algorithmes (voir doc specifique) |"
<< "\n#---------------------------------------------------------------------"
<< "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # --- parametres de controle du calcul de la matrice de viscosite --- "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # Il est possible de prendre en compte de l'amortissement critique numerique "
<< "\n # classiquement utilise dans le cas de la relaxation dynamique "
<< "\n # "
<< "\n # ** PARAMETRES FACULTATIF ** "
<< "\n # on indique tout d'abord le mot cle : parametre_calcul_de_la_viscosite_ suivi des parametres associes eventuelles "
<< "\n # type_calcul_visqu_critique= suivi du type de calcul "
<< "\n # si type_calcul_visqu_critique= 1 : la matrice C est calculee selon: C_{ii} = c * M_{ii} avec c = 2 * omega_0 "
<< "\n # si type_calcul_visqu_critique= 2 : la matrice C est calculee selon: C_{ii} = c * M_{ii} "
<< "\n # avec c = sqrt( 4*omega_0^2 - omega_0^4)"
<< "\n # si type_calcul_visqu_critique= 3 : la matrice C est calculee selon: C_{ii} = c * M_{ii} "
<< "\n # avec c = 2*sqrt(omega_0/(1+omega_0)) "
<< "\n # "
<< "\n # puis il y a un choix via le parametre opt_cal_C_critique= "
<< "\n # opt_cal_C_critique= 0 : (omega_0)^2 \approx (Delta X^T Delta R_{i(statique)}^n) / (Delta X^T M Delta X) "
<< "\n # opt_cal_C_critique= 1 : (omega_0)^2 \approx (dot X^T Delta R_{i(statique)}^n) / (dot X^T M dot X) "
<< "\n # "
<< "\n # a) si (omega_0)^2 est négative on met omega_0^2=0 "
<< "\n # b) si (omega_0)^2 > f^2 * 4, on pose (omega_0) = f^2 * 4, par defaut: f= 0.9 "
<< "\n # on peut changer la valeur de f avec le parametre: f_= suivi de la valeur "
<< "\n # "
<< "\n # il est possible egalement d'amplifier la valeur de la viscosite calculee (avec cependant toujours les limites a) et b) "
<< "\n # ampli_visco_= val_ampli "
<< "\n # "
<< "\n # Exemple de declaration: "
<< "\n ## parametre_calcul_de_la_viscosite_ type_calcul_visqu_critique= 1 opt_cal_C_critique= 0 f_= 1.3 "
<< "\n # "
<< "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: "
<< "\n # opt_cal_C_critique= 1 ; f_= 0.9 ; ampli_visco_= 1.; "
<< "\n # "
<< "\n # "
<< endl;
break;}
case 3: // parametres supplementaires de controle du type d'arret de l'algo
{
sort << "\n#---------------------------------------------------------------------"
<< "\n| parametres communs a differents algorithmes (voir doc specifique) |"
<< "\n#---------------------------------------------------------------------"
<< "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
<< "\n # apres l'amortissement cinetique, apres la def de calcul de viscosite et les autres qui precedent!!! "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # --- parametres de controle du type d'arret --- "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # ce parametre est utile dans le cas d'un calcul dynamique "
<< "\n # on peut egalement indiquer un arret correspondant a un equilibre statique. Dans ce cas "
<< "\n # le calcul s'arrete lorsqu'on considere que l'on a atteind un regime statique dont le critere est:"
<< "\n # - le residu statique est inferieur au maxi indique dans les parametres generaux de controle"
<< "\n # - si l'on utilise de l'amortissement cinetique: le critere d'arret est celui de cet algo"
<< "\n # Pour activer cette possibilite d'arret il faut indiquer sur la ligne qui suit le mot cle"
<< "\n # ARRET_A_EQUILIBRE_STATIQUE_ suivant d'un nombre "
<< "\n # ARRET_A_EQUILIBRE_STATIQUE_ 1 signifie que le residu statique est utilise comme critere"
<< "\n # ARRET_A_EQUILIBRE_STATIQUE_ 2 le residu statique et le critere de l'amortissement cinetique "
<< "\n # sont conjointement utilises, on retient le plus defavorable"
<< "\n # ARRET_A_EQUILIBRE_STATIQUE_ 0 pas de prise en compte de ce parametre (valeur par defaut)"
<< "\n # "
<< "\n # exemple d'utilisation "
<< "\n # "
<< "\n # ARRET_A_EQUILIBRE_STATIQUE_ 1 "
<< "\n # "
<< endl;
break;}
case 4: // parametres de controle du mod debug
{
sort << "\n#---------------------------------------------------------------------"
<< "\n| parametres communs a differents algorithmes (voir doc specifique) |"
<< "\n#---------------------------------------------------------------------"
<< "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
<< "\n # apres les parametres de controle de type d'arret et les autres qui precedent !!! "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # --- parametres de controle du mode debug --- "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # ** PARAMETRES FACULTATIF ** "
<< "\n # mode_debug_= parametre de debug (= 0 par defaut -> calcul classique) "
<< "\n # = n : a chaque n iteration on sort une visualisation "
<< "\n ## mode_debug_= 0 # a mettre apres les para de relaxation "
<< "\n # "
<< "\n # modulation_precision_equilibre_= fonction_nD "
<< "\n # la fonction fonction_nD module par multiplication, la precision en cours "
<< "\n # **important**: ces parametres doivent etre mis chacun sur une ligne differente "
<< endl;
break;}
case 5: // def de fichiers externes contenant des contraintes, deformations ...
{
sort << "\n # --------------------------------------------------------------------------------- "
<< "\n # --- lecture sur fichiers externes de grandeurs preexistantes au calcul --- "
<< "\n # --------------------------------------------------------------------------------- "
<< "\n # ce referer a la doc pour la syntaxe dans les fichiers \n"
<< "\n flotExterne #--- # mot cle pour introduire la lecture \n";
string repi= " "; // init
rep=" "; // init
while ((Minuscules(repi) != "f")&&(Minuscules(repi) != "0"))
{
try
{
cout
<< "\n (0 ou f) (fin) "
<< "\n (1) nouveau fichier de contraintes aux point d'integration "
<< "\n (2) nouveau fichier de deplacement aux noeuds "
<< "\n ";
// procédure de lecture avec prise en charge d'un retour chariot
repi = lect_return_defaut(false,"f");
if ((Minuscules(repi) == "f") || (Minuscules(repi) == "0"))// sortie directe
break;
int numi = ChangeEntier(repi);
bool choix_valide=false;
if ((numi >= 0)&&(numi<=2))
{ choix_valide=true; }
else { cout << "\n Erreur on attendait un entier entre 0 et 2 !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour arreter le programme";
choix_valide=false;
}
switch (numi)
{ case 0: //fin
{ break;} // normalement cela a déjà été filtré avant
case 1: // nouveau fichier de contraintes aux point d'integration
{ string nom;
cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _cab.isoe ) ";
nom = lect_chaine();
sort << "\n 1 " << nom << "_cab.isoe " ;
cout << "\n nom du maillage associe au fichier ? ";
nom = lect_chaine();
sort << nom << endl;
break;
}
case 2: // nouveau fichier de contraintes aux point d'integration
{ string nom;
cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _dpl.points ) ";
nom = lect_chaine();
sort << "\n 2 " << nom << "_dpl.points " ;
cout << "\n nom du maillage associe au fichier ? ";
nom = lect_chaine();
sort << nom << endl;
break;
}
default:
cout << "\n le cas "<<repi<<" n'est pas encore traite !!, mais cela devrait ce faire sans tarder ";
};
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
throw (toto);
}
catch (...)//
{ cout << "\n Erreur on attendait un des mots cles proposés !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour sortir ";
};
}; //-- fin du while
break;}
case 6: // parametres de controle du mod debug
{
sort << "\n#---------------------------------------------------------------------"
<< "\n| parametres communs a differents algorithmes (voir doc specifique) |"
<< "\n#---------------------------------------------------------------------"
<< "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! "
<< "\n # apres les parametres de controle de type d'arret et les autres qui precedent !!! "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # --- parametres de controle du niveau de commentaire --- "
<< "\n # ---------------------------------------------------------------------- "
<< "\n # ** PARAMETRES FACULTATIF ** "
<< "\n # permet_affichage_ 3 "
<< "\n # **important**: ce parametre doit etre mis sur une ligne seule "
<< endl;
break;
}
default:
cout << "\n le cas "<<rep<<" n'est pas encore traite !!, mais cela devrait ce faire sans tarder ";
};
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
throw (toto);
}
catch (...)//(UtilLecture::ErrNouvelleDonnee erreur)
{ cout << "\n Erreur on attendait un des mots cles proposés !!, "
<< "\n redonnez une bonne valeur"
<< "\n ou taper f ou 0 pour sortir ";
};
}; //-- fin du while
};
sort << "\n" << endl;
};
// initialisation d'un calcul de remonté à des variables secondaires ou d'erreur
// globalement, cette initialisation dépend des paramètres utilisateurs
// ramène true s'il y a initialisation
bool Algori::InitRemont(LesMaillages * lesMail,LesReferences* lesRef, DiversStockage* diversStockage,Charge* charge,
LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
{bool avec_remont=false;
// on parcourt la liste soustypeDeCalcul si elle n'est pas vide
if (soustypeDeCalcul->size() > 0)
{if ((find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_sigma) != soustypeDeCalcul->end())
|| (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),avec_remonte_erreur) != soustypeDeCalcul->end()))
{Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
avec_remont=true;avec_remont_sigma=true;}
if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_epsilon) != soustypeDeCalcul->end())
{Algori::InitRemontEps(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
avec_remont=true;avec_remont_eps=true;}
if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_erreur) != soustypeDeCalcul->end())
{if (!avec_remont_sigma)
{Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
avec_remont_sigma=true;}
Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
avec_remont=true;avec_erreur=true;}
};
return avec_remont;
};
// calcul d'une remontée à des variables secondaires ou d'erreur, ceci pour un post traitement de visualisation
// ce calcul dépend des paramètres utilisateurs, il n'est fait qu'à chaque sortie .BI
// ramène true s'il y a un calcul effectif
bool Algori::CalculRemont(LesMaillages * lesMail,OrdreVisu::EnumTypeIncre type_incre,int incre)
{ bool change=false;
bool remont_contrainte=false;
if (pa.SauvegardeAutorisee(incre,temps_derniere_sauvegarde,type_incre))
{ if (avec_remont_sigma) {Algori::RemontSigma(lesMail);change=true;remont_contrainte=true;};
if (avec_remont_eps) {Algori::RemontEps(lesMail);change=true;};
if (avec_erreur) {Algori::RemontErreur(lesMail);change=true;};
};
return change;
};
// affichage éventuelle de la matrice de raideur et du second membre
void Algori::Affiche_RaidSM(const Vecteur & vglobin,const Mat_abstraite& matglob) const
{ // affichage éventuelle de la matrice de raideur et du second membre
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage de la matrice de raideur ";
matglob.Affichage_ecran(entete);
entete = " affichage du second membre ";
vglobin.Affichage_ecran(entete);
}
};
// algorithme classique de line search
// le line seach agit sur une partie de la puissance et non sur la norme du résidu
// le line search à pour objectif de minimiser une partie de l'acroissement de la puissance
// en jeux, ainsi on peut avoir une minimisation réussi tout en ayant une norme d'équilibre
// qui continue à grandir
// cependant en général les deux sont lié et l'application du line_seach garantit que dans
// la direction de descente choisi on minimise norme (mais ce minimum peut cependant être
// supérieur à l'ancienne norme!)
bool Algori::Line_search1(Vecteur& sauve_deltadept,double& puis_precedente,
Vecteur& vres,LesMaillages * lesMail,Vecteur* sol
,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex
,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal
,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb
,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)
{ // ------------------------------------------------------------
// |on regarde s'il faut utiliser l'algorithme de line search |
// ------------------------------------------------------------
// nombre d'incrément mini à partir duquel on exécute le line_search
const int nb_incr_min_line_search = 2;
// les mini et maxi du facteur de line _search
const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit
// le nombre de fois que l'algorithme bute sur le mini et maxi
int nbfois_alphmin = 0; int nbfois_alphmax = 0;
const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2;
// nombre maxi de boucle de line_search
const int iwwmax = 5;
// limite sur la puissance pour activer le line_search
const double epsilon_p = 0.01;
double ancien_residu_norme = vres.Max_val_abs ();
double norme_dep = sauve_deltadept.Max_val_abs ();
double ancien_residuN = (- vres * (*sol));
// sauvegarde du déplacement
sauve_deltadept = *sol;
// il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre
// en oeuvre l'algorithme
// 1 - on sauvegarde les conditions actuelles
// récupération de l'incrément total de t à tdt avant le déplacement
lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb);
// 2 - on met en place le nouveau déplacement
lesMail->PlusDelta_tdt(*sol,nb_casAssemb);
// 3 - initialisation de la puissance externe puis on la calcul
vglobex.Zero();
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
<< " des efforts externes: arret"
<< "\n Algori::Line_search1(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// 4 - idem pour la puissance interne
vglobin.Zero();
// 5 - calcul du second membre et des énergies
// dans le cas d'un calcul inexploitable arrêt de la boucle
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret"
<< "\n Algori::Line_search1(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// 6 - second membre total
vglobaal = vglobex ;vglobaal += vglobin;
// 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
double nouvelle_norme = vglobaal.Max_val_abs ();
// calcul d'une partie de la variation de puissance relative au delta ddl
// cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl
// et la direction du résidu
double var_puis = - vglobaal * sauve_deltadept; // calcul de la puissance
cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis;
cout << "\n puissance " << var_puis ;
cout << "\n ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme);
if ((compteur >= nb_incr_min_line_search)
&& ((Abs(var_puis) > epsilon_p * norme_dep * nouvelle_norme)
|| (nouvelle_norme > 0.1 * ancien_residu_norme)))
// ((var_puis > puis_precedente) || (nouvelle_norme > ancien_residu_norme)))
// || (puis_reelle < 0.))
{// signifie que le déplacement précédent était trop grand
// ou pas dans la bonne direction !
// 1) on revient aux conditions du début de l'itération
v_travail -= sauve_dept_a_tdt;
lesMail->PlusDelta_tdt(v_travail,nb_casAssemb);
// 2) on traite la direction
// si la puissance est négative cela signifie que la matrice n'est pas définie
// positive, dans ce cas on utilise comme direction de descente
// - la direction trouvée ou le résidu
/* if (puis_reelle < 0.)
{ // message d'avertissement
cout << "\n ********** attention puissance négative, changement de descente ";
// ancien_dep = - vres;
ancien_dep = - ancien_dep;
} */
/* else if (Abs(puis_reelle) > pa.max_puissance)
// si la puissance est trop grande arrêt des itérations
{
non_convergence = true;
break;
} */
// 3) Maintenant application du line search,
//calcul d'alpha en utilisant une approximation linéaire de la puissance
double alph = 1.; // initialisation du coef multiplicateur du delta ddl
// dans le cas ou la nouvelle et l'ancienne puissance sont très proche
// on change de alpha
if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme)
alph = 0.66; // par exemple
// dans un premier temps on effectue un nombre de boucle fixé pour alpha
bool reduc_reussi = false;
bool reduc_possible = true;
for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++)
{ // calcul du nouveau résidu
// mise en place du nouveau déplacement
// pour éviter de créer un nouveau vecteur qui peut être de grande taille
// on utilise la place de vglobex pour le déplacement
Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement
nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept;
lesMail->TversTdt();
lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb );
//puissance externe
vglobex.Zero();
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
<< " des efforts externes: arret"
<< "\n Algori::Line_search1(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// puissance interne boucle sur les elements
vglobin.Zero();
// calcul du second membre et des énergies
// dans le cas d'un calcul inexploitable arrêt de la boucle
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
{ cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret"
<< "\n Algori::Line_search1(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// second membre total
vglobaal = vglobex ;vglobaal += vglobin;
// mise en place des conditions limites
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
// calcul du nouveau coefficient
// double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep);
// double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu * ancien_dep);//vres.Norme();
double nouveau_residuN = alph * (- vglobaal * sauve_deltadept);
double ancien_alph = alph;
nouvelle_norme = vglobaal.Max_val_abs ();
alph = - alph* ancien_residuN/
(nouveau_residuN - ancien_residuN);
// test d'arrêt
if ((alph < alphmin) || (alph > alphmax))
{ // troncature d'alpha
if (alph < alphmin)
{alph = alphmin;nbfois_alphmin++;
if (nbfois_alphmin > nbfois_alphmin_max)
/* if (nouvelle_norme < ancien_residu_norme)
// soit la norme à diminuée => on prend le nouveau déplacement
// et on arrête car dans tous les cas ce n'est pas une bonne convergence
// d'être acculé à la borne
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobal;
puis_precedente = Abs(nouveau_residuN);
break;
}
else */
// sinon il n'y a pas en plus de convergence on arrête tout
reduc_possible = false;
}
if (alph > alphmax)
{alph = alphmax;nbfois_alphmax++;
if (nbfois_alphmax > nbfois_alphmax_max)
/* if (nouvelle_norme < ancien_residu_norme)
// soit la norme à diminuée => on prend le nouveau déplacement
// et on arrête car dans tous les cas ce n'est pas une bonne convergence
// d'être acculé à la borne
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobal;
puis_precedente = Abs(nouveau_residuN);
break;
}
else */
// sinon il n'y a pas en plus de convergence on arrête tout
reduc_possible = false;
}
}
else // sinon on test la convergence
// if (nouvelle_norme < 0.8 * ancien_residu_norme )
{if ((Abs(nouveau_residuN) < 0.5 * Abs(puis_precedente) )
&& (nouvelle_norme < ancien_residu_norme))
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobaal;
puis_precedente = Abs(nouveau_residuN);
break;
}
// else if (iww==iwwmax)
else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme))
{reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobaal;
puis_precedente = Abs(nouveau_residuN);
break;
}
}
// sinon on incrémente la position à tdt
cout << "\n coefficient de line_search = " << alph
<< " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN;
}
// si la réduction c'est mal passée alors on laisse la solution
// identique à avant le line_search
if (!reduc_reussi)
{ // mise en place du déplacement existant avant le line_search
// ainsi que les autres grandeurs actives
lesMail->TversTdt();
v_travail = sauve_dept_a_tdt + sauve_deltadept;
lesMail->PlusDelta_tdt( v_travail,nb_casAssemb);
// retour du fait qu'il n'y a pas eu de line search
return false;
}
else
{
// retour du fait que le line search a été effectué
return true;
}
}
else // cas ou l'on ne fait pas de line seach
return false;
};
// algorithme de line search qui utilise une approximation cubique du résidu ( (R).<ddl>)
// en fonction du paramètre lambda de line search ( X+lambda. delta_ddl)
// la méthode renvoi si oui ou non le line search a été effecué
// sauve_deltadept : vecteur de travail servant à sauver la valeur calculée de sol
// vres : correspond en entrée au vecteur résidu
// sauve_dept_a_tdt : vecteur de travail utilisé pour sauvegarder la totalité de l'incrément de t à t+dt
// vglobex : puissance externe
// v_travail : vecteur de travail à la même dimension que sol
// vglobal : = & vglobin: vecteur puissance globale
bool Algori::Line_search2(Vecteur& sauve_deltadept,double& puis_precedente,
Vecteur& vres,LesMaillages * lesMail,Vecteur* sol
,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex
,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal
,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb
,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)
{
/* // initialisation des différentes grandeurs nécessaires pour le calcul du polynome cubique complet ou dégénéré
double f1= ;// puissance pour lambda = 0
double f2= ;// puissance pour lambda = 1
double g1= ;// */
// ------------------------------------------------------------
// |on regarde s'il faut utiliser l'algorithme de line search |
// ------------------------------------------------------------
// nombre d'incrément mini à partir duquel on exécute le line_search
const int nb_incr_min_line_search = 2;
// les mini et maxi du facteur de line _search
const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit
// le nombre de fois que l'algorithme bute sur le mini et maxi
int nbfois_alphmin = 0; int nbfois_alphmax = 0;
const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2;
// nombre maxi de boucle de line_search
const int iwwmax = 5;
// limite sur la puissance pour activer le line_search
const double epsilon_p = 0.01;
double ancien_residu_norme = vres.Max_val_abs ();
double norme_dep = sauve_deltadept.Max_val_abs ();
double ancien_residuN = (- vres * (*sol));
// sauvegarde du déplacement
sauve_deltadept = *sol;
// il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre
// en oeuvre l'algorithme
// 1 - on sauvegarde les conditions actuelles
// récupération de l'incrément total de t à tdt avant le déplacement
lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb);
// 2 - on met en place le nouveau déplacement
lesMail->PlusDelta_tdt(*sol,nb_casAssemb);
// 3 - initialisation de la puissance externe puis on la calcul
vglobex.Zero();
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
<< " des efforts externes: arret"
<< "\n Algori::Line_search2(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// 4 - idem pour la puissance interne
vglobin.Zero();
// 5 - calcul du second membre et des énergies
// dans le cas d'un calcul inexploitable arrêt de la boucle
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret"
<< "\n Algori::Line_search2(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// 6 - second membre total ( vglobal est identique a vglobin)
vglobaal = vglobex ; vglobaal += vglobin;
// 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
double nouvelle_norme = vglobaal.Max_val_abs ();
// calcul d'une partie de la variation de puissance relative au delta ddl
// cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl
// et la direction du résidu
double var_puis = - vglobaal * sauve_deltadept; // calcul de la puissance
cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis;
cout << "\n puissance " << var_puis ;
cout << "\n ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme);
if ((compteur >= nb_incr_min_line_search)
&& ((Abs(var_puis) > epsilon_p * norme_dep * nouvelle_norme)
|| (nouvelle_norme > 0.1 * ancien_residu_norme)))
// ((var_puis > puis_precedente) || (nouvelle_norme > ancien_residu_norme)))
// || (puis_reelle < 0.))
{// signifie que le déplacement précédent était trop grand
// ou pas dans la bonne direction !
// 1) on revient aux conditions du début de l'itération
v_travail -= sauve_dept_a_tdt;
lesMail->PlusDelta_tdt(v_travail,nb_casAssemb);
// 2) on traite la direction
// si la puissance est négative cela signifie que la matrice n'est pas définie
// positive, dans ce cas on utilise comme direction de descente
// - la direction trouvée ou le résidu
/* if (puis_reelle < 0.)
{ // message d'avertissement
cout << "\n ********** attention puissance négative, changement de descente ";
// ancien_dep = - vres;
ancien_dep = - ancien_dep;
} */
/* else if (Abs(puis_reelle) > pa.max_puissance)
// si la puissance est trop grande arrêt des itérations
{
non_convergence = true;
break;
} */
// 3) Maintenant application du line search,
//calcul d'alpha en utilisant une approximation linéaire de la puissance
double alph = 1.; // initialisation du coef multiplicateur du delta ddl
// dans le cas ou la nouvelle et l'ancienne puissance sont très proche
// on change de alpha
if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme)
alph = 0.66; // par exemple
// dans un premier temps on effectue un nombre de boucle fixé pour alpha
bool reduc_reussi = false;
bool reduc_possible = true;
for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++)
{ // calcul du nouveau résidu
// mise en place du nouveau déplacement
// pour éviter de créer un nouveau vecteur qui peut être de grande taille
// on utilise la place de vglobex pour le déplacement
Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement
nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept;
lesMail->TversTdt();
lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb );
//puissance externe
vglobex.Zero();
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
{ cout << "\n erreur dans l'algo, du a une erreur sur le calcul "
<< " des efforts externes: arret"
<< "\n Algori::Line_search2(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// puissance interne boucle sur les elements
vglobin.Zero();
// calcul du second membre et des énergies
// dans le cas d'un calcul inexploitable arrêt de la boucle
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
{ cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret"
<< "\n Algori::Line_search1(...";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// second membre total ( vglobal est identique a vglobin)
vglobaal = vglobex ;vglobaal += vglobin;
// mise en place des conditions limites
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat);
// calcul du nouveau coefficient
// double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep);
// double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu * ancien_dep);//vres.Norme();
double nouveau_residuN = alph * (- vglobaal * sauve_deltadept);
double ancien_alph = alph;
nouvelle_norme = vglobaal.Max_val_abs ();
alph = - alph* ancien_residuN/
(nouveau_residuN - ancien_residuN);
// test d'arrêt
if ((alph < alphmin) || (alph > alphmax))
{ // troncature d'alpha
if (alph < alphmin)
{alph = alphmin;nbfois_alphmin++;
if (nbfois_alphmin > nbfois_alphmin_max)
/* if (nouvelle_norme < ancien_residu_norme)
// soit la norme à diminuée => on prend le nouveau déplacement
// et on arrête car dans tous les cas ce n'est pas une bonne convergence
// d'être acculé à la borne
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobal;
puis_precedente = Abs(nouveau_residuN);
break;
}
else */
// sinon il n'y a pas en plus de convergence on arrête tout
reduc_possible = false;
}
if (alph > alphmax)
{alph = alphmax;nbfois_alphmax++;
if (nbfois_alphmax > nbfois_alphmax_max)
/* if (nouvelle_norme < ancien_residu_norme)
// soit la norme à diminuée => on prend le nouveau déplacement
// et on arrête car dans tous les cas ce n'est pas une bonne convergence
// d'être acculé à la borne
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobal;
puis_precedente = Abs(nouveau_residuN);
break;
}
else */
// sinon il n'y a pas en plus de convergence on arrête tout
reduc_possible = false;
}
}
else // sinon on test la convergence
// if (nouvelle_norme < 0.8 * ancien_residu_norme )
{if ((Abs(nouveau_residuN) < 0.5 * Abs(puis_precedente) )
&& (nouvelle_norme < ancien_residu_norme))
{ reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobaal;
puis_precedente = Abs(nouveau_residuN);
break;
}
// else if (iww==iwwmax)
else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme))
{reduc_reussi = true;
// on remet au mieux les choses comme au début de la méthode
*sol = ancien_alph * sauve_deltadept;
vres = vglobaal;
puis_precedente = Abs(nouveau_residuN);
break;
}
}
// sinon on incrémente la position à tdt
cout << "\n coefficient de line_search = " << alph
<< " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN;
}
// si la réduction c'est mal passée alors on laisse la solution
// identique à avant le line_search
if (!reduc_reussi)
{ // mise en place du déplacement existant avant le line_search
// ainsi que les autres grandeurs actives
lesMail->TversTdt();
v_travail = sauve_dept_a_tdt + sauve_deltadept;
lesMail->PlusDelta_tdt( v_travail,nb_casAssemb);
// retour du fait qu'il n'y a pas eu de line search
return false;
}
else
{
// retour du fait que le line search a été effectué
return true;
}
}
else // cas ou l'on ne fait pas de line seach
return false;
};
// initialisation des paramètres pour l'amortissement cinétique (au cas ou on veut plusieurs amortissement)
void Algori::InitialiseAmortissementCinetique()
{ compteur_decroit_pourRelaxDyn=0;
dernier_pic = pic_E_cint_t = -1.;
max_pic_E_cin = -1.;
compteur_test_pourRelaxDyn = 0;
compteur_pic_energie = 0;compteur_pic_energie_noe= 0;
// cas de l'utilisation d'une moyenne glissante
sauve_E_cin.Change_taille(taille_moyenne_glissante);
nb_Ecin_stocker = 0;indice_EC1= 0;
moyenne_glissante = 0.;
moy_gliss_t = 0.;
};
// méthode d'application de l'amortissement cinétique
// on arrête l'amortissement lorsque E_cin_tdt < E_cin_t * pic_E_cint_t
// on redémarre l'amortissement lorsque E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn
// retour un int :
// = 1 : il y a eu amortissement mais le calcul continue
// = 0 : pas d'amortissement
// = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait
int Algori::AmortissementCinetique(const Vecteur & delta_ddl,const double& coef_mass,const Vecteur& X
,const Mat_abstraite& mat_mass,int icharge,Vecteur& V)
{int relax_vit = 0;
nb_depuis_derniere_relax++; // on incrémente à chaque passage
// dans le cas où inter_nb_entre_relax dépend d'une fonction nD, on calcule sa valeur
if (fct_nD_inter_nb_entre_relax != NULL)
{int old_valeur = inter_nb_entre_relax;
inter_nb_entre_relax = (fct_nD_inter_nb_entre_relax->Valeur_pour_variables_globales())(1);
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 1))
if (old_valeur != inter_nb_entre_relax)
cout << "\n >>> changement de inter_nb_entre_relax de " << old_valeur
<< " en ==> "<< inter_nb_entre_relax;
};
// #ifdef UTILISATION_MPI
// // debug
// cout << "\n debug Algori::AmortissementCinetique N: " << icharge
// << " debut, proc= "<< ParaGlob::Monde()->rank() << flush;
// // fin debug
// #endif
// // dans le cas où l'on veut un amortissement individuel aux noeuds, on appelle la méthode spécifique
// int relax_vit_individuel = 0;
// if (amortissement_cinetique_au_noeud && !relax_vit)
// { relax_vit_individuel=AmortissementCinetique_individuel_aux_noeuds(delta_ddl,coef_mass,X,mat_mass,icharge,V);};
//*** je ne comprends pas le test que j'ai mis ici: abscon !! 16 oct 2018
// on ne continue que s'il n'y a pas d'amortissement cinétique en route
bool relaxation_effectuee = false; // initialisation
if (!((icharge > nb_deb_test_amort_cinetique_noe) && amortissement_cinetique_au_noeud))
// ---- non la suite n'est pas bonne et converge beaucoup moins bien !!
// je le remplace : on test si on est en amortissement cinétique, et que le nombre d'itérations
// est suffisant
/// if ((icharge > nb_deb_test_amort_cinetique_noe) && (!amortissement_cinetique_au_noeud)
/// && amortissement_cinetique )
// --- fin modif avorté !!!
{
// if (!relax_vit_individuel)
//// else
// {
// cout << "\n E_cin_t= " << E_cin_t << " E_cin_tdt= " << E_cin_tdt
// << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn;
// remarque:
// compteur_decroit_pourRelaxDyn: indique combien de fois le test de pic a été effectué avec succés
// si == -2 : indique que la procédure de test est gelé
// si == 0 : indique que la procédure est active, et qu'il n'y a pas eu pour l'instant de pic détecté
// si > 0 : indique que la procédure est active, et que, de manière consécutive, indique
// le nombre de fois où il y a eu baisse
bool relaxation_reactive = false; // "
if ((amortissement_cinetique)&&(icharge != 0) && (icharge > nb_deb_test_amort_cinetique))
{ // on regarde si l'énergie cinétique a déjà été calculée, sinon on la calcule
if (icharge < pa.NbIncrCalEnergie()) // ******* a revoir, car le test n'est peut-être pas suffisant avec tous les algos
{ // initialisation
v_int.Change_taille(V.Taille()); v_int.Zero();
// calcul de l'énergie cinétique
E_cin_tdt = (0.5/coef_mass) * (V * (mat_mass.Prod_vec_mat(V,v_int)));
};
// on calcul éventuellement la moyenne glissante
if (taille_moyenne_glissante > 1)
{ if (nb_Ecin_stocker < taille_moyenne_glissante)
{ // c'est le cas où la moyenne n'est pas finalisée
nb_Ecin_stocker++; indice_EC1=1;
sauve_E_cin(nb_Ecin_stocker) = E_cin_tdt;
}
else // cas ou la moyenne est finalisée
{ sauve_E_cin(indice_EC1) = E_cin_tdt;
indice_EC1++; // mise à jour de l'indice pour le prochain stockage
// si l'indice dépasse la taille du taille, on remet au début
if (indice_EC1 > taille_moyenne_glissante) indice_EC1 = 1;
};
// maintenant on regarde de nouveau si on peut calculer la moyenne
if (nb_Ecin_stocker == taille_moyenne_glissante)
{moy_gliss_t = moyenne_glissante; moyenne_glissante = sauve_E_cin.Moyenne();}
else {moy_gliss_t= 0.; moyenne_glissante = 0.;}; // au cas où on met une valeur très grande
};
// écriture d'info pour le débug au cas où
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3))
{if (taille_moyenne_glissante == 1)
{cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn
<< " pic_E_cint_t= " << pic_E_cint_t << endl;
}
else
{cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn
<< " moyenne_glissante= " << moyenne_glissante << " moy_gliss_t= " << moy_gliss_t
<< " pic_E_cint_t= " << pic_E_cint_t << endl;
};
};
// --- application de l'algo
// a) dans le cas où la procédure a été gelée précédemment, on regarde
// s'il faut la redémarrer
if (compteur_decroit_pourRelaxDyn == -2)
{if (E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn)
{compteur_decroit_pourRelaxDyn = 0; // indique que l'amortissement est de nouveau active
relaxation_reactive = true;
};
};
// b) on regarde pour l'application de l'amortissement
if (compteur_decroit_pourRelaxDyn != -2) // != -2 veut dire que la procédure est active
{if (taille_moyenne_glissante == 1)
{
//debug ------
//cout << "\n E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl;
// fin debug
if ((E_cin_tdt > E_cin_t) && (E_cin_tdt > pic_E_cint_t)) //pic_E_cint_t)
{
//debug ------
//cout << "\n marquage d'un nouveau pic: E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl;
// fin debug
pic_E_cint_t = E_cin_tdt;
} //X_EcinMax = X;
max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin);
}
else
{ if ((moyenne_glissante > moy_gliss_t) && (moyenne_glissante > pic_E_cint_t))//pic_E_cint_t)
{ pic_E_cint_t = moyenne_glissante;
};// X_EcinMax = X; }
max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin);
};
// on considère qu'il y a décroissance, lorsque soit:
// 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique
// ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin
// 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante
// ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin
// NB: si le pic_E_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide
if ( ((test_fraction_energie == 0.) &&
( ((taille_moyenne_glissante == 1) && (E_cin_tdt < pic_E_cint_t)) // cas sans moyenne glissante
|| ((taille_moyenne_glissante != 1) && (moyenne_glissante < pic_E_cint_t)) // cas avec moyenne glissante
)
)
||
((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente
( ((taille_moyenne_glissante == 1) && (E_cin_tdt < (test_fraction_energie * pic_E_cint_t))) // cas sans moyenne glissante
|| ((taille_moyenne_glissante != 1) && (moyenne_glissante < (test_fraction_energie * pic_E_cint_t))) // cas avec moyenne glissante
)
)
)
{
//debug ------
//cout << "\n descente: E_cin_tdt " << E_cin_tdt << " pic_E_cint_t " << pic_E_cint_t << endl;
// fin debug
compteur_decroit_pourRelaxDyn++;
if ((compteur_decroit_pourRelaxDyn >= max_nb_decroit_pourRelaxDyn)
&& (nb_depuis_derniere_relax >= inter_nb_entre_relax))
{ // cas ou on met en place l'amortissement
V.Zero();relaxation_effectuee=true;
nb_depuis_derniere_relax = 0;
dernier_pic = pic_E_cint_t; // on sauvegarde
if (taille_moyenne_glissante != 1) // on remet tout à 0
{nb_Ecin_stocker = 0;indice_EC1= 0;};
relax_vit=1;
compteur_pic_energie++;
compteur_decroit_pourRelaxDyn=0;
if ( dernier_pic == -1)
// { if ( ((taille_moyenne_glissante != 1) && ( moyenne_glissante < dernier_pic*coef_arret_pourRelaxDyn))
// || ((taille_moyenne_glissante == 1) && ( E_cin_tdt < dernier_pic*coef_arret_pourRelaxDyn)) )
{ pic_E_cint_t = 0.; // on remet à 0 le pic
E_cin_tdt = 0.;
}
else
{ if ( dernier_pic < max_pic_E_cin*coef_arret_pourRelaxDyn)
// if (E_cin_tdt <= pic_E_cint_t*coef_arret_pourRelaxDyn)
// cas où on suspend l'amortissement pour la suite
{compteur_decroit_pourRelaxDyn=-2;}; // inactive l'amortissement
pic_E_cint_t = 0.; // on remet à 0 le pic
E_cin_tdt = 0.;
};
E_cinNoe_tdt.Zero();
pic_E_cint_t_noe.Zero();
};
}
else // sinon cela signifie que la diminution n'est pas validée donc
// on re-initialise le compteur de décroissance (qui sert à valider des décroissances consécutives)
{compteur_decroit_pourRelaxDyn=0;};
// c) on regarde s'il faut arrêter le calcul, relativement au delta_ddl, seulement à partir d'un
// certain nombre de fois que la méthode à été activé
// ce qui permet d'éviter des pbs au démarrage, pour lequel l'énergie cinétique démarre forcément
// de 0 puis petit à petit grandie
// de plus on ne test le delta_ddl que:
// 1) si on a passé au moins "un" pic d'énergie cinétique (sinon on peut avoir un deltat ddl = 0 car on est presqu'au
// maxi et ce maxi = pas du tout l'équilibre !!)
// non pour l'instant ... // 2) si l'énergie cinétique est suffisament faible
compteur_test_pourRelaxDyn++;
if (compteur_test_pourRelaxDyn > nb_deb_testfin_pourRelaxDyn)
{ if ((max_pic_E_cin != -1)
|| // on ajoute le cas très particulier où l'énergie cinétique reste nulle
((E_cin_tdt ==0.) && (E_cin_t==0.)) // c'est le cas où rien ne bouge !!
)
{ if (delta_ddl.Max_val_abs() <= max_deltaX_pourRelaxDyn) nb_dX_OK_pourRelaxDyn++;
if (nb_dX_OK_pourRelaxDyn > nb_max_dX_OK_pourRelaxDyn)
{ relax_vit = -1;
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3))
cout << "\n critere en deplacement ok: max_deltaX= " << delta_ddl.Max_val_abs();
nb_dX_OK_pourRelaxDyn=0; // on initialise pour une prochaine fois
// dans le cas ou l'arrêt réel n'est pas drivé par le déplacement
// mais par exemple sur le résidu
};
};
};
}; // -- fin du cas où l'on applique l'amortissement
};
// on tente d'afficher que si l'amortissement a effectivement eu lieu
// if (relax_vit && pa.AfficheIncrEnergie())
if (relaxation_effectuee)
{if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 2))
{cout << "\n N:" << icharge << " relaxation cinetique effectuee "
<< " pic_E_cint_t("<<compteur_pic_energie<<") " << dernier_pic
<< " max_pic_E_cin= " << max_pic_E_cin;
//--- info pour le debug
/* if (ParaGlob::NiveauImpression() > 8)
{if (taille_moyenne_glissante == 1)
{cout << "\n nb_Ecin_stocker= " << nb_Ecin_stocker << " indice_EC1= " << indice_EC1 << endl;
}
else
{cout << "\n nb_Ecin_stocker= " << nb_Ecin_stocker << " indice_EC1= " << indice_EC1
<< " moyenne_glissante= " << moyenne_glissante << " moy_gliss_t= " << moy_gliss_t << endl;
};
};*/
if (compteur_decroit_pourRelaxDyn == -2)
cout << " relaxation_gelee " ;
if (relaxation_reactive)
cout << " relaxation_re_active ";
cout << endl;
};
};
};
#ifdef UTILISATION_MPI
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
broadcast(*ParaGlob::Monde(), relaxation_effectuee, 0);
// debug
//cout << "\n debug Algori::AmortissementCinetique "
// << " barriere transfert relaxation_effectuee , proc= "<< ParaGlob::Monde()->rank() << flush;
// fin debug
// ParaGlob::Monde()->barrier(); // synchronisation ici de tous les process
temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
#endif
#ifdef UTILISATION_MPI
// // debug
// cout << "\n debug Algori::AmortissementCinetique "
// << " relaxation_effectué = "<< relaxation_effectuee << " proc= "<< ParaGlob::Monde()->rank() << flush;
// // fin debug
if (relaxation_effectuee && (ParaGlob::Monde()->rank() != 0))
// if (relaxation_effectuee )
{ V.Zero();
// // debug
// cout << "\n debug Algori::AmortissementCinetique "
// << " mise à 0 du vecteur vitesse, proc= "<< ParaGlob::Monde()->rank() << flush;
// // fin debug
};
#endif
// dans le cas où l'on veut également un amortissement individuel aux noeuds, on appelle la méthode spécifique
// que si il n'y a pas eu d'amortissement cinétique global
int relax_vit_individuel = 0;int retour = 0;
if (amortissement_cinetique_au_noeud && !relax_vit)
{ relax_vit_individuel=AmortissementCinetique_individuel_aux_noeuds(delta_ddl,coef_mass,X,mat_mass,icharge,V);
// ici on a relax_vit = 0 donc le retour est uniquement particularisé par relax_vit_individuel
retour = relax_vit_individuel;
}
else // sinon on est dans le cas où on a seulement un amortissement global et seul relax_vit donne une info à ce sujet
{ retour = relax_vit;};
#ifdef UTILISATION_MPI
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
broadcast(*ParaGlob::Monde(), retour, 0);
temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
//// debug
//cout << "\n debug Algori::AmortissementCinetique N: " << icharge
// << " fin, proc= "<< ParaGlob::Monde()->rank() << flush;
//// fin debug
#endif
return retour;
// la ligne qui suit est fausse car avec un "ou" le résultat est uniquement 1 ou 0, et en particulier
// les - sont supprimé !! ce qui pose un pb lorsque relax_vit = -1 !!
// return (relax_vit||relax_vit_individuel);
};
// méthode interne d'application de l'amortissement cinétique, exploratoire
// cas d'un amortissement local
// retour un int :
// = 1 : il y a eu au moins un amortissement
// = 0 : pas d'amortissement
int Algori::AmortissementCinetique_individuel_aux_noeuds(const Vecteur & delta_ddl,const double& coef_mass,const Vecteur& X
,const Mat_abstraite& mat_mass,int icharge,Vecteur& V)
{int relax_vit = 0;
if ((amortissement_cinetique_au_noeud)&&(icharge != 0) && (icharge > nb_deb_test_amort_cinetique_noe))
{ // on va faire une boucle sur tous les noeuds
int nbddl = delta_ddl.Taille(); int dim = ParaGlob::Dimension();
int NBN = nbddl / dim;
// mise à jour des tailles
if (E_cinNoe_tdt.Taille() == 0)
{ E_cinNoe_tdt.Change_taille(NBN,0.);E_cinNoe_t.Change_taille(NBN,0.);
compteur_decroit_pourRelaxDyn_noe.Change_taille(NBN,0);
dernier_pic_noe.Change_taille(NBN,-1);
pic_E_cint_t_noe.Change_taille(NBN,-1);
max_pic_E_cin_noe.Change_taille(NBN,-1);
};
// un compteur de relaxation pour info
int compteur_relaxation_ok=0; // init
for (int noe =1; noe <= NBN; noe++)
{ // on calcul l'énergie pour le noeud
bool relaxation_effectuee = false; // initialisation
bool relaxation_reactive = false; // "
double& eN_cin_tdt = E_cinNoe_tdt(noe);
double& eN_cin_t = E_cinNoe_t(noe);
double& pic_eN_cint_t = pic_E_cint_t_noe(noe);
double& dernier_pic_eN = dernier_pic_noe(noe);
eN_cin_tdt = 0.; // init
int ptint = (noe-1)*dim;
switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
case 2: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
case 1: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint);
};
/* switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint);
case 2: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint);
case 1: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint);
};
*/
// --- application de l'algo
// a) dans le cas où la procédure a été gelée précédemment, on regarde
// s'il faut la redémarrer
double & max_pic_eN_cin = max_pic_E_cin_noe(noe);
int & compt_decroit_pourRelaxDyn_noe = compteur_decroit_pourRelaxDyn_noe(noe);
if (compt_decroit_pourRelaxDyn_noe == -2)
{if (eN_cin_tdt > max_pic_eN_cin * coef_redemarrage_pourRelaxDyn_noe)
{compt_decroit_pourRelaxDyn_noe = 0; // indique que l'amortissement est de nouveau active
relaxation_reactive = true;
};
};
// b) on regarde pour l'application de l'amortissement
if (compt_decroit_pourRelaxDyn_noe != -2) // != -2 veut dire que la procédure est active
{
////debug ------
//if (noe==220)
//{ cout << "\n V(i)= "<<V((noe-1)*dim+1)<<" "<<V((noe-1)*dim+2)<<" "<<V((noe-1)*dim+3)<<" "
// << mat_mass((noe-1)*dim+1,(noe-1)*dim+1)<<" "<<mat_mass((noe-1)*dim+2,(noe-1)*dim+2)
// <<" "<<mat_mass((noe-1)*dim+3,(noe-1)*dim+3)<<" ";
// cout << "\n eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// }
// fin debug
if ((eN_cin_tdt > eN_cin_t) && (eN_cin_tdt > pic_eN_cint_t)) //pic_eN_cint_t)
{
////debug ------
//if (noe==220)
//cout << "\n marquage d'un nouveau pic: eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
//// fin debug
pic_eN_cint_t = eN_cin_tdt;
}; //X_EcinMax = X;
max_pic_eN_cin=MaX(pic_eN_cint_t,max_pic_eN_cin);
};
// on considère qu'il y a décroissance, lorsque soit:
// 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique
// ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin
// 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante
// ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin
// NB: si le pic_eN_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide
if ( ((test_fraction_energie == 0.) && (eN_cin_tdt < pic_eN_cint_t))
||
((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente
(eN_cin_tdt < (test_fraction_energie * pic_eN_cint_t)))
)
{
//debug ------
//cout << "\n descente: eN_cin_tdt " << eN_cin_tdt << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// fin debug
compt_decroit_pourRelaxDyn_noe++;
if (compt_decroit_pourRelaxDyn_noe >= max_nb_decroit_pourRelaxDyn_noe)
{ // cas ou on met en place l'amortissement
int depart = (noe-1)*dim+1;
for (int i=0;i<dim;i++)
V(depart+i)=0.;
// V(depart+i)*=0.5; // test: on diminue la vitesse par 2 au lieu de la supprimer
////debug ------
//if (noe==220)
//cout << "\n amortissemen:eN_cin_tdt " << eN_cin_tdt << " pic_eN_cint_t " << pic_eN_cint_t << endl;
//// fin debug
relaxation_effectuee=true;
dernier_pic_eN = pic_eN_cint_t; // on sauvegarde
relax_vit=1;
compteur_pic_energie_noe++;
compt_decroit_pourRelaxDyn_noe=0;
compteur_relaxation_ok++; // pour l'affichage éventuelle
if ( dernier_pic_eN == -1)
{ pic_eN_cint_t = 0.; // on remet à 0 le pic
eN_cin_tdt = 0.;
// eN_cin_tdt *= 0.25; // test, comme la vitesse est diminuée de 2, ecin est diminuée de 4
}
else
{ if ( dernier_pic_eN < max_pic_eN_cin*coef_arret_pourRelaxDyn_noe)
{compt_decroit_pourRelaxDyn_noe=-2;}; // inactive l'amortissement
pic_eN_cint_t = 0.; // on remet à 0 le pic
eN_cin_tdt = 0.;
// eN_cin_tdt = 0.25; // test, comme la vitesse est diminuée de 2, ecin est diminuée de 4
};
};
}
else // sinon cela signifie que la diminution n'est pas validée donc
{ // on re-initialise le compteur de décroissance (qui sert à valider des décroissances consécutives)
compt_decroit_pourRelaxDyn_noe=0;
};
////debug ------
//if (relaxation_effectuee && (noe==220))
//{ cout << "\n relaxation:V(i)= "<<V((noe-1)*dim+1)<<" "<<V((noe-1)*dim+2)<<" "<<V((noe-1)*dim+3)<<" "
// << mat_mass((noe-1)*dim+1,(noe-1)*dim+1)<<" "<<mat_mass((noe-1)*dim+2,(noe-1)*dim+2)
// <<" "<<mat_mass((noe-1)*dim+3,(noe-1)*dim+3)<<" ";
// cout << "\n eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl;
// }
//// fin debug
// on tente d'afficher que si l'amortissement a effectivement eu lieu
if (relaxation_effectuee)
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 7)) || (permet_affichage > 5))
{cout << "\n relax effectue au noeud " << noe
<< " pic_eN_cint_t("<<compteur_pic_energie_noe<<") " << dernier_pic_eN
<< " max_pic_eN_cin= " << max_pic_eN_cin;
if (compt_decroit_pourRelaxDyn_noe == -2)
cout << " relaxation_gelee " ;
if (relaxation_reactive)
cout << " relaxation_re_activee ";
cout << endl;
};
}; // fin de la boucle sur les noeuds
if (compteur_relaxation_ok>0) // affichage global éventuel
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 2))
cout << "\n nb de relaxation individuelle effectuee: " << compteur_relaxation_ok;
};// -- fin du cas où l'on applique l'amortissement
return relax_vit;
};
// pilotage de la convergence, ceci en fonction du type de pilotage choisit
// ramène true si le pas de temps a été modifié, false sinon
// arret = true: indique dans le cas d'une non convergence, neanmoins rien n'a changé, il faut donc arrêter
bool Algori::Pilotage_du_temps(Charge* charge,bool& arret)
{ arret = false; // initialisation
bool modif_pas_de_temps = false;
// choix en fonction des différents cas
switch (pa.TypeDePilotage())
{ case AUCUN_PILOTAGE: // pas de pilotage
{if (phase_de_convergence >= 0) // cas normal
{ // on regarde s'il faut augmenter le paramètre de charge
if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
{ // cas ou on augmente
// modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation());
// réinitialisation pour la suite
// nombre_de_bonnes_convergences = 0;
// nombre_de_mauvaises_convergences = 0;
}
bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit
// car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier
modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge
}
else
{ // cas ou l'incrément précédent n'a pas convergé
// modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution());
// if (!modif_pas_de_temps)
{ // dans le cas où il n'y a pas de modification du pas de temps on le signale
cout << "\n pas de pilotage ===> pas de modification possible du pas de temps";
arret = true;
}
bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit
// car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier
modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge
phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
}
break;
}
case PILOTAGE_BASIQUE: case PILOT_GRADIENT : // cas du pilotage basique
// et également pour le gradient pour l'instant
{//cout << "\n phase de convergence " << phase_de_convergence << endl;
if (phase_de_convergence >= 0) // cas normal
{// on regarde s'il faut augmenter le paramètre de charge
if (phase_de_convergence < 2)
{if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
{ // cas ou on augmente le pas de temps
bool etat_charge= charge->Augmente_inc_charge(pa.Facteur_augmentation());
modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
// réinitialisation pour la suite
nombre_de_bonnes_convergences = 0;nombre_de_mauvaises_convergences=0;
};
}
else // cas la convergence n'a pas été bonne: phase_de_convergence >= 2
{ // on va diminuer l'incrément
bool etat_charge= charge->Diminue_inc_charge(pa.Fact_dim_en_mauvaiseConv());
modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
// réinitialisation pour la suite
nombre_de_bonnes_convergences = 0;
// on laisse le nombre de mauvaises convergence nombre_de_mauvaises_convergences = 0; // mais ça a convergé donc on met à 0
};
}
else
{ // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps
// on revient en arrière
charge->Precedant(false);
bool etat_charge= charge->Diminue_inc_charge(pa.Facteur_diminution());
modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
if (!modif_pas_de_temps)
{ // dans le cas où il n'y a pas de modification du pas de temps on le signale
// l'arrêt sera traité par le programme appelant
cout << "\n Pilotage ===> pas de modification possible du pas de temps";
arret = true;
};
phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
}
bool etat_charge= charge->Avance();
modif_pas_de_temps = (etat_charge || modif_pas_de_temps );
break;
};
/* case PILOT_GRADIENT: // pour l'instant idem cas du pilotage basique
{if (phase_de_convergence >= 0) // cas normal
{// on regarde s'il faut augmenter le paramètre de charge
if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence())
{ // cas ou on augmente le pas de temps
modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation());
// réinitialisation pour la suite
nombre_de_bonnes_convergences = 0;
}
}
else
{ // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps
// on revient en arrière
charge->Precedant(false);
modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution());
if (!modif_pas_de_temps)
{ // dans le cas où il n'y a pas de modification du pas de temps on le signale
// l'arrêt sera traité par le programme appelant
cout << "\n Pilotage ===> pas de modification possible du pas de temps";
arret = true;
}
phase_de_convergence = 0; // initialisation pour repartir d'un bon pied
}
charge->Avance(); // increment de charge
break;
}
*/
default:
{ cout << "\n erreur le cas de pilotage " << Nom_TypePilotage(pa.TypeDePilotage())
<< " n'est pas implante !!! "
<< "\n Algori::Pilotage_du_temps(... ";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
}; // fin des différents cas de pilotage
// retour de l'information sur la modification ou non du pas de temps
//debug
//cout << "\n Algori::Pilotage_du_temps: phase_de_convergence=" << phase_de_convergence
// << " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences
// << " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl ;
//fin debug
cout << flush; // pour que l'on puisse voir quelque chose ! en cours de calcul en particulier s'il y a pb
return modif_pas_de_temps;
};
// pilotage de la fin des itération en implicite : utilisation conjointe avec: Pilotage_du_temps()
// ramène vraie si la convergence est correcte, sinon false
bool Algori::Pilotage_fin_iteration_implicite(int compteur)
{ bool fin_iter = false;
if (a_converge)
{ if (compteur < pa.Nb_iter_pour_bonne_convergence())
{ // cas où le calcul a convergé en moins de pa.Nb_iter_pour_bonne_convergence
nombre_de_bonnes_convergences++; // incrémentation de la bonne convergence
nombre_de_mauvaises_convergences=0;
phase_de_convergence = 1; //signalement pour Pilotage_du_temps
}
else if (compteur > (pa.Nb_iter_pour_mauvaise_convergence()))
{ // cas où on considère que la convergence n'a pas été bonne et qu'il vaut mieux diminuer l'incrément
// pour la prochaine fois, on efface également le nombre de bonnes convergences
nombre_de_bonnes_convergences = 0;
nombre_de_mauvaises_convergences++;
phase_de_convergence = 2;
}
else // cas où c'est ni très bon, ni très mauvais, on laisse en l'état
{ phase_de_convergence = 1; //signalement pour Pilotage_du_temps
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences=0;
};
// nombre_de_mauvaises_convergences = 0; // dans tous les cas on a convergé
fin_iter = true; // on signale qu'il y a eu convergence et que l'on a fini les itérations
}
else if (compteur > pa.Iterations())
{ nombre_de_mauvaises_convergences++;
nombre_de_bonnes_convergences = 0;
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n ******* NON convergence des iterations d'equilibre ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================="
<< "\n *** NON convergence of the balance iteration ***** "
<< "\n=============================================================================";
};
phase_de_convergence = -1; //signalement pour Pilotage_du_temps
fin_iter = false; // on signale qu'il n'y a pas convergence
}
else if (phase_de_convergence == -2) // cas où c'est Convergence() qui est la cause de l'arret
// pour cause d'évolution divergente des résidus
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n *** NON convergence equilibre: evolution divergente des residus ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================="
<< "\n *** NON convergence of balance: divergente evolution of the residues ***** "
<< "\n=============================================================================";
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -3) // cas où c'est Convergence() qui est la cause de l'arret
// pour cause de variation de ddl minimal atteinte
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n *** NON convergence equilibre: variation de ddl minimal atteinte ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================="
<< "\n *** NON convergence of balance: reaching of the minimum allowed of ddf ***** "
<< "\n=============================================================================";
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -4) // cas où c'est Convergence() qui est la cause de l'arret
// pour cause de variation de ddl maximal atteinte
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n *** NON convergence equilibre: variation de ddl maximum atteinte ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================="
<< "\n *** NON convergence of balance: reaching of the maximum allowed of ddl ***** "
<< "\n=============================================================================";
};
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
fin_iter = false; // on signale qu'il n'y a pas convergence
}
else if (phase_de_convergence == -5) // cas d'un arrêt à cause d'un jacobien négatif, qui est géré
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n *** NON convergence due a la gestion de jacobien negatif ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================"
<< "\n *** NON convergence due to the management of negative jacobian ********* "
<< "\n============================================================================";
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -6) // cas d'un arrêt à cause d'une variation de jacobine trop grande
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n============================================================================"
<< "\n *** NON convergence due a une variation de jacobien trop grande ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================"
<< "\n *** NON convergence due to a too big variation of the jacobian ********* "
<< "\n============================================================================";
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -7) // cas d'un arrêt à cause d'une non convergence de la loi de comp
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{ cout << "\n============================================================================"
<< "\n *** NON convergence due a la loi de comportement ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================"
<< "\n *** NON convergence due to the material behaviour ********* "
<< "\n============================================================================";
};
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -8) // cas d'un arrêt à cause d'une non convergence de la loi de comp
// mais pour un pb qui couve depuis plusieurs incréments
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{ cout << "\n============================================================================"
<< "\n *** NON convergence du a la loi de comportement ********* "
<< "\n *** probablement due a des erreurs sur plusieurs increments ********* "
<< "\n============================================================================";
}
else
{ cout << "\n============================================================================"
<< "\n *** NON convergence due to the material behaviour ********* "
<< "\n *** probably due to errors along several increments ********* "
<< "\n============================================================================";
};
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -9) // cas d'un arrêt à cause d'un pb de la résolution du syteme linéaire
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{ cout << "\n=============================================================================="
<< "\n *** NON convergence due a un pb de resolution du systeme lineaire ********* "
<< "\n==============================================================================";
}
else
{ cout << "\n================================================================================="
<< "\n *** NON convergence due to the resolution of the global linear system ********* "
<< "\n=================================================================================";
};
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -10) // cas d'un arrêt à cause d'un pb de calcul des efforts extérieurs
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{ cout << "\n=============================================================================="
<< "\n *** NON convergence due a un pb de calcul des efforts exterieurs ********* "
<< "\n==============================================================================";
}
else
{ cout << "\n================================================================================="
<< "\n *** NON convergence due to extern loading problem ********* "
<< "\n=================================================================================";
};
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else if (phase_de_convergence == -11) // cas d'un arrêt à cause d'un nan ou infini sur forces ext, int
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{ cout << "\n=============================================================================="
<< "\n *** NON convergence due a un nan ou infini sur forces int, ext, totales ********* "
<< "\n==============================================================================";
}
else
{ cout << "\n================================================================================="
<< "\n *** NON convergence due to nan value ********* "
<< "\n=================================================================================";
};
};
fin_iter = false; // on signale qu'il n'y a pas convergence
nombre_de_bonnes_convergences=0;
nombre_de_mauvaises_convergences++;
}
else // cas d'une erreur de pilotage: on ne sait pas pourquoi il s'est arrêté sans convergence
{ if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n cas de pilotage de fin d'iteration inconnues ? ou alors qui suit une erreur signalee precedemment ";
if (ParaGlob::NiveauImpression() > 5)
cout << "\n bool Pilotage_fin_iteration_implicite(int compteur) ";
cout << endl;
}
else {cout << "\n unknown case of management for the end of iteration or, following an error ";
if (ParaGlob::NiveauImpression() > 5)
cout << "\n bool Pilotage_fin_iteration_implicite(int compteur) ";
cout << endl;
};
};
// si il ne s'agit pas d'une sortie voulue des itérations et incréments
// on s'arrête
if (!(pa.EtatSortieEquilibreGlobal()))
{ // dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
// sinon on continue
}
return fin_iter;
//debug
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n Algori::Pilotage_fin_iteration_implicite: phase_de_convergence=" << phase_de_convergence
<< " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences
<< " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl ;
};
//fin debug
};
// pilotage spécifique de la fin de la relaxation dynamique, en tenant compte des différents critères demandés
// relax_vit_acce :
// = 1 : il y a eu relaxation mais le calcul continue
// = 0 : pas de relaxation
// = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait
// compteur: indique le nombre d'itération ou d'incrément en cours
// iter_ou_incr : =1: il s'agit d'itération", =0 il s'agit d'incrément
// lit arret, puis modifie arret en true ou false = il faut arrêter ou non
// si true met à jour en interne certains paramètres de gestion de pilotage pour dire que l'on a bien convergé
bool Algori::Pilotage_fin_relaxation_et_ou_residu(const int& relax_vit_acce,const int& iter_ou_incr,
const int& compteur, const bool& arretResidu, bool& arret)
{
// pour mémoire: arret_a_equilibre_statique indique, si diff de 0, que l'on veut contrôler une convergence vers la solution
// statique. Si = 1: le residu statique est utilise comme critere
// si = 2: nécessite que les deux critères précédents soient satisfait
// examen de la convergence éventuelle, utilisant le déplacement et/ou le résidu
string nom="l'iteration"; if (!iter_ou_incr) nom = "l'increment";
switch (relax_vit_acce)
{ case -1: // cas où le critère en déplacement est ok
{if (!arret_a_equilibre_statique) // cas ou on ne considère pas l'équilibre en résidu
{arret=true;a_converge = true;
cout << "\n critere en deplacement satisfait pour "<< nom << " : " << compteur
<< " max_deltaX= " <<delta_X.Max_val_abs() << endl;
}
else if ((arret_a_equilibre_statique==2) && arretResidu) // cas ou considère l'équilibre en résidu et en amortissement cinétique
{arret=true;a_converge = true;
cout << "\n critere en deplacement et en residu satisfait pour "<< nom << " : "
<< compteur << " max_deltaX= " <<delta_X.Max_val_abs() <<endl;
}
}
break;
case 0: case 1: // cas où le critère en déplacement n'est pas satisfait ou qu'il y a eu une relaxation (donc pas encore de convergence)
{if ( (arret_a_equilibre_statique==1) && arretResidu) // cas du critère en résidu uniquement
{arret=true;a_converge = 1;
cout << "\n critere equilibre statique satisfait pour "<< nom << " : " << compteur << " " <<endl;
}
else // sinon on est pas avec un contrôle avec le résidu donc on se base uniquement sur le déplacement
{arret=false;a_converge = false;}
}
break;
default:
cout << "\n *** erreur: relax_vit_acce= "<<relax_vit_acce
<< "\n ce cas n'est pas prevu... \n Algori::Pilotage_fin_relaxation_et_ou_residu(...";
Sortie(1);
break;
};
// if (relax_vit_acce == -1) // en amortissement cinétique, on a convergé
// {if (!arret_a_equilibre_statique) // cas ou on ne considère pas l'équilibre en résidu
// {arret=true;a_converge = 1;
// cout << "\n critere en deplacement satisfait pour "<< nom << " : " << compteur << " " <<endl;
// }
// else if ((arret_a_equilibre_statique==2) && arretResidu) // cas ou considère l'équilibre en résidu et en amortissement cinétique
// {arret=true;a_converge = 1;
// cout << "\n critere en deplacement et en residu satisfait pour "<< nom << " : "
// << compteur << " " <<endl;
// }
//
// }
// else if ( (arret_a_equilibre_statique==1) && arretResidu) // cas du critère en résidu uniquement
// {arret=true;a_converge = 1;
// cout << "\n critere equilibre statique satisfait pour "<< nom << " : " << compteur << " " <<endl;
// };
return arret;
};
// pilotage à chaque itération:
// - sous ou sur relaxation
// - limitation de la norme de delta ddl
// - indication de précision pour les éléments (utilisée pour certain type de gestion d'hourglass)
// en entrée: le maxi de var ddl juste après résolution
// ramène le maxi de var ddl maxDeltaDdl modifié, ainsi que sol modifié éventuellement,
void Algori::Pilotage_chaque_iteration(Vecteur* sol,double& maxDeltaDdl,const int& itera,LesMaillages * lesMail)
{ // -- sur ou sous relaxation
double sursousrelax = pa.SurSousRelaxation();
(*sol) *= sursousrelax;
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 3)) || (permet_affichage > 2))
if (sursousrelax != 1.)
{if(ParaGlob::Francais())
{cout << "\n intervention d'une sur-sous relaxation: ";}
else {cout << "\n intervention of an over or under relaxation: ";};
cout << sursousrelax;
};
// --limitation de la norme de delta ddl
// dans le cas où le maxi de variation de ddl est supérieur à la limite fixée on ramène la valeur
if (pa.NormeMax_increment() > 0.)
{// cas d'une limitation globale (tout le vecteur sol change
if (maxDeltaDdl > pa.NormeMax_increment())
{ double facteur=(pa.NormeMax_increment()/maxDeltaDdl);
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof ";};
cout << facteur;
};
(*sol) *= facteur;
// mise à jour du maxi de variation de ddl
maxDeltaDdl = pa.NormeMax_increment();
};
}
else // ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
{// cas d'une limitation globale (tout le vecteur sol change
if (maxDeltaDdl > Abs(pa.NormeMax_increment()))
{ double maxa= Abs(pa.NormeMax_increment());
Vecteur & vect = *sol; // pour simplifier
int taill=vect.Taille();
bool modif = false;
for (int i=1;i<= taill;i++)
{ if (Abs(vect(i)) > maxa)
{ vect(i) = Signe(vect(i),maxa); modif = true;};
};
if (modif)
{if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl, limitation des maxis ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof, limitation of the maxis ";};
};
};
// mise à jour du maxi de variation de ddl
maxDeltaDdl = maxa;
};
};
// -- indication de précision pour les éléments (utilisée pour certain type de gestion d'hourglass)
// pour l'instant l'idée est la suivante: si le résidu augmente => on demande un calcul précis sur les éléments
// pour le prochain calcul
int nb_cycle_controle = MaX(2,pa.NbCycleControleResidu());
if (itera == 0)
{ lesMail->Drapeau_preparation_calcul_precis(10);} // par défaut à l'itération 0 on demande un calcul précis
if (itera > 1)
{ bool change = false; // indicateur pour la demande d'un calcul précis
if (itera <= nb_cycle_controle)
{ if (max_var_residu(itera) > max_var_residu(itera-1)) change = true;}
else { if (max_var_residu(nb_cycle_controle) > max_var_residu(nb_cycle_controle-1)) change = true;};
if (change) // dans le cas où le résidu augmente => on demande un calcul précis sur les éléments
{ lesMail->Drapeau_preparation_calcul_precis(4);}
else {lesMail->Drapeau_preparation_calcul_precis(4);}; // sinon pas de modif
};
};
// pilotage pour l'initialisation de Xtdt à chaque début d'incrément, en implicite
// avec la même direction qu'au pas précédent
// ramène true, si c'est ok pour initialiser Xtdt
bool Algori::Pilotage_init_Xtdt()
{ return (nombre_de_mauvaises_convergences <= 2);
};
// pilotage en dynamique implicite, du maxi des déplacements et/ou vitesses
// limitation spécifiquement des maxi en déplacements et/ou vitesses
// il y a calcul éventuel de delta_X, mais c'est considéré comme une variable de travail
void Algori::Pilotage_maxi_X_V(const Vecteur& X_t,Vecteur& X_tdt,const Vecteur& V_t,Vecteur& V_tdt)
{ // --limitation de la norme de delta X
// dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur
double normeMax_X_increment = pa.NormeMax_X_increment();
if ((normeMax_X_increment > 0.)&&( normeMax_X_increment!= ConstMath::tresgrand))
{// cas d'une limitation globale sur X
if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille());
vec_trav = X_tdt; vec_trav -= X_t;
double maxDeltaDdl=vec_trav.Max_val_abs();
if (maxDeltaDdl > normeMax_X_increment)
{ double facteur=(normeMax_X_increment/maxDeltaDdl);
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur delta X ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X ";};
cout << facteur << "( maxDeltaX= " << maxDeltaDdl<<")";
};
vec_trav *= facteur;
X_tdt = X_t; X_tdt += vec_trav;
};
}
else if ( normeMax_X_increment!= ConstMath::tresgrand)
// cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
{// cas d'une limitation globale (tout le vecteur sol change
int taill=X_t.Taille();
if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille());
vec_trav = X_tdt; vec_trav -= X_t;
double maxDeltaDdl=vec_trav.Max_val_abs();
if (maxDeltaDdl > -normeMax_X_increment)
{ double maxa= -normeMax_X_increment;
bool modif = false;
for (int i=1;i<= taill;i++)
{ if (Abs(vec_trav(i)) > maxa)
{ vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;};
};
if (modif)
{if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur delta X, limitation des maxis ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X, limitation of the maxis ";};
};
X_tdt = X_t; X_tdt += vec_trav;
};
};
};
// --limitation de la norme de delta V
// dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur
double normeMax_V_increment = pa.NormeMax_V_increment();
if ((normeMax_V_increment > 0.)&&( normeMax_V_increment!= ConstMath::tresgrand))
{// cas d'une limitation globale sur V
if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille());
vec_trav = V_tdt; vec_trav -= V_t;
double maxDeltaDdl=vec_trav.Max_val_abs();
if (maxDeltaDdl > normeMax_V_increment)
{ double facteur=(normeMax_V_increment/maxDeltaDdl);
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur delta V ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V ";};
cout << facteur ;
};
vec_trav *= facteur;
V_tdt = V_t; V_tdt += vec_trav;
};
}
else if ( normeMax_V_increment!= ConstMath::tresgrand)
// cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées
{// cas d'une limitation globale (tout le vecteur sol change
int taill=V_t.Taille();
if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille());
vec_trav = V_tdt; vec_trav -= V_t;
double maxDeltaDdl=vec_trav.Max_val_abs();
if (maxDeltaDdl > -normeMax_V_increment)
{ double maxa= -normeMax_V_increment;
bool modif = false;
for (int i=1;i<= taill;i++)
{ if (Abs(vec_trav(i)) > maxa)
{ vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;};
};
if (modif)
{if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 0))
{if(ParaGlob::Francais())
{cout << "\n ===>>>>> intervention de la reduction du vecteur delta V, limitation des maxis ";}
else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V, limitation of the maxis ";};
};
V_tdt = V_t; V_tdt += vec_trav;
};
};
};
};
// passage des grandeurs gérées par l'algorithme de tdt à t
// en particulier les énergies et les puissances
void Algori::TdtversT()
{ // cas du calcul des énergies, passage des grandeurs de tdt à t
// les énergies globales
E_cin_t=E_cin_tdt; E_int_t = E_int_tdt; E_ext_t = E_ext_tdt;
// la quantité de mouvement globale
q_mov_t = q_mov_tdt;
// les forces internes et externes généralisées
F_int_t = F_int_tdt; F_ext_t = F_ext_tdt;
// l'énergie visqueuse numérique
E_visco_numerique_t=E_visco_numerique_tdt;
// les puissances
P_acc_t = P_acc_tdt; P_int_t = P_int_tdt; P_ext_t = P_ext_tdt; bilan_P_t = bilan_P_tdt;
// cas particulier de l'amortissement cinétique à chaque noeud
if (amortissement_cinetique_au_noeud)
E_cinNoe_t = E_cinNoe_tdt;
};
// vérification d'une singularité éventuelle de la matrice de raideur de dim: nbddl
// pour un problème de mécanique, en comparant le nombre de point d'intégration total
// et le nombre totale de degré de liberté
void Algori::VerifSingulariteRaideurMeca(int nbddl,const LesMaillages& lesMail) const
{
#ifdef UTILISATION_MPI
// cas d'un calcul //, seule la matrice du CPU 0 est concernée
if (ParaGlob::Monde()->rank() != 0)
return ;
#endif
if (ParaGlob::NiveauImpression() != 0)
{ // récup du nombre de grandeurs génératrices
// Enum_ddl enu(SIG11); // init par défaut
// on récupère la liste des problèmes physiques gérés par les éléments de tous les maillages
const list <Enum_ddl >& li = lesMail.Ddl_representatifs_des_physiques();
// on boucle sur la liste
list <Enum_ddl >::const_iterator ili,iliend = li.end();
int nbpt=0; // init
for (ili = li.begin();ili != iliend; ili++)
nbpt += lesMail.NbTotalGrandeursGeneratrices(*ili);
// affichage
const double ratio = 1.2; // le pourcentage
if (nbpt < ratio * nbddl)
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0))
{ cout << "\n *** Attention, le nombre total de grandeurs generatrices aux point d'integrations dans "
<< " le probleme: " << nbpt << " est inferieur "
<< " a " << ratio << " * le nombre total de ddl du probleme !! c-a-d: "<< int(ratio * nbddl)
<< "\n en consequence il est possible que la matrice de raideur soit naturellement singuliere \n\n ";
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 7)) || (permet_affichage > 0))
cout << "\n void Algori::VerifSingulariteRaideurMeca(... ";
};
};
};
// retouve le numéro de l'incrément sauvegardé trouvé dont le numéro est juste inf ou égale au
// dernier incrément calculé - nb_incr_en_arriere.
// ramène false si on n'a pas trouvé d'incrément a-doc
// en retour icharge prend la valeur de l'incrément trouvé (si tout c'est bien passé)
bool Algori::Controle_retour_sur_un_increment_enregistre(int nb_incr_en_arriere,int& icharge)
{ // tout d'abord on calcul le numéro d'incrément auquel il faut se placer
List_io <Entier_et_Double>::iterator inc_ok = list_incre_temps_calculer.begin();
List_io <Entier_et_Double>::iterator inc_fin = list_incre_temps_calculer.end();
for (int i=1;i<=nb_incr_en_arriere;i++)
if (inc_ok != inc_fin)
{inc_ok++; } // les incréments sont rangés du dernier vers le premier
else
{return false;}; // sinon l'opération n'est pas possible
// donc inc_ok représente maintenant le num maxi à partir duquel on va chercher un incrément enregistré
List_io <Entier_et_Double>::iterator in_sauve = list_incre_temps_sauvegarder.begin();
List_io <Entier_et_Double>::iterator in_sauve_fin = list_incre_temps_sauvegarder.end();
// on recherche le premier incrément sauvegardé juste inf à celui que l'on s'est fixé
while (((*in_sauve).n > (*inc_ok).n)&&(in_sauve != in_sauve_fin))
in_sauve++;
// on vérifie que l'incrément est valide sinon on est obligé d'arrêter
if (in_sauve == in_sauve_fin)
{return false;}; // opération non possible
// sinon c'est ok
icharge = (*in_sauve).n;
return true;
};
// cohérence du type de convergence adopté en fonction de l'algorithme: par exemple on vérifie que l'on n'utilise
// pas une convergence sur l'énergie cinétique avec un algo statique !!
void Algori::Coherence_Algo_typeConvergence()
{ if ((Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE)
&& (strstr(pa.Norme().nom1.c_str(),"E_cinetique/E_statique"))
&& (Evolution_temporelle_du_calcul(typeCalcul) != AUCUNE_EVOLUTION))
{ cout << "\n *** erreur: utilisation de la norme E_cinetique/E_statique avec un calcul non dynamique"
<< " arret ! ";
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5)) || (permet_affichage > 0))
cout << "\n Algori::Coherence_Algo_typeConvergence() ";
// dans le cas où un comptage du calcul est en cours on l'arrête
if (tempsCalEquilibre.Comptage_en_cours())
tempsCalEquilibre.Arret_du_comptage();
Sortie(1);
};
};