Gérard Rio
ea11c75ff8
- fct nD: amélioration message d'erreur (arguments), et en fct du niveau géré par une fct nD - première validation du fct. en // en implicite statique et en RD, nombreuses modifications et amélioration ! Signed-off-by: Gérard Rio <gerardrio56@free.fr>
2208 lines
120 KiB
C++
2208 lines
120 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 "AlgoriNonDyna.h"
|
|
#include "MatBand.h"
|
|
#include <cmath>
|
|
|
|
//------- décomposition en 3 du calcul d'équilibre -------------
|
|
// a priori : InitAlgorithme et FinCalcul ne s'appellent qu'une fois,
|
|
// par contre : CalEquilibre peut s'appeler plusieurs fois, le résultat sera différent si entre deux calcul
|
|
// certaines variables ont-été changés
|
|
|
|
|
|
// initialisation
|
|
void AlgoriNonDyna::InitAlgorithme(ParaGlob * paraGlob,LesMaillages * lesMail,
|
|
LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor
|
|
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
|
|
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts
|
|
,Resultats* resultats)
|
|
{ // INITIALISATION globale
|
|
tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
|
|
|
|
#ifdef UTILISATION_MPI
|
|
// calcul de l'équilibrage initiale par le cpu 0
|
|
if (distribution_CPU_algo.Tableau_element_CPU_en_cours()->Taille() == 0 )
|
|
{distribution_CPU_algo.Calcul_Equilibrage_initiale(lesMail,lesContacts);
|
|
tempsInitialisation.Arret_du_comptage(); // temps cpu
|
|
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
distribution_CPU_algo.Passage_Equilibrage_aux_CPU();
|
|
temps_transfert_court_algo.Arret_du_comptage(); // comptage cpu
|
|
tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
|
|
paraGlob->Init_tableau(distribution_CPU_algo.Tableau_element_CPU_en_cours()
|
|
,distribution_CPU_algo.Tab_indique_CPU_en_cours()
|
|
,distribution_CPU_algo.Tableau_noeud_CPU_en_cours()
|
|
,distribution_CPU_algo.Tab_indique_noeud_CPU_en_cours());
|
|
};
|
|
#endif
|
|
|
|
|
|
////------- debug
|
|
//cout << "\n debug AlgoriNonDyna::InitAlgorithme ";
|
|
//lesMail->Noeud_LesMaille(1,120).Affiche(9);
|
|
//cout << endl;
|
|
////-------- fin debug
|
|
|
|
// avant toute chose, au cas où l'algo interviendrait après un autre algo
|
|
// on inactive tous les ddl existants
|
|
lesMail->Inactive_ddl();
|
|
// on regarde s'il s'agit d'un pb purement non méca, dans ce cas il faut cependant initialiser les positions
|
|
// à t et tdt pour le calcul de la métrique associée
|
|
{ const list <EnumElemTypeProblem >& type_pb = lesMail->Types_de_problemes();
|
|
bool purement_non_meca = true;
|
|
list <EnumElemTypeProblem >::const_iterator il,ilfin=type_pb.end();
|
|
for (il=type_pb.begin();il != ilfin; il++)
|
|
{switch (*il)
|
|
{ case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE:
|
|
purement_non_meca=false; break;
|
|
default: break; // sinon on ne fait rien
|
|
};
|
|
};
|
|
if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0
|
|
{lesMail->Init_Xi_t_et_tdt_de_0();}
|
|
else // dans le cas où il y a de la mécanique, on active X1
|
|
{ lesMail->Active_un_type_ddl_particulier(X1);
|
|
};
|
|
};
|
|
|
|
// on défini globalement que l'on a pas de combinaison des ddl c'est à dire que le seul ddl est X
|
|
// ou TEMP pour la température ...
|
|
cas_combi_ddl=0;
|
|
// cas du chargement, on verifie egalement la bonne adequation des references
|
|
charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD);
|
|
// on indique que l'on ne souhaite le temps fin stricte, vrai par défaut en implicite
|
|
charge->Change_temps_fin_non_stricte(0);
|
|
// dans le cas où l'on calcul des contraintes et/ou déformation et/ou un estimateur d'erreur
|
|
// à chaque incrément, initialisation
|
|
prepa_avec_remont =
|
|
Algori::InitRemont(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats);
|
|
if ( prepa_avec_remont)// remise enservice des ddl du pab
|
|
{lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);};
|
|
// on définit un nouveau cas d'assemblage
|
|
// à travers la définition d'une instance de la classe assemblage
|
|
if (Ass_ == NULL) Ass_ = new Assemblage(lesMail->InitNouveauCasAssemblage(1));
|
|
Assemblage& Ass = *Ass_;
|
|
// mise à jour du nombre de cas d'assemblage pour les conditions limites
|
|
// c-a-d le nombre maxi possible (intégrant les autres pb qui sont résolu en // éventuellement)
|
|
lesCondLim->InitNombreCasAssemblage(lesMail->Nb_total_en_cours_de_cas_Assemblage());
|
|
// mise a zero de tous les ddl et creation des tableaux a t+dt
|
|
// les ddl de position ne sont pas mis a zero ! ils sont initialise
|
|
// a la position courante
|
|
lesMail->ZeroDdl(true);
|
|
// on vérifie que les noeuds sont bien attachés à un élément sinon on met un warning si niveau > 2
|
|
if (ParaGlob::NiveauImpression() > 2)
|
|
lesMail->AffichageNoeudNonReferencer();
|
|
// init des ddl avec les conditions initials
|
|
lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl);
|
|
|
|
|
|
// L'algorithme peut s'appliquer à plusieurs types de problème: création des types de ddl du pb en fonction
|
|
// des physiques
|
|
lesMail->Active_un_type_ddl_particulier(lesMail->Ddl_representatifs_des_physiques());
|
|
// lesMail->Active_un_type_ddl_particulier(X1);
|
|
lesMail->MiseAJourPointeurAssemblage(Ass.Nb_cas_assemb());// mise a jour des pointeurs d'assemblage
|
|
|
|
// mise en place éventuelle du bulk viscosity: pas prévue au départ donc exploratoire !!
|
|
lesMail->Init_bulk_viscosity(pa.BulkViscosity(),pa.CoefsBulk());
|
|
|
|
//---- arrêt intro thermique --- la suite à suivre !!!!!!!!!
|
|
int nbddl_X = lesMail->NbTotalDdlActifs(); // nb total de ddl
|
|
|
|
// choix de la matrice de raideur du système linéaire (calcul éventuellement d'une largeur de bande ad oc)
|
|
// ici, au niveau init, on démarre sans contact, son action sera ensuite rajoutée
|
|
Choix_matriciel(nbddl_X,tab_mato,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim,NULL);
|
|
matglob = tab_mato(1); // par défaut c'est la première matrice
|
|
// dans le cas où l'on veut également utiliser du Newton modifié, on definit la matrice de sauvegarde
|
|
if (deb_newton_modifie >= 0)
|
|
Choix_matriciel(nbddl_X,tab_matsauve,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
|
|
matsauve = tab_matsauve(1); // par défaut c'est la première matrice
|
|
// dans le cas où l'on veut utiliser une raideur moyenne on définit les sous-matrices
|
|
// pour chaque niveau secondaire
|
|
if (deb_raideur_moyenne >= 0)
|
|
// on boucle sur les groupes de matrices
|
|
{
|
|
// comme il s'agit du premier dimensionnement on commence par tout supprimer
|
|
// au cas où quelque chose existait déjà
|
|
{int taille = tab_tab_matmoysauve.Taille();
|
|
for (int i=1;i<=taille;i++)
|
|
if (tab_tab_matmoysauve(i)!= NULL)
|
|
{Tableau <Mat_abstraite*> * tab_matmoysauve_i = tab_tab_matmoysauve(i); // par simplicité
|
|
int tail = tab_matmoysauve_i->Taille();
|
|
for (int j=1; j<= tail;j++)
|
|
if ((*tab_matmoysauve_i)(j) != NULL)
|
|
delete (*tab_matmoysauve_i)(j);
|
|
};
|
|
};
|
|
// puis on redimensionne le tableau maître de pointeurs
|
|
// nb_mat_secondaire = le nb de table secondaire + 1
|
|
int nb_mat_secondaire = tab_mato.Taille();
|
|
tab_tab_matmoysauve.Change_taille(nb_raideur_moyenne,NULL);
|
|
// maintenant on crée les sous tableaux de pointeurs nulles
|
|
for (int i=1;i<=nb_raideur_moyenne;i++)
|
|
{tab_tab_matmoysauve(i) = new Tableau<Mat_abstraite*>;
|
|
tab_tab_matmoysauve(i)->Change_taille(nb_mat_secondaire,NULL);
|
|
};
|
|
// maintenant on peu créer les matrices
|
|
for (int i=1;i<=nb_raideur_moyenne;i++)
|
|
{ Tableau <Mat_abstraite*>& tab_matmoysauve_i = *tab_tab_matmoysauve(i);
|
|
Choix_matriciel(nbddl_X,tab_matmoysauve_i,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
|
|
};
|
|
};
|
|
|
|
// on refait une passe dans le cas où l'utilisateur veut une renumérotation des pointeurs
|
|
// d'assemblage, globalement
|
|
{bool premier_calcul=true;bool nouvelle_situation_CLL=false;
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
Gestion_stockage_et_renumerotation_sans_contact
|
|
(lesContacts,premier_calcul,lesMail,nouvelle_situation_CLL
|
|
,lesCondLim,lesRef,tab_mato,Ass.Nb_cas_assemb()
|
|
,niveau_substitution);
|
|
};
|
|
|
|
// choix de la résolution pour la première matrice
|
|
matglob->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
|
|
// vérification d'une singularité éventuelle de la matrice de raideur
|
|
// à cause d'un trop faible nombre de pti
|
|
VerifSingulariteRaideurMeca(nbddl_X,*lesMail);
|
|
// def vecteurs globaux
|
|
vglobin.Change_taille(nbddl_X); // puissance interne
|
|
vglobex.Change_taille(nbddl_X); // puissance externe
|
|
vglobaal.Change_taille(nbddl_X,0.); // puissance totale
|
|
// même si le contact n'est pas encore actif, il faut prévoir qu'il le deviendra peut-être !
|
|
if (lesMail->NbEsclave() != 0)
|
|
vcontact.Change_taille(nbddl_X); // puissance de contact
|
|
// dans le cas où on initialise les ddl_tdt(n) avec les ddl_t(n)+delta_ddl(n-1), def de grandeurs
|
|
X_t.Change_taille(nbddl_X);X_tdt.Change_taille(nbddl_X); delta_X.Change_taille(nbddl_X);
|
|
delta_prec_X.Change_taille(nbddl_X);var_delta_X.Change_taille(nbddl_X);
|
|
// calcul des énergies
|
|
if (pa.Amort_visco_artificielle()) // dans le cas d'un amortissement artificiel
|
|
forces_vis_num.Change_taille(nbddl_X,0.);
|
|
E_int_t = 0.; E_int_tdt = 0.; // init des différentes énergies
|
|
E_ext_t = 0.; E_ext_tdt = 0.; bilan_E = 0.; // " et du bilan
|
|
F_int_t.Change_taille(nbddl_X); F_ext_t.Change_taille(nbddl_X); // forces généralisées int et ext au pas précédent
|
|
F_int_tdt.Change_taille(nbddl_X); F_ext_tdt.Change_taille(nbddl_X); // forces généralisées int et ext au pas actuel
|
|
residu_final.Change_taille(nbddl_X); // pour la sauvegarde du résidu pour le post-traitement
|
|
|
|
// définition d'un pointeur de fonction d'assemblage en fonction du type voulu
|
|
// (symetrique ou non), utilisé dans la prise en compte des efforts extérieurs
|
|
if (pa.Symetrie_matrice())
|
|
// cas d'un assemblage symétrique
|
|
assembMat = & Assemblage::AssembMatSym;
|
|
else // cas d'un assemblage non symétrique
|
|
assembMat = & Assemblage::AssembMatnonSym;
|
|
|
|
// dans le cas où l'on fait du line search on dimensionne des vecteurs
|
|
// globaux supplémentaires
|
|
if (pa.Line_search())
|
|
{ sauve_deltadept = new Vecteur(nbddl_X);
|
|
Vres = new Vecteur(nbddl_X);
|
|
sauve_dept_a_tdt = new Vecteur(nbddl_X);
|
|
v_travail = new Vecteur(nbddl_X);
|
|
}
|
|
else if (acceleration_convergence)
|
|
// idem pour l'accélération de convergence, pour la sauvegarde du résidu
|
|
{ Vres = new Vecteur(nbddl_X);
|
|
for (int ni =1;ni<= nb_vec_cycle+2;ni++)
|
|
{ if (cas_acceleration_convergence < 4)
|
|
{Vi(ni).Change_taille(nbddl_X);}
|
|
else if (cas_acceleration_convergence == 4)
|
|
{Vi(ni).Change_taille(1);};
|
|
Yi(ni).Change_taille(nbddl_X);
|
|
};
|
|
};
|
|
|
|
// initi boucle sur les increments de charge
|
|
icharge = 0;
|
|
|
|
// definition des elements de frontiere, ces elements sont utilises pour le contact
|
|
lesMail->CreeElemFront();
|
|
// calcul éventuel des normales aux noeuds -> init des normales pour t=0
|
|
lesMail->InitNormaleAuxNoeuds(); //utilisé pour la stabilisation des membranes par ex
|
|
// --- init du contact ---
|
|
// doit-être avant la lecture d'un restart, car il y a une initialisation de conteneurs qui est faites
|
|
// qui ensuite est utilisée en restart
|
|
// par exemple il faut initialiser les frontières et la répartition esclave et maître
|
|
// pour préparer la lecture de restart éventuel
|
|
if (lesMail->NbEsclave() != 0)
|
|
{ lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
// initialisation des zones de contacts éventuelles
|
|
lesContacts->Init_contact(*lesMail,*lesRef,lesFonctionsnD);
|
|
// verification qu'il n'y a pas de contact avant le premier increment de charge
|
|
lesContacts->Verification();
|
|
if (pa.ContactType() == 4) // cas particulier du type 4 de contact où on utilise les forces internes
|
|
{// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
|
|
Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif pour un vecteur force à chaque noeud
|
|
TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
|
|
lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
|
|
};
|
|
// definition des elements de contact eventuels
|
|
// et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
|
|
// double diam_mini = lesMail->Min_dist2Noeud_des_elements(TEMPS_0);
|
|
// lesContacts->DefElemCont(2. * diam_mini);
|
|
try {
|
|
// definition des elements de contact eventuels
|
|
// et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
|
|
bool nevez_contact = lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
|
|
|
|
// #ifdef UTILISATION_MPI
|
|
// if (ParaGlob::Monde()->rank() == 0)
|
|
// { cout << "\n debug AlgoriNonDyna::InitAlgorithme fin transitoire proc 0";
|
|
// cout << "\n taper une lettre pour stopper ";
|
|
// string toto;
|
|
// cin >> toto;
|
|
// int nb_process = ParaGlob::Monde()->size();
|
|
// for (int i=1;i<nb_process;i++) // < absolu, donc le max c'est nb_process-1
|
|
// { // on envoie un signal de re démarrage au process i
|
|
// ParaGlob::Monde()->send(i, 100, std::string("redemarrage"));
|
|
// };
|
|
// Sortie(1);
|
|
// }
|
|
// else
|
|
// { cout << "\n debug AlgoriNonDyna::InitAlgorithme fin transitoire proc " << ParaGlob::Monde()->rank();
|
|
// // on attend le message de redémarrage du proc 0
|
|
// std::string msg;
|
|
// ParaGlob::Monde()->recv(0, 100, msg);
|
|
// Sortie(1);
|
|
// };
|
|
// #endif
|
|
|
|
|
|
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
bool premier_calcul = true;
|
|
// mise à jour éventuelle de la matrice de raideur en fonction du contact
|
|
//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,nevez_contact,lesCondLim
|
|
,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
}
|
|
// sortie anormale de l'initialisation du contact
|
|
catch (ErrSortieFinale)
|
|
// cas d'une direction voulue vers la sortie
|
|
// on relance l'interuption pour le niveau supérieur
|
|
{ ErrSortieFinale toto;
|
|
throw (toto);
|
|
}
|
|
catch (...)// erreur inconnue
|
|
{ cout << "\n **** >>>> ERREUR inconnuee en en initialisant le contact ***** ";
|
|
if (ParaGlob::NiveauImpression() >= 4)
|
|
cout << "\n AlgoriNonDyna::InitAlgorithme(..";
|
|
cout << endl;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
//--cas de restart et/ou de sauvegarde------------
|
|
// tout d'abord récup du restart si nécessaire
|
|
// dans le cas ou un incrément différent de 0 est demandé -> seconde lecture à l'incrément
|
|
brestart=false; // booleen qui indique si l'on est en restart ou pas
|
|
if (this->Num_restart() != 0)
|
|
{ int cas = 2;
|
|
////---debug
|
|
//{cout << "\n debug1: AlgoriNonDyna::InitAlgorithme(...";
|
|
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
|
|
// noe.Affiche();
|
|
//}
|
|
////--fin-debug // ouverture de base info
|
|
entreePrinc->Ouverture_base_info("lecture");
|
|
this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,(this->Num_restart()));
|
|
// on ferme tout de suite le baseinfo en lecture de manière à éviter des pb de switch
|
|
// lecture -> écriture, si le fichier est très gros
|
|
entreePrinc->Fermeture_base_info();
|
|
icharge = this->Num_restart();//+1;
|
|
brestart = true;
|
|
////---debug
|
|
//{cout << "\n debug2: AlgoriNonDyna::InitAlgorithme(...";
|
|
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
|
|
// noe.Affiche();
|
|
//}
|
|
////--fin-debug // ouverture de base info
|
|
|
|
// comme les conditions limites cinématiques peuvent être différentes en restart
|
|
// par rapport à celles sauvegardées, on commence par libérer toutes les CL imposées éventuelles
|
|
lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
|
|
////---debug
|
|
//{cout << "\n debug3: AlgoriNonDyna::InitAlgorithme(...";
|
|
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
|
|
// noe.Affiche();
|
|
//}
|
|
//--fin-debug // ouverture de base info
|
|
lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
|
|
// dans le cas d'un calcul axisymétrique on bloque le ddl 3
|
|
if (ParaGlob::AxiSymetrie())
|
|
lesMail->Inactive_un_ddl_particulier(X3);
|
|
// on valide l'activité des conditions limites et condition linéaires, pour le temps initial
|
|
// en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
////---debug
|
|
//{cout << "\n debug4: AlgoriNonDyna::InitAlgorithme(...";
|
|
// Noeud& noe = lesMail->Noeud_LesMaille(1,4);
|
|
// noe.Affiche();
|
|
//}
|
|
////--fin-debug // ouverture de base info
|
|
// on remet à jour les éléments pour le contact s'il y du contact présumé
|
|
if (pa.ContactType())
|
|
{ // mise à jour pour le contact s'il y du contact présumé
|
|
if (lesMail->NbEsclave() == 0)
|
|
// là pb
|
|
{cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact "
|
|
<< " la definition d'un type contact possible est donc incoherente "
|
|
<< " revoir la mise en donnees !! "<< flush;
|
|
Sortie(1);
|
|
};
|
|
// sinon ok, et on met à jour la boite d'encombrement compte tenue des nouvelles coordonnées
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
bool nevez_contact = lesContacts->Actualisation(0);
|
|
// *** test
|
|
bool nevez_bis_contact = lesContacts->Nouveau(0.);
|
|
nevez_contact = (nevez_contact || nevez_bis_contact); //double dep_max)
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
bool premier_calcul = true;
|
|
// mise à jour éventuelle de la matrice de raideur en fonction du contact
|
|
//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,nevez_contact,lesCondLim
|
|
,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
if (deb_newton_modifie >= 0)
|
|
(*matsauve) = (*matglob);
|
|
// dans le cas où l'on veut utiliser une raideur moyenne on redéfinit les matrices
|
|
if (deb_raideur_moyenne >= 0)
|
|
{ Tableau <Mat_abstraite*>& tab_matmoysauve = *tab_tab_matmoysauve(1);
|
|
tab_matmoysauve.Change_taille(nb_raideur_moyenne);
|
|
for (int i=1;i<= nb_raideur_moyenne;i++)
|
|
(*tab_matmoysauve(i)) = (*matglob);
|
|
};
|
|
};
|
|
};
|
|
// vérif de cohérence pour le contact
|
|
if ((pa.ContactType()) && (lesMail->NbEsclave() == 0)) // là pb
|
|
{cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact "
|
|
<< " la definition d'un type contact possible est donc incoherente "
|
|
<< " revoir la mise en donnees !! "<< flush;
|
|
Sortie(1);
|
|
};
|
|
// on regarde s'il y a besoin de sauvegarde
|
|
if (this->Active_sauvegarde() && (ParaGlob::param->TypeCalcul_maitre() == this->typeCalcul) )
|
|
{ // si le fichier base_info n'est pas en service on l'ouvre
|
|
entreePrinc->Ouverture_base_info("ecriture");
|
|
// dans le cas ou se n'est pas un restart on sauvegarde l'incrément actuel
|
|
// c'est-à-dire le premier incrément
|
|
// après s'être positionné au début du fichier
|
|
if (this->Num_restart() == 0)
|
|
{ (entreePrinc->Sort_BI())->seekp(0);
|
|
int cas = 1;
|
|
paraGlob->Ecriture_base_info(*(entreePrinc->Sort_BI()),cas);
|
|
this->Ecriture_base_info
|
|
(cas,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,OrdreVisu::INCRE_0);
|
|
}
|
|
else
|
|
{ // sinon on se place dans le fichier à la position du restart
|
|
// debut_increment a été définit dans algori (classe mère)
|
|
(entreePrinc->Sort_BI())->seekp(debut_increment);
|
|
};
|
|
};
|
|
|
|
// init de var glob
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
//--fin cas de restart et/ou de sauvegarde--------
|
|
type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
|
|
|
|
// ajout d'un conteneur pour les coordonnées à l'itération 0
|
|
{Coordonnee coor(ParaGlob::Dimension()); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif à chaque noeud
|
|
TypeQuelconque typQ_gene_int(XI_ITER_0,X1,gt);
|
|
lesMail->AjoutConteneurAuNoeud(typQ_gene_int);
|
|
};
|
|
|
|
// mise à jour au cas où
|
|
Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats);
|
|
tempsInitialisation.Arret_du_comptage(); // temps cpu
|
|
|
|
};
|
|
// mise à jour
|
|
void AlgoriNonDyna::MiseAJourAlgo(ParaGlob * paraGlob,LesMaillages * lesMail,
|
|
LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor
|
|
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
|
|
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts
|
|
,Resultats* resultats)
|
|
{ // INITIALISATION globale
|
|
tempsMiseAjourAlgo.Mise_en_route_du_comptage(); // temps cpu
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
|
|
|
|
// on regarde le type de calcul: tout n'est pas possible pour l'instant !!
|
|
const list <EnumElemTypeProblem >& type_pb = lesMail->Types_de_problemes();
|
|
bool purement_non_meca = true;
|
|
list <EnumElemTypeProblem >::const_iterator il,ilfin=type_pb.end();
|
|
for (il=type_pb.begin();il != ilfin; il++)
|
|
{switch (*il)
|
|
{ case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE:
|
|
purement_non_meca=false; break;
|
|
case THERMIQUE:
|
|
{cout << "\n *** cas non operationnel: pour l'instant MiseAjourAlgo "
|
|
<< " n'est prevu que pour de la meca ... "
|
|
<< "\n AlgoriNonDyna::MiseAJourAlgo(...)" ;
|
|
Sortie(1);
|
|
break;
|
|
}
|
|
default: break; // sinon on ne fait rien
|
|
};
|
|
};
|
|
if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0
|
|
{lesMail->Init_Xi_t_et_tdt_de_0();
|
|
// il faut sans doute faire plus de chose, par exemple activer les ddl particuliers
|
|
cout << "\n *** cas non operationnel: pour l'instant MiseAjourAlgo "
|
|
<< " n'est prevu que pour de la meca ... "
|
|
<< "\n AlgoriNonDyna::MiseAJourAlgo(...)" ;
|
|
Sortie(1);
|
|
}
|
|
else // dans le cas où il y a de la mécanique, et que l'on a récupéré des ddl de vitesse et d'accélération
|
|
{ // on les inactives
|
|
lesMail->Inactive_un_type_ddl_particulier(V1);
|
|
lesMail->Inactive_un_type_ddl_particulier(GAMMA1);
|
|
lesMail->Active_un_type_ddl_particulier(X1);
|
|
};
|
|
// mise à jour au cas où
|
|
Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp
|
|
,diversStockage,charge,lesCondLim,lesContacts,resultats);
|
|
tempsMiseAjourAlgo.Arret_du_comptage(); // temps cpu
|
|
};
|
|
|
|
// calcul de l'équilibre
|
|
// calcul
|
|
// si tb_combiner est non null -> un tableau de 2 fonctions
|
|
// - la première fct dit si on doit valider ou non le calcul à convergence ok,
|
|
// - la seconde dit si on doit sortir de la boucle ou non à convergence ok
|
|
//
|
|
// si la validation est effectuée, la sauvegarde pour le post-traitement est également effectuée
|
|
// en fonction de la demande de sauvegard,
|
|
// sinon pas de sauvegarde pour le post-traitement à moins que l'on a demandé un mode debug
|
|
// qui lui fonctionne indépendamment
|
|
void AlgoriNonDyna::CalEquilibre(ParaGlob * paraGlob,LesMaillages * lesMail
|
|
,LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor
|
|
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage
|
|
,Charge* charge,LesCondLim* lesCondLim,LesContacts* lescontacts
|
|
,Resultats* resultats,Tableau < Fonction_nD* > * tb_combiner)
|
|
|
|
{
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
|
|
|
|
// préparation pour les aspects validation du calcul et sortie contrôlée des incréments
|
|
int validation_calcul = 1; // init : par défaut la validation est effective si le calcul converge
|
|
int sortie_boucle_controler_par_fctnD = 0; // init : par défaut la sortie n'est pas contrôler
|
|
|
|
// on vérifie que le pas de temps est correcte: on propose le deltat actuel qui sera modifié s'il n'est pas bon
|
|
double deltat_actuel = pa.Deltat();
|
|
pa.Modif_Detat_dans_borne(deltat_actuel);
|
|
|
|
// def d'un type générique, utilisé pour le transfert des forces internes, vers les conteneurs noeuds
|
|
int dim = ParaGlob::Dimension();if (ParaGlob::AxiSymetrie()) dim--;
|
|
Coordonnee coor(dim); // un type coordonnee typique
|
|
Grandeur_coordonnee gt(coor); // une grandeur typique de type Grandeur_coordonnee
|
|
// def d'un type quelconque représentatif pour un vecteur force à chaque noeud
|
|
TypeQuelconque typQ_gene_int(FORCE_GENE_INT,X1,gt);
|
|
|
|
// on définit un type générique qui sert pour passer aux noeuds les positions à l'itération 0
|
|
TypeQuelconque typQ_XI_ITER_0(XI_ITER_0,X1,gt);
|
|
|
|
// on met à jour des variables de travail
|
|
Assemblage& Ass = *Ass_;
|
|
Vecteur vglobal_sauv; // vecteur de sauvegarde éventuel, dans le cas de l'utilisation de matrices de raideur secondaire
|
|
double max_delta_X=0.; // le maxi du delta X
|
|
double max_var_delta_X=0.; // idem d'une itération à l'autre
|
|
|
|
// tant que la fin du chargement n'est pas atteinte
|
|
// dans le cas du premier chargement on calcul de toute manière, ce qui permet
|
|
// de calculer meme si l'utilisateur indique un increment de charge supérieur
|
|
// au temps final
|
|
bool arret_pilotage=false; // pour arrêt du calcul au niveau du pilotage
|
|
bool premier_calcul = true; // utilisé pour l'initialisation de l'incrément avec le pas précédent
|
|
int indicCycleContact = 0; // def d'un indicateur donnant la situation dans le cycle de contact
|
|
// un booléen pour uniquement gérer le fait que dans la boucle globale on fait le test après le test du while
|
|
// d'où pour le temps final, on peut sortir de la boucle globale sans avoir convergé, ce qui n'est pas bon
|
|
bool pas_de_convergence_pour_l_instant=1;
|
|
icharge++; // on incrémente le chargement -> donne le num d'incr du prochain incr chargé
|
|
while ( ((!charge->Fin(icharge,!pas_de_convergence_pour_l_instant)) // on n'affiche la situation
|
|
// que si on a eu convergence
|
|
|| pas_de_convergence_pour_l_instant ||(icharge == 1)
|
|
)
|
|
&& (charge->Fin(icharge,true)!=2) // si on a dépassé le nombre d'incrément permis on s'arrête dans tous les cas
|
|
&& (charge->Fin(icharge,false)!=3) // idem si on a dépassé le nombre d'essai d'incrément permis
|
|
// 1er appel avec true: pour affichage et second avec false car c'est déjà affiché
|
|
&& (!pa.EtatSortieEquilibreGlobal())
|
|
)
|
|
{ double maxPuissExt; // maxi de la puissance des efforts externes
|
|
double maxPuissInt; // maxi de la puissance des efforts internes
|
|
double maxReaction; // maxi des reactions
|
|
int inReaction = 0; // pointeur d'assemblage pour le maxi de reaction
|
|
int inSol =0 ; // pointeur d'assemblage du maxi de variation de ddl
|
|
double maxDeltaDdl=0; // // maxi de variation de ddl
|
|
double last_var_ddl_max=0; // maxi var ddl juste après résolutuion, que l'on sauvegarde d'une it à l'autre
|
|
// initialisation de la variable puissance_précédente d'une itération à l'autre
|
|
double puis_precedente = 0.;
|
|
Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
|
|
// affichage de l'increment de charge
|
|
bool aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
|
|
bool change_statut = false; // init des changements de statut, ne sert pas ici
|
|
|
|
// mise à jour du calcul éventuel des normales aux noeuds -> mise à jour des normales à t
|
|
// mais ici, on calcule les normales à tdt, et on transfert à t
|
|
// comme on est au début de l'incrément, la géométrie à tdt est identique à celle à t
|
|
// sauf "au premier incrément", si l'algo est un sous algo d'un algo combiné
|
|
// et que l'on suit un précédent algo sur un même pas de temps
|
|
// qui a aboutit à une géométrie à tdt différente de celle de t
|
|
// du coup cela permet d'utiliser la nouvelle géométrie pour ce premier incrément
|
|
lesMail->MiseAjourNormaleAuxNoeuds_de_tdt_vers_T();
|
|
// passage aux noeuds des vecteurs globaux: F_INT, F_EXT
|
|
Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(lesMail);
|
|
|
|
////--- debug
|
|
//if (premier_calcul)
|
|
// cout << "\toto "<<flush;
|
|
////--- fin debug
|
|
// premier contact de l'incrément
|
|
if (!indicCycleContact) // modification de la charge et du pas de temps qu'au premier passage
|
|
// mais pas après un changement de statut
|
|
{ Pilotage_du_temps(charge,arret_pilotage); // appel du Pilotage
|
|
if (arret_pilotage) break; // pilotage -> arret du calcul
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
#endif
|
|
if (aff_incr)
|
|
{cout << "\n======================================================================"
|
|
<< "\nINCREMENT DE CHARGE : " << icharge
|
|
<< " intensite " << charge->IntensiteCharge()
|
|
<< " t= " << charge->Temps_courant()
|
|
<< " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
|
|
<< "\n======================================================================";
|
|
};
|
|
// -- on regarde si l'on doit initialiser l'incrément avec le pas précédent: cas d'un premier calcul
|
|
// sinon c'est fait à la fin lors de la préparation pour le prochain incrément
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1); // sert pour calculer le delta_X après CL (**)
|
|
|
|
if ((!premier_calcul) && (delta_t_precedent_a_convergence > 0.)
|
|
&& pa.IniIncreAvecDeltaDdlPrec() && Pilotage_init_Xtdt()) // si oui, calcul
|
|
{ // de X_tdt = X_t + deltat(n)/deltat(n-1) *(X_tdt(n-1) - X_t(n-1))
|
|
delta_X = delta_prec_X; // init avec le précédent delta_X qui a convergé
|
|
X_tdt = X_t; delta_X *= pa.Deltat() * pa.IniIncreAvecDeltaDdlPrec(); X_tdt += delta_X;
|
|
// passage de ces nouvelles positions aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_tdt,X1);
|
|
};
|
|
|
|
// -- initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
|
|
// --- calcul des éléments de contact: (correspond à la définition de la surface de contact)
|
|
// definition ou mise à jour, des elements de contact eventuels
|
|
// - imposition (en fonction de l'algorithme de contact) de conditions particulières de penetration (nulle par exemple)
|
|
if (pa.ContactType()) // traitement différent lors du premier incément calculé (premier passage) puis des passages courants
|
|
{bool a_changer = false; // init par défaut
|
|
if (premier_calcul)
|
|
{a_changer = lescontacts->DefElemCont(max_delta_X);}
|
|
else
|
|
{ // on supprime les éléments inactifs testés à l'incr prec dans Actualisation()
|
|
a_changer = lescontacts->SuppressionDefinitiveElemInactif();
|
|
bool a_changer_nouveau = lescontacts->Nouveau(max_delta_X);
|
|
a_changer = a_changer || a_changer_nouveau;
|
|
};
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
if (premier_calcul || a_changer)
|
|
{//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,a_changer,lesCondLim,lesRef
|
|
,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
};
|
|
|
|
};
|
|
}
|
|
else
|
|
{if (arret_pilotage) break; // pilotage -> arret du calcul
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la sortie
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
#endif
|
|
cout << "\n============================================================================="
|
|
<< "\n ....... re-analyse du contact ........ "
|
|
<< "\nINCREMENT DE CHARGE : " << icharge << " intensite " << charge->IntensiteCharge()
|
|
<< " t= " << charge->Temps_courant()
|
|
<< " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
|
|
<< "\n============================================================================";
|
|
};
|
|
|
|
lesLoisDeComp->MiseAJour_umat_nbincr(icharge); // init pour les lois Umat éventuelles
|
|
|
|
// récupération (initialisation) des ddl position à t
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
|
|
|
|
// on démarre avec le compteur à 0 et on sauvegarde la position finale à l'itération 0
|
|
lesMail->Quelconque_glob_vers_local(X1,X_tdt,typQ_XI_ITER_0);
|
|
|
|
// boucle de convergence sur un increment
|
|
Vecteur * sol; // pointeur du vecteur solution
|
|
bool arret_convergence = false;
|
|
int tab_matmoysauve_rempli = 0; // ne sert que pour les matrices de raideur moyenne
|
|
// for (compteur = 0; compteur<= pa.Iterations();compteur++)
|
|
for (compteur = 0; (compteur<= pa.Iterations())&&(!pa.EtatSortieEquilibreGlobal()); compteur++)
|
|
//---//\\//\\// début de la boucle sur les itérations d'équilibres //\\//\\//
|
|
{// initialisation de la matrice et du second membre
|
|
matglob->Initialise(0.);
|
|
vglobin.Zero();
|
|
vglobex.Zero();
|
|
if (pa.ContactType())
|
|
vcontact.Zero();
|
|
vglobaal.Zero(); // puissance totale
|
|
|
|
// init de var glob
|
|
Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(compteur);
|
|
|
|
// prise en compte du cas particulier ou l'utilisateur demande
|
|
// une mise à jour des conditions limites à chaque itération
|
|
if (cL_a_chaque_iteration)
|
|
{// -- initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
};
|
|
|
|
// renseigne les variables définies par l'utilisateur via les valeurs déjà calculées par Herezh
|
|
// if (compteur > 0)
|
|
{Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(lesMail,varExpor,Ass.Nb_cas_assemb(),*lesRef);
|
|
varExpor->RenseigneVarUtilisateur(*lesMail,*lesRef);
|
|
};
|
|
lesMail->CalStatistique(); // calcul éventuel de statistiques
|
|
lesMail->Force_Ddl_aux_noeuds_a_une_valeur(R_X1,0.0,TEMPS_tdt,true); // mise à 0 des ddl de réactions, qui sont uniquement des sorties
|
|
lesMail->Force_Ddl_etendu_aux_noeuds_a_zero(Ddl_enum_etendu::Tab_FN_FT()); // idem pour les composantes normales et tangentielles
|
|
|
|
//---debug
|
|
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
//cout << "\ninitial Xtdt "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";cout << X_tdt(i)<<" ";}
|
|
//for (int j=1;j<=3;j++) cout << X_tdt((i-1)*3+j)<<" ";};
|
|
//--fin-debug
|
|
|
|
// mise en place des conditions linéaires (ne comprend pas les conditions linéaires de contact éventuelles)
|
|
lesCondLim->MiseAJour_condilineaire_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
//---debug
|
|
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
//cout << "\naprès condlin Xtdt "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";cout << X_tdt(i)<<" ";}
|
|
//for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";for (int j=1;j<=3;j++) cout << X_tdt((i-1)*3+j)<<" ";};
|
|
//--fin-debug
|
|
// affichage ou non de l'itération
|
|
bool aff_iteration = (pa.freq_affich_iter() > 0) ?
|
|
(aff_incr && (compteur % pa.freq_affich_iter()==0) &&(compteur!=0))
|
|
: (pa.freq_affich_iter() < 0) ? // dans le cas < 0 on affiche également l'itération 0
|
|
(aff_incr && (compteur % pa.freq_affich_iter()==0))
|
|
:false ;
|
|
// utilisation d'un comportement tangent simplifié si nécessaire
|
|
if (compteur <= pa.Init_comp_tangent_simple() )
|
|
lesLoisDeComp->Loi_simplifie(true);
|
|
else
|
|
lesLoisDeComp->Loi_simplifie(false);
|
|
lesLoisDeComp->MiseAJour_umat_nbiter(compteur); // init pour les lois Umat éventuelles
|
|
// actualisation des conditions de contact qui peuvent changer la largeur de bande,
|
|
// quand un noeud glisse d'une facette sur une voisine, peut changer la position du noeud
|
|
// qui est projeté sur la facette dans le cas de l'algorithme cinématique
|
|
if (pa.ContactType())
|
|
{ int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
bool a_changer = lescontacts->Actualisation(1);
|
|
#ifdef UTILISATION_MPI
|
|
// if faut que tous les proc aient le résultat final qui peut être différent pour chaque proc
|
|
// due au fait que chaque proc ne traite pas les mêmes éléments de contact
|
|
broadcast(*ParaGlob::Monde(), a_changer, 0);
|
|
#endif
|
|
|
|
// mise à jour éventuelle des matrices de raideur en fonction du contact
|
|
if (a_changer)
|
|
{//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,a_changer,lesCondLim,lesRef
|
|
,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
};
|
|
}
|
|
else if (change_statut)// sinon il faut éventuellement tenir compte du cht du au CLL
|
|
// NB: c'est pris en compte directement dans le contact, quand celui-ci est actif
|
|
{bool premier_calcul_inter=false; // si pas de contact, normalement il n'y a pas à changer
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
Gestion_stockage_et_renumerotation_sans_contact
|
|
(lescontacts,premier_calcul_inter,lesMail,change_statut
|
|
,lesCondLim,lesRef,tab_mato,Ass.Nb_cas_assemb()
|
|
,niveau_substitution);
|
|
};
|
|
|
|
// -- appel du calcul de la raideur et du second membre, énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
// avec prise en compte éventuelle d'un newton modifié
|
|
if ((deb_newton_modifie >= 0) && (compteur >= deb_newton_modifie) && (compteur <= fin_newton_modifie))
|
|
{ if (((compteur-deb_newton_modifie) % nb_iter_NM)== 0)
|
|
// on est au début du cycle -> on récupère la partie effort externes relative aux chargements
|
|
{ matsauve->Initialise(0.);
|
|
(*matsauve) -= (*matglob); // change de signe
|
|
// -- appel du calcul de la raideur et du second membre, énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
if (!RaidSmEner(lesMail,Ass,vglobin,(*matglob))) break;
|
|
// on sauvegade la raideur seule
|
|
(*matsauve) += (*matglob); // sans les efforts externes
|
|
}
|
|
else
|
|
// sinon on est en newton modifié, on utilise la matrice modifiée pour la raideur
|
|
{ (*matglob) += (*matsauve);
|
|
// on calcul uniquement le second membre
|
|
if (!SecondMembreEnerg(lesMail,Ass,vglobin)) break;
|
|
};
|
|
}
|
|
else
|
|
// sinon on regarde si on utilise de la raideur moyenne
|
|
{if (deb_raideur_moyenne >= 0)
|
|
{ if ((compteur >= (deb_raideur_moyenne-nb_raideur_moyenne))
|
|
&& (compteur <= deb_raideur_moyenne)&& (compteur <= fin_raideur_moyenne))
|
|
// phase de premier remplissage
|
|
{ tab_matmoysauve_rempli++;
|
|
if (tab_matmoysauve_rempli > nb_raideur_moyenne) tab_matmoysauve_rempli = 1;
|
|
(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1)->Initialise(0.);
|
|
// -- appel du calcul de la raideur et du second membre, énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
if (!RaidSmEner(lesMail,Ass,vglobin
|
|
,(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))))
|
|
break;
|
|
// on met à jour la raideur
|
|
(*matglob) += (*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1));
|
|
(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))
|
|
*= (1./nb_raideur_moyenne); // on prépare la moyenne
|
|
}
|
|
else
|
|
// phase d'exploitation
|
|
{ tab_matmoysauve_rempli++;
|
|
if (tab_matmoysauve_rempli > nb_raideur_moyenne) tab_matmoysauve_rempli = 1;
|
|
(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1)->Initialise(0.);
|
|
// -- appel du calcul de la raideur et du second membre, énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
if (!RaidSmEner(lesMail,Ass,vglobin
|
|
,(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))))
|
|
break;
|
|
(*(*tab_tab_matmoysauve(tab_matmoysauve_rempli))(1))
|
|
*= (1./nb_raideur_moyenne); // on prépare la moyenne
|
|
// on met à jour la raideur utilisée
|
|
for (int ii=1;ii<=nb_raideur_moyenne;ii++)
|
|
(*matglob) += (*(*tab_tab_matmoysauve(ii))(1));
|
|
};
|
|
}
|
|
else
|
|
{// sinon calcul classique NR
|
|
if (!RaidSmEner(lesMail,Ass,vglobin,(*matglob))) break;
|
|
};
|
|
};
|
|
|
|
#ifdef UTILISATION_MPI
|
|
if (pa.ContactType())
|
|
{ temps_transfert_long_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
vglobin.Broadcast(0); // transfert à tous les proc
|
|
temps_transfert_long_algo.Arret_du_comptage(); // fin comptage cpu
|
|
};
|
|
#endif
|
|
|
|
// calcul des maxi des puissances internes
|
|
maxPuissInt = vglobin.Max_val_abs();
|
|
////------- debug
|
|
//#ifdef UTILISATION_MPI
|
|
// // cas d'un calcul //, pour l'instant seul le CPU 0 sont concerné
|
|
// if (ParaGlob::Monde()->rank() == 0)
|
|
//#endif
|
|
//cout << "\n debug AlgoNonDyna::CalEquilibre: maxPuissInt => "<<maxPuissInt
|
|
// << " compteur= " << compteur <<flush;
|
|
////--- fin debug
|
|
|
|
// dans le cas où l'on utilise de l'amortissement numérique le second membre
|
|
// et la matrice de raideur sont modifiés
|
|
if (pa.Amort_visco_artificielle())
|
|
{Algori::Cal_mat_visqueux_num_stat(*matglob,forces_vis_num);
|
|
vglobaal += forces_vis_num;
|
|
};
|
|
|
|
F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures
|
|
if (pa.ContactType() == 4) // si contact on passe les efforts aux noeuds
|
|
// on transfert les forces internes aux noeuds
|
|
lesMail->Quelconque_glob_vers_local(X1,F_int_tdt,typQ_gene_int);
|
|
|
|
// mise en place du chargement impose sur le second membre
|
|
// et éventuellement sur la raideur en fonction de sur_raideur
|
|
|
|
// mise en place du chargement impose, c-a-d calcul de la puissance externe
|
|
// si pb on sort de la boucle
|
|
if (!(charge->ChargeSMembreRaideur_Im_mecaSolid
|
|
(Ass,lesMail,lesRef,vglobex,*matglob,assembMat,pa,lesCourbes1D,lesFonctionsnD)))
|
|
{ Change_PhaseDeConvergence(-10);break;};
|
|
|
|
////cout << "\n debug AlgoNonDyna::CalEquilibre: vglobex => "; vglobex.Affiche();
|
|
////------- debug
|
|
// #ifdef UTILISATION_MPI
|
|
// // cas d'un calcul //, pour l'instant seul le CPU 0 sont concerné
|
|
// if (ParaGlob::Monde()->rank() == 0)
|
|
// #endif
|
|
// { cout << "\n debug AlgoriNonDyna::CalEquilibre";
|
|
// cout << "\n debug AlgoNonDyna::CalEquilibre: maxPuissext sans contact => "<<vglobex.Max_val_abs();
|
|
// };
|
|
////--- fin debug
|
|
|
|
// cas des efforts de contact, contribution second membre et matrice,
|
|
// suivant le type de contact on utilise ou on recalcule les reactions de contact éventuelles (contact et frottement)
|
|
if (pa.ContactType()) // et des énergies développées pendant le contact
|
|
{
|
|
#ifdef UTILISATION_MPI
|
|
temps_transfert_long_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
vglobex.Broadcast(0);
|
|
temps_transfert_long_algo.Arret_du_comptage(); // fin comptage cpu
|
|
#endif
|
|
// dans le cas où le calcul est inexploitable (pb dans le calcul) arrêt de la boucle
|
|
if (!RaidSmEnerContact(lescontacts,Ass,vcontact,(*matglob))) break;
|
|
//cout << "\n debug AlgoNonDyna::CalEquilibre: vcontact => "; vcontact.Affiche();
|
|
|
|
// //------- debug
|
|
// #ifdef UTILISATION_MPI
|
|
// // cas d'un calcul //, pour l'instant seul le CPU 0 sont concerné
|
|
// if (ParaGlob::Monde()->rank() == 0)
|
|
// #endif
|
|
// { cout << "\n debug AlgoriNonDyna::CalEquilibre";
|
|
// cout << "\n max forces de contact " << vcontact.Max_val_abs();
|
|
// };
|
|
// //--- fin debug
|
|
|
|
// on globalise tout pour les forces externes généralisées
|
|
#ifdef UTILISATION_MPI
|
|
temps_transfert_long_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
vcontact.Broadcast(0);
|
|
temps_transfert_long_algo.Arret_du_comptage(); // fin comptage cpu
|
|
#endif
|
|
};
|
|
|
|
F_ext_tdt_prec = F_ext_tdt; // sauvegarde des valeurs de l'itération précédente
|
|
if (pa.ContactType())
|
|
vglobex += vcontact;
|
|
maxPuissExt = vglobex.Max_val_abs();
|
|
F_ext_tdt = vglobex; // sauvegarde des forces généralisées extérieures
|
|
// second membre total
|
|
vglobaal += vglobex ;vglobaal += vglobin ;
|
|
//cout << "\n debug AlgoNonDyna::CalEquilibre: vglobal => "; vglobal.Affiche();
|
|
// calcul des reactions de contact pour les noeuds esclaves
|
|
// dans le repere absolu ( pour la sortie des infos sur le contact)
|
|
// et test s'il y a decollement de noeud en contact (pour les contacts actifs)
|
|
// mais ici, il n'y a pas de modification des éléments de contact (elles ont été faites dans lescontacts->Actualisation())
|
|
bool decol=false; // création et init de decol
|
|
if (pa.ContactType())
|
|
lescontacts->CalculReaction(vglobin,decol,Ass.Nb_cas_assemb(),aff_iteration);
|
|
// - definition éventuelle de conditions limites linéaires de contact, en fonction des éléments du contact existant à ce niveau
|
|
|
|
// (certains contacts (par pénalisation par exemple) ne produise pas de conditions linéaires)
|
|
list <Condilineaire>* listCondLine=NULL;
|
|
if ((pa.ContactType()==1) || (pa.ContactType()==3))
|
|
listCondLine = &(lescontacts->ConditionLin(Ass.Nb_cas_assemb()));
|
|
|
|
// - initialisation des sauvegardes sur matrice et second membre
|
|
lesCondLim->InitSauve(Ass.Nb_cas_assemb());
|
|
// on récupère les réactions avant changement de repère et calcul des torseurs de réaction
|
|
lesCondLim->ReacAvantCHrepere(vglobaal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl);
|
|
|
|
// ---exploratoire
|
|
// // mise en place des conditions linéaires (ne comprend pas les conditions linéaires de contact éventuelles)
|
|
// lesCondLim->MiseAJour_condilineaire_tdt
|
|
// (pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
// ,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// ---exploratoire
|
|
|
|
|
|
|
|
// -->> expression de la raideur et du second membre dans un nouveau repere
|
|
// mais ici on n'impose pas les conditons, on fait simplement le changement de repère
|
|
lesCondLim->CoLinCHrepere_int((*matglob),vglobaal,Ass.Nb_cas_assemb(),vglob_stat);
|
|
if (pa.ContactType()==1)
|
|
lesCondLim->CoLinCHrepere_ext((*matglob),vglobaal,*listCondLine,Ass.Nb_cas_assemb(),vglob_stat);
|
|
if (pa.ContactType()==3) // *** exploratoire
|
|
lesCondLim->CoLinUneOpe_ext((*matglob),vglobaal,*listCondLine,Ass.Nb_cas_assemb(),vglob_stat);
|
|
// sauvegarde des reactions pour les ddl bloques (simplement)
|
|
// en fait ne sert à rien, car les réactions maxi sont calculées dans condlin, mais comme c'est peut-être un peu spécial ici on laisse
|
|
// mais dans les autres algos c'est supprimé !!!!!
|
|
lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom
|
|
|
|
// prise en compte des conditions imposée sur la matrice et second membres (donc dans le nouveau repère)
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,(*matglob),vglobaal,Ass.Nb_cas_assemb()
|
|
,cas_combi_ddl,vglob_stat);
|
|
if (pa.ContactType()!=3) // *** exploratoire
|
|
// cas des conditions linéaires: répercutions sur matrices et second membre
|
|
// (blocage de toutes les conditions lineaires, quelque soit leur origines ext ou int donc contact éventuel)
|
|
lesCondLim->CoLinBlocage((*matglob),vglobaal,Ass.Nb_cas_assemb(),vglob_stat);
|
|
// calcul du maxi des reactions
|
|
maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
|
|
|
|
// sortie d'info sur l'increment concernant les réactions
|
|
if (compteur != 0)
|
|
if (aff_iteration) InfoIncrementReac(lesMail,compteur,inReaction,maxReaction,Ass.Nb_cas_assemb());
|
|
// calcul des énergies et affichage des balances
|
|
// récupération (initialisation) des ddl position à t+dt
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// calcul de la variation de ddl / delta t
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
#ifdef UTILISATION_MPI
|
|
// cas d'un calcul //, pour l'instant seul le CPU 0 sont concerné
|
|
if ((ParaGlob::Monde()->rank() == 0)&&(permet_affichage > 3))
|
|
#else
|
|
if (permet_affichage > 3)
|
|
#endif
|
|
{ cout << "\n --- |max_var_DeltaDdl|= "<< max_var_delta_X
|
|
<< " , |max_deltaDdl|= " << max_delta_X << flush;};
|
|
// ---dans le cas du mode debug on sort éventuellement les infos au fil du calcul (un peu bricolé)
|
|
|
|
if ((mode_debug > 0)||(pa.EtatSortieEtatActuelDansCVisu()))
|
|
{bool a_sortir_debug=false; // pour éviter une division par 0 du test (compteur % mode_debug == 0)
|
|
if (pa.EtatSortieEtatActuelDansCVisu()) {a_sortir_debug=true;}
|
|
else if (compteur % mode_debug == 0) {a_sortir_debug=true;};
|
|
if (a_sortir_debug)
|
|
{// on passe les déplacements de tdt à t
|
|
tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
|
|
lesMail->Vect_glob_vers_local(TEMPS_t,X1,X_tdt,X1);
|
|
// visualisation éventuelle au fil du calcul: essentiellement la déformée
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lescontacts,resultats,type_incre,(icharge*1000000+compteur));
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
|
|
// on remet les choses dans l'ordre initial
|
|
lesMail->Vect_glob_vers_local(TEMPS_t,X1,X_t,X1);
|
|
};
|
|
};
|
|
|
|
CalEnergieAffichage(delta_X,icharge,brestart,forces_vis_num);
|
|
// test de convergence sur un increment
|
|
// en tenant compte éventuellement du contact (non decollement) decol = false systématiquement si pas de contact
|
|
|
|
decol = false; // pour debugger
|
|
|
|
bool arret_iteration = false;
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 s'occupe de la convergence
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
{
|
|
#endif
|
|
if (Convergence(aff_iteration,last_var_ddl_max,vglobaal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence)
|
|
&& !decol)
|
|
{ // on sort de la boucle des itérations sauf si l'on est en loi simplifiée
|
|
if (lesLoisDeComp->Test_loi_simplife() )
|
|
// cas d'une loi simplifié on remet normal
|
|
{ lesLoisDeComp->Loi_simplifie(false);}
|
|
else
|
|
// cas normal,
|
|
{arret_iteration = true; }; //break;};
|
|
}
|
|
else if (arret_convergence)
|
|
{arret_iteration = true; }; //break;} // cas ou la méthode Convergence() demande l'arret
|
|
#ifdef UTILISATION_MPI
|
|
};
|
|
temps_transfert_court_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
broadcast(*ParaGlob::Monde(), arret_iteration, 0);
|
|
temps_transfert_court_algo.Arret_du_comptage(); // fin comptage cpu
|
|
#endif
|
|
if (arret_iteration)
|
|
break;
|
|
|
|
// sinon on continue
|
|
// pour le pilotage ou pour l'accélération de convergence, sauvegarde du résidu
|
|
if (pa.Line_search() || (acceleration_convergence))
|
|
(*Vres) = vglobaal;
|
|
|
|
// ---- resolution ----
|
|
tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu
|
|
bool erreur_resolution_syst_lineaire = false; // init
|
|
int nb_matrice_secondaire = tab_mato.Taille(); // = 1 par défaut, mais on peut en avoir d'autre
|
|
int niveau_substitution = 1; // par défaut on utilise la matrice de raideur matglob = tab_mato(1)
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 fait la résolution globale
|
|
if (ParaGlob::Monde()->rank() == 0)
|
|
{
|
|
#endif
|
|
while (niveau_substitution <= nb_matrice_secondaire)
|
|
{ // on sauvegarde éventuellement le second membre
|
|
if (nb_matrice_secondaire > 1) // cela veut dire que l'on est suceptible de faire plusieurs boucles
|
|
{ if (niveau_substitution == 1)
|
|
// init au premier passage
|
|
{vglobal_sauv = vglobaal;
|
|
matglob->Transfert_vers_mat(*tab_mato(niveau_substitution+1));
|
|
}
|
|
else
|
|
{vglobaal = vglobal_sauv; // récup du second membre
|
|
// s'il y a une matrice de substitution supplémentaire, on sauvegarde
|
|
if (nb_matrice_secondaire > niveau_substitution)
|
|
tab_mato(niveau_substitution)->Transfert_vers_mat
|
|
(*tab_mato(niveau_substitution+1));
|
|
if (ParaGlob::NiveauImpression() >= 3)
|
|
{ cout << "\n nouvelle resolution du systeme avec la matrice "<<niveau_substitution
|
|
<< " de substitution " << endl;
|
|
};
|
|
};
|
|
};
|
|
|
|
residu_final = vglobaal; // sauvegarde pour le post-traitement
|
|
////------- debug
|
|
//cout << "\n debug AlgoriNonDyna::CalEquilibre";
|
|
// { string entete = " affichage de la matrice de raideur (puissance interne) avant resolution";
|
|
// tab_mato(1)->Affichage_ecran(entete);
|
|
// entete = " affichage du second membre (puissance interne) avant resolution ";
|
|
// residu_final.Affichage_ecran(entete);
|
|
// };
|
|
////--- fin debug
|
|
try
|
|
{// ici sol en fait = vecglob qui est ecrase par la resolution
|
|
sol = &(tab_mato(niveau_substitution)->Resol_systID
|
|
(vglobaal,pa.Tolerance(),pa.Nb_iter_nondirecte(),pa.Nb_vect_restart()));
|
|
// affichage éventuelle du vecteur solution : deltat_ddl
|
|
if (ParaGlob::NiveauImpression() >= 10)
|
|
{ string entete = " affichage du vecteur solution (delta_ddl) ";
|
|
sol->Affichage_ecran(entete); };
|
|
// retour des ddl dans les reperes generaux, dans le cas où ils ont ete modifie
|
|
// par des conditions linéaires
|
|
if (pa.ContactType()!=3) // *** exploratoire
|
|
lesCondLim->RepInitiaux( *sol,Ass.Nb_cas_assemb());
|
|
erreur_resolution_syst_lineaire = false;
|
|
break; // on sort du while
|
|
}
|
|
catch (ErrResolve_system_lineaire excep)
|
|
// cas d'une d'une erreur survenue pendant la résolution
|
|
{ erreur_resolution_syst_lineaire = true; // on prépare l'arrêt
|
|
} // car il faut néanmoins effacer les marques avant l'arrêt
|
|
catch (ErrSortieFinale)
|
|
// cas d'une direction voulue vers la sortie
|
|
// on relance l'interuption pour le niveau supérieur
|
|
{ ErrSortieFinale toto;
|
|
throw (toto);
|
|
}
|
|
catch ( ... )
|
|
{ erreur_resolution_syst_lineaire = true; // on prépare l'arrêt
|
|
}
|
|
// il y a eu un pb de résolution
|
|
niveau_substitution++;
|
|
};
|
|
tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu
|
|
|
|
// cas où on a eu au final une erreur de résolution
|
|
if (erreur_resolution_syst_lineaire)
|
|
{Change_PhaseDeConvergence(-9); // on signale une divergence due à la résolution
|
|
break; // arrêt si on avait détecté une erreur à la résolution
|
|
};
|
|
// idem si la norme de la solution est infinie
|
|
// calcul du maxi de variation de ddl
|
|
maxDeltaDdl = sol->Max_val_abs(inSol); last_var_ddl_max=maxDeltaDdl;
|
|
double maxDeltatDdl_signe=(*sol)(inSol); // récupération de la grandeur signée
|
|
if ((std::isinf(maxDeltaDdl))||( std::isnan(maxDeltaDdl)))
|
|
{if (ParaGlob::NiveauImpression() > 2)
|
|
cout << "\n resolution du systeme lineaire global (equilibre global) norme de delta_ddl infinie "
|
|
<< maxDeltaDdl;
|
|
Change_PhaseDeConvergence(-9); // on signale une divergence due à la résolution
|
|
break; // arrêt si on avait détecté une erreur à la résolution
|
|
};
|
|
if (((ParaGlob::NiveauImpression() > 6) && (ParaGlob::NiveauImpression() < 10))
|
|
|| (permet_affichage > 6))
|
|
{cout << "\n vecteur solution: "; sol->Affiche();};
|
|
|
|
|
|
// pilotage à chaque itération: ramène: maxDeltaDdl,csol modifiés éventuellement et insol
|
|
Pilotage_chaque_iteration(sol,maxDeltaDdl,compteur,lesMail);
|
|
// sortie d'info sur l'increment concernant les variations de ddl
|
|
if ((aff_iteration)&&(ParaGlob::NiveauImpression() > 1))
|
|
InfoIncrementDdl(lesMail,inSol,maxDeltatDdl_signe,Ass.Nb_cas_assemb());
|
|
|
|
#ifdef UTILISATION_MPI
|
|
}
|
|
else // s'il s'agit d'un process de calcul élémentaire
|
|
{sol = &vglobaal; // il faut affecter sol pour récupérer ensuite la solution
|
|
};
|
|
// le process 0 transmet aux autres process le vecteur résultat
|
|
temps_transfert_long_algo.Mise_en_route_du_comptage(); // comptage cpu
|
|
|
|
//// essai pour remplacer broadcast
|
|
// int nb_process = ParaGlob::Monde()->size();
|
|
// mpi::request reqs1;
|
|
// if (ParaGlob::Monde()->rank() == 0)
|
|
// // NB: le process 0 c'est le main
|
|
// {for (int i=1;i<nb_process;i++) // < absolu, donc le max c'est nb_process-1
|
|
// {reqs1 = sol->Ienvoi_MPI(i, 38);}
|
|
// }
|
|
// else
|
|
// {reqs1 = sol->Irecup_MPI(0,38);};
|
|
//// ParaGlob::Monde()->barrier();
|
|
// reqs1.wait();
|
|
|
|
// mpi::request Ienvoi_MPI(int dest, int tag) const
|
|
// {return ParaGlob::Monde()->isend(dest,tag,v,taille);};
|
|
// mpi::request Irecup_MPI(int source, int tag) const
|
|
|
|
sol->Broadcast(0);
|
|
// broadcast(*ParaGlob::Monde(), *sol, 0);
|
|
// synchronisation ici de tous les process (à supprimer par la suite car n'est
|
|
// pas nécessaire pour le déroulementa priori ?? )
|
|
// ParaGlob::Monde()->barrier();
|
|
temps_transfert_long_algo.Arret_du_comptage(); // fin comptage cpu
|
|
#endif
|
|
|
|
// effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
|
|
lesCondLim->EffMarque();
|
|
if ((pa.ContactType()==1) || (pa.ContactType()==3))
|
|
lescontacts->EffMarque();
|
|
|
|
// suite du pilotage
|
|
// ------------------------------------------------------------
|
|
// |on regarde s'il faut utiliser l'algorithme de line search |
|
|
// ------------------------------------------------------------
|
|
bool avec_line_search = false;
|
|
if (pa.Line_search())
|
|
{ // la méthode de line_search incrémente la solution
|
|
// même s'il n'y a pas de mise en oeuvre de la méthode
|
|
avec_line_search = Line_search1
|
|
(*sauve_deltadept,puis_precedente,*Vres,lesMail,sol
|
|
,compteur,*sauve_dept_a_tdt,charge,vglobex,Ass,*v_travail,
|
|
lesCondLim,vglobaal,lesRef,vglobin,Ass.Nb_cas_assemb(),cas_combi_ddl,lesCourbes1D,lesFonctionsnD);
|
|
}
|
|
else
|
|
//cas ou l'on ne fait pas de line seach
|
|
{ // on regarde si l'on veut une accélération de convergence, par une méthode d'extrapolation
|
|
if (acceleration_convergence)
|
|
{ sauve_sol = *sol;// on sauvegarde le vecteur solution, car = vglobal qui va être écrasé
|
|
if (!(AccelerationConvergence(aff_iteration,(*Vres),lesMail,compteur,X_t,delta_X,charge,vglobex
|
|
,Ass,sauve_sol,lesCondLim,vglobaal,lesRef,vglobin,Ass.Nb_cas_assemb(),cas_combi_ddl,lesCourbes1D,lesFonctionsnD)
|
|
== 4))
|
|
// 4 cas ou on a a priori convergé avec l'extrapolation,
|
|
// les positions finales des noeuds a été modifiée en conséquence
|
|
// donc dans ce cas on ne fait rien, sinon on continue normalement
|
|
{ // actualisation des ddl actifs a t+dt à chaque incrément
|
|
lesMail->PlusDelta_tdt(sauve_sol,Ass.Nb_cas_assemb());
|
|
};
|
|
}
|
|
else
|
|
// cas normal, sans accélération
|
|
{ // actualisation des ddl actifs a t+dt à chaque incrément
|
|
lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb());
|
|
//---debug
|
|
//lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
//cout << "\nXtdt+deltaddl "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<<i<< " ";for (int j=1;j<=3;j++) cout << X_tdt((i-1)*3+j)<<" ";};
|
|
//--fin-debug
|
|
};
|
|
};
|
|
};
|
|
|
|
//---//\\//\\// fin de la boucle sur les itérations d'équilibres //\\//\\//
|
|
// effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
|
|
// car ici on n'est pas passé par cette endroit si l'on a convergé
|
|
lesCondLim->EffMarque();
|
|
|
|
// mise à jour des indicateurs contrôlés par le tableau: *tb_combiner
|
|
if (tb_combiner != NULL) // cas d'un contrôle via des fonctions nD
|
|
{if ((*tb_combiner)(1) != NULL)
|
|
validation_calcul = (*tb_combiner)(1)->Valeur_pour_variables_globales()(1);
|
|
if ((*tb_combiner)(2) != NULL)
|
|
sortie_boucle_controler_par_fctnD = (*tb_combiner)(2)->Valeur_pour_variables_globales()(1);
|
|
};
|
|
|
|
if ((pa.ContactType()==1) || (pa.ContactType()==3)) lescontacts->EffMarque();
|
|
|
|
// === gestion de la fin des itérations ===
|
|
#ifdef UTILISATION_MPI
|
|
// seule le process 0 a fait la résolution globale
|
|
// il gère seul également la convergence, mais il doit tenir au courant les autres process
|
|
Algori::Passage_indicConvergenceAuxProcCalcul();
|
|
// ce qui permet le déroulement correct de la suite pour tous les process
|
|
#endif
|
|
|
|
if ((!Pilotage_fin_iteration_implicite(compteur))||(pa.EtatSortieEquilibreGlobal()))
|
|
// if ((!Pilotage_fin_iteration_implicite(compteur))
|
|
// && (!pa.EtatSortieEtatActuelDansBI()))
|
|
{ // cas d'une non convergence
|
|
pas_de_convergence_pour_l_instant = 1;
|
|
// comme on incrémente pas les ddl on remet cependant les ddl
|
|
// et les grandeurs actives de tdt aux valeurs de ceux de t
|
|
lesMail->TversTdt();
|
|
lescontacts->TversTdt(); // idem pour les contacts éventuels
|
|
// on remet indicCycleContact à 0 pour que le pilotage sur le temps se refasse
|
|
indicCycleContact = 0;
|
|
|
|
// ------ cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
|
|
if (Algori::PhaseDeConvergence() == -8)
|
|
{ int nb_incr_en_arriere = 3; // !!!!! nombre actuellement arbitraire -> par la suite mettre dans les para
|
|
if (Controle_retour_sur_un_increment_enregistre(nb_incr_en_arriere,icharge))
|
|
{ // cas ou on a réussi à trouver un incrément sauvegardé adoc = maintenant icharge
|
|
int cas=2;
|
|
this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lescontacts,resultats,icharge);
|
|
// comme les conditions limites cinématiques peuvent être différentes en restart
|
|
// on libére toutes les CL imposées éventuelles
|
|
lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
|
|
lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
|
|
// dans le cas d'un calcul axisymétrique on bloque le ddl 3
|
|
if (ParaGlob::AxiSymetrie())
|
|
lesMail->Inactive_un_ddl_particulier(X3);
|
|
// on valide l'activité des conditions limites et condition linéaires, pour le temps initial
|
|
// en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
// on remet à jour les éléments pour le contact s'il y du contact présumé
|
|
if (pa.ContactType())
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
brestart = true; // on signale que l'on repars avec un restart
|
|
};
|
|
// sinon on ne fait rien, on se contente du pilotage de divergence existant
|
|
};
|
|
// ------ fin cas particulier où on a une divergence qui demande de remonter sur plus d'un incrément
|
|
}
|
|
else
|
|
{ // --- sinon calcul correcte
|
|
pas_de_convergence_pour_l_instant = 0;
|
|
if (permet_affichage > 0)
|
|
{ cout << "\n --- |max_var_DeltaDdl|= "<< max_var_delta_X
|
|
<< " , |max_deltaDdl|= " << max_delta_X << flush;};
|
|
if (pa.ContactType())
|
|
{ // actualisation du contact en fonction du dernier incrément
|
|
bool nevez_contact = lescontacts->Actualisation(0);
|
|
// réexamen du contact pour voir s'il n'y a pas de nouveau element de contact
|
|
// en fait on fera au plus deux passages supplémentaire, sinon la boucle peut être infini,
|
|
// à la fin du second passage, on regarde s'il y a décollement, si oui on relâche et on refait un passage
|
|
// sinon on valide
|
|
//I)--------------
|
|
if (indicCycleContact == 0 )
|
|
{ bool nouveau_contact = lescontacts->Nouveau(lesMail->Max_var_dep_t_a_tdt());
|
|
nevez_contact = nevez_contact || nouveau_contact;
|
|
if (nevez_contact)
|
|
{indicCycleContact=1;} // on a de nouveau contact on refait le deuxième cycle
|
|
else
|
|
// sinon, on n'a pas de nouveau contact, on regarde s'il y a du relachement
|
|
{ indicCycleContact=2;};
|
|
}
|
|
else if (indicCycleContact == 1)
|
|
{indicCycleContact=2;} // pour regarder le relachement
|
|
else
|
|
{indicCycleContact=0;}; // pas de newcontact, ni de relachement donc c'est ok
|
|
//II)---------------
|
|
bool relachement_contact = false;
|
|
if (indicCycleContact == 2)
|
|
{relachement_contact = lescontacts->RelachementNoeudcolle();
|
|
if (relachement_contact)
|
|
{indicCycleContact=3;} // pour une dernière boucle d'équilibre
|
|
else
|
|
{indicCycleContact=0;};// pas de relachement donc ok
|
|
};
|
|
|
|
if ( (nevez_contact || relachement_contact)
|
|
)
|
|
{int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
bool nouveau = (nevez_contact || relachement_contact);
|
|
//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,nouveau,lesCondLim
|
|
,lesRef,tab_mato,Ass.Nb_cas_assemb(),lescontacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
};
|
|
}
|
|
else
|
|
// concerne ici le cas où c'est un problème sans contact (=contact non activé)
|
|
{ indicCycleContact = 0; }; //pour le prochain increment
|
|
if (!(pa.ContactType()) || (indicCycleContact == 0))
|
|
{
|
|
// --- pour l'instant en test, mais normalement on fait la sauvegarde et la sortie d'info éventuelle avant le passage de t à tdt
|
|
// ce qui permet de différencier les grandeurs à t et celles à tdt
|
|
// non !!! ce n'est pas une bonne chose, car il y a plein de grandeur que l'on ne sauve qu'à t, or t c'est la valeur de départ donc cela fait en pratique
|
|
// un décalage de temps d'un incrément !! c'est pas une bonne chose, il faudrait intervenir à plein d'endroit. donc on fait t et tdt = idem
|
|
//
|
|
// // sauvegarde de l'incrément si nécessaire
|
|
// Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
// ,lesLoisDeComp,diversStockage,charge,lesCondLim,lescontacts
|
|
// ,resultats,type_incre,icharge);
|
|
// // enregistrement du num d'incrément et du temps correspondant
|
|
// list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
// // visualisation éventuelle au fil du calcul
|
|
// VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
// ,lesCondLim,lescontacts,resultats,type_incre,icharge);
|
|
// --- fin de la partie en test
|
|
|
|
// on regarde si l'on doit initialiser le prochain incrément avec le pas précédent
|
|
if (pa.IniIncreAvecDeltaDdlPrec()) // si oui on sauvegarde le delta_X actuel / delta_t
|
|
{ // récupération (initialisation) des ddl position à t et t+dt
|
|
lesMail->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1);
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// calcul de la variation de ddl / delta t
|
|
// delta_X = X_tdt; delta_X -= X_t; delta_X /= pa.Deltat();
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
// si le pas de temps est trop petit il y aura un pb
|
|
if (pa.Deltat() > ConstMath::unpeupetit)
|
|
{delta_prec_X = delta_X/pa.Deltat(); // on sauvegarde le delta_X qui a convergé
|
|
delta_t_precedent_a_convergence = pa.Deltat();
|
|
}
|
|
else // sinon on neutralise
|
|
{delta_prec_X.Zero(); // on neutralise
|
|
delta_t_precedent_a_convergence = -1; // pour signaler une valeur non utilisable
|
|
}
|
|
};
|
|
|
|
// si on est sans validation, on ne fait rien, sinon on valide l'incrément
|
|
// avec sauvegarde éventuelle
|
|
if (validation_calcul)
|
|
{// actualisation des ddl et des grandeurs actives de t+dt vers t
|
|
lesMail->TdtversT();
|
|
lescontacts->TdtversT();
|
|
// cas du calcul des énergies, passage des grandeurs de tdt à t
|
|
Algori::TdtversT();
|
|
// on valide l'activité des conditions limites et condition linéaires
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
tempsCalEquilibre.Arret_du_comptage(); // pour enregistrer
|
|
//s'il y a remonté des sigma et/ou def aux noeuds et/ou calcul d'erreur
|
|
bool change =false; // calcul que s'il y a eu initialisation
|
|
if(prepa_avec_remont) {change = Algori::CalculRemont(lesMail,type_incre,icharge);};
|
|
if (change) // dans le cas d'une remonté il faut réactiver les bon ddls
|
|
{lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);};
|
|
|
|
// --- sauvegarde de l'incrément si nécessaire: ici on est après le passage de tdt vers t donc, les grandeurs à t et tdt sont identiques !!
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge,lesCondLim,lescontacts
|
|
,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
// visualisation éventuelle au fil du calcul
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lescontacts,resultats,type_incre,icharge);
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // en remet en route pour la suite
|
|
}; // -- fin du test: if (validation_calcul)
|
|
|
|
premier_calcul = false;// -- on enregistre le fait que l'on n'est plus au premier passage
|
|
|
|
|
|
brestart = false; // dans le cas où l'on était en restart, on passe l'indicateur en cas courant
|
|
if (validation_calcul)
|
|
{icharge++;
|
|
// init de var glob
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
};
|
|
}; //- fin du cas où l'incrément est validé pour l'équilibre avec le contact
|
|
}; // -- fin du cas ou le calcul converge
|
|
// cas particulier où la sortie de la boucle est pilotée
|
|
if (sortie_boucle_controler_par_fctnD && (!pas_de_convergence_pour_l_instant))
|
|
break;
|
|
|
|
}; // -- fin du while sur les incréments de charge
|
|
// on remet à jour le nombre d'incréments qui ont convergés:
|
|
if (validation_calcul)
|
|
{icharge--;
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
// dans le cas d'une suite de sous algo on signale qu'il y a validation
|
|
if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
|
|
(*tb_combiner)(3) = NULL;
|
|
}
|
|
else // si on ne valide pas le calcul, on reinitialise la charge
|
|
// c-a-d l'avancement en temps, incrément et facteur multiplicatif
|
|
// de manière à avoir les mêmes conditions de départ pour le prochain calcul
|
|
{ charge->Precedant(true);
|
|
// dans le cas d'une suite de sous algo on signale qu'il n'y a pas validation
|
|
if ((tb_combiner != NULL) && ((*tb_combiner)(1) != NULL))
|
|
(*tb_combiner)(3) = (*tb_combiner)(1);
|
|
} ;
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
};
|
|
|
|
// dernière passe
|
|
void AlgoriNonDyna::FinCalcul(ParaGlob * paraGlob,LesMaillages * lesMail,LesReferences* lesRef
|
|
,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor
|
|
,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage,
|
|
Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
|
|
{
|
|
// fin des calculs
|
|
type_incre = OrdreVisu::DERNIER_INCRE;
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
// sauvegarde de l'incrément si nécessaire
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
|
|
,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
};
|
|
|
|
// accélération de convergence, suivant une méthode MMPE (modified minimal polynomial extrapolation)
|
|
// ou une méthode pour essayer de régler les oscillations en dents de scie : n'a pas l'air de marcher
|
|
// compteur : compteur d'itération
|
|
// retour = 0: l'accélération n'est pas active (aucun résultat, aucune action, aucune sauvegarde)
|
|
// = 1: phase de préparation: sauvegarde d'info, mais aucun résultat
|
|
// = 2: calcul de l'accélération mais ... pas d'accélération constatée
|
|
// = 3: calcul de l'accélération et l'accélération est effective
|
|
// dans le cas différent de 0 et 1, le programme a priori, change le stockage des conditions
|
|
// limites, en particulier CL linéaire, mais avec des hypothèses, pour les sorties de réactions
|
|
// etc, il vaut mieux refaire une boucle normale avec toutes les initialisation ad hoc
|
|
// affiche: indique si l'on veut l'affichage ou non des infos
|
|
// on travaille avec les deltaX, car les deltaX valent 0 pour les ddl bloqués (imposés)
|
|
int AlgoriNonDyna::AccelerationConvergence(bool affiche,const Vecteur& vres ,LesMaillages * lesMail
|
|
,const int& compteur,const Vecteur& X_t,const Vecteur& delta_X,Charge* charge,Vecteur& vglobex
|
|
,Assemblage& Ass ,const Vecteur& delta_delta_X,LesCondLim* lesCondLim,Vecteur& vglobal
|
|
,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb
|
|
,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD)
|
|
|
|
{ // ne fonctionne que si le compteur est supérieur à 0
|
|
if (compteur <= 0) return 0;
|
|
int retour = 0; // par defaut
|
|
if (cas_acceleration_convergence < 4)
|
|
//--- cas de la méthode MMPE (modified minimal polynomial extrapolation) -----------------
|
|
{
|
|
|
|
// borne maxi du cycle qui varie de 1 à nb_vec_cycle
|
|
// indique le nombre de vecteur actif
|
|
int N = compteur % (nb_vec_cycle+2);
|
|
if (N==0) N=(nb_vec_cycle+2);
|
|
|
|
// --- 1) récupération des informations
|
|
// calcul des nouvelles grandeurs des vecteurs d'entrées à l'accélération
|
|
// (pour toutes les affectations, on a un dimensionnement automatique)
|
|
if (N == 1)
|
|
{ S_0 = delta_X; // affectation et dimensionnement automatique de S_1
|
|
Vi(N)=delta_delta_X;
|
|
switch (cas_acceleration_convergence)
|
|
{ case 1: case 10: Yi(N)=delta_X; break;
|
|
case 2: Yi(N)=vres; break;
|
|
case 3: Yi(N)=delta_delta_X; break;
|
|
};
|
|
return 1;
|
|
}
|
|
else
|
|
{ Vi(N) = delta_delta_X; // affectation et dimensionnement automatique de S_1
|
|
switch (cas_acceleration_convergence)
|
|
{ case 1: case 10: Yi(N)=delta_X; break;
|
|
case 2: Yi(N)=vres; break;
|
|
case 3: Yi(N)=delta_delta_X; break;
|
|
};
|
|
};
|
|
retour = 2; // par défaut
|
|
|
|
// --- 2) calcul d'une nouvelle position extrapolée
|
|
// préparation du calcul des coeff ai:
|
|
// calcul de la matrice et du second membre
|
|
mat_ai.Initialise(0.);Sm_ai.Zero(); // on initialise l'ensemble des containers
|
|
// mais seule la partie de 1 à N est utilisé
|
|
for (int i=1;i<=N-1;i++)
|
|
{ Sm_ai(i)=-(Vi(1) * Yi(i));
|
|
for (int j=1;j<=N-1;j++)
|
|
// projection des delta_Gi sur les Yi
|
|
mat_ai(i,j)=Yi(i) * (Vi(j+1)-Vi(j));
|
|
};
|
|
// pour éviter d'avoir une matrice singulière on met des 1 sur la partie de la diagonale restante
|
|
for (int i=N;i<= nb_vec_cycle+1;i++)
|
|
mat_ai(i,i)=1.;
|
|
// calcul des coef ai
|
|
coef_ai = mat_ai.Resol_systID (Sm_ai);
|
|
// construction du vecteur extrapolé, de position
|
|
X_extrapol = S_0; // affectation et dimensionnement automatique de X_extrapol
|
|
for (int i=1;i<=N-1;i++)
|
|
X_extrapol += coef_ai(i) * Vi(i);
|
|
X_extrapol += X_t;
|
|
|
|
// cout << "\n coef_ai " << coef_ai ;
|
|
|
|
// --- 3) l'ancien résidu
|
|
double norme_residu_entree = vres.Max_val_abs();
|
|
|
|
// --- 4) calcul du nouveau résidu
|
|
// maintenant on va calculer le résidu correspondant aux vecteur extrapolé de position
|
|
int re_init = 0; // sert dans le cas d'un pb de calcul
|
|
// 1) passage de ces nouvelles positions aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
|
|
// 2 - initialisation de la puissance externe puis on la calcule
|
|
vglobex.Zero();
|
|
// mise en place du chargement impose, c-a-d calcul de la puissance externe
|
|
// si pb on sort de la boucle
|
|
if (!(charge->ChargeSecondMembre_Ex_mecaSolid
|
|
(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD)))
|
|
{ Change_PhaseDeConvergence(-10);};
|
|
double maxPuissExt = vglobex.Max_val_abs();
|
|
// 3 - idem pour la puissance interne
|
|
vglobin.Zero();
|
|
if (pa.ContactType())
|
|
vcontact.Zero();
|
|
vglobaal.Zero(); // puissance totale
|
|
lesMail->Force_Ddl_aux_noeuds_a_une_valeur(R_X1,0.0,TEMPS_tdt,true); // mise à 0 des ddl de réactions, qui sont uniquement des sorties
|
|
lesMail->Force_Ddl_etendu_aux_noeuds_a_zero(Ddl_enum_etendu::Tab_FN_FT()); // idem pour les composantes normales et tangentielles
|
|
// 4 - calcul du second membre et des énergies
|
|
// dans le cas d'un calcul inexploitable on ressort en remettant les choses telles qu'elles
|
|
// étaient en entrée
|
|
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
|
|
{ cout << "\n pb dans l'acceleration de convergence, on neutralise l'acceleration";
|
|
re_init = 1;
|
|
};
|
|
double maxPuissInt = vglobin.Max_val_abs();
|
|
// 5 - second membre total
|
|
vglobal += vglobex ; vglobal += vglobin;
|
|
// 6 - mise en place des conditions limites, vglobal contiend le nouveau résidu
|
|
|
|
// sauvegarde des reactions aux ddl bloque
|
|
lesCondLim->ReacApresCHrepere(vglobal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom
|
|
|
|
// mise en place des conditions limites, uniquement sur le second membre
|
|
///!!!!! on considère que les conditions limites sont identiques à celle utilisée avec Xtd
|
|
///!!!!! au moment de la résolution (qui a précédé l'appel de AccelerationConvergence)
|
|
///!!!!! donc on ne s'occupe pas de CoLinCHrepere
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobal,nb_casAssemb,cas_combi_ddl,vglob_stat);
|
|
double nouvelle_norme = vglobal.Max_val_abs ();
|
|
|
|
// pour le débug !!!!!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
/* X_extrapol = X_t;
|
|
X_extrapol += delta_X;
|
|
|
|
// --- 4) calcul du nouveau résidu
|
|
// maintenant on va calculer le résidu correspondant aux vecteur extrapolé de position
|
|
re_init = 0; // sert dans le cas d'un pb de calcul
|
|
// 1) passage de ces nouvelles positions aux niveaux des maillages
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
|
|
// 2 - initialisation de la puissance externe puis on la calcul
|
|
vglobex.Zero();
|
|
charge->ChargeSecondMembre_Ex_mecaSolid(Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D);
|
|
maxPuissExt = vglobex.Max_val_abs();
|
|
// 3 - idem pour la puissance interne
|
|
vglobin.Zero();
|
|
// 4 - calcul du second membre et des énergies
|
|
// dans le cas d'un calcul inexploitable on ressort en remettant les choses telles qu'elles
|
|
// étaient en entrée
|
|
if (!SecondMembreEnerg(lesMail,Ass,vglobin))
|
|
{ cout << "\n pb dans l'acceleration de convergence, on neutralise l'acceleration";
|
|
re_init = 1;
|
|
};
|
|
maxPuissInt = vglobin.Max_val_abs();
|
|
// 5 - second membre total ( vglobal est identique a vglobin)
|
|
vglobal += vglobex ;
|
|
// 6 - mise en place des conditions limites, vglobal contiend le nouveau résidu
|
|
|
|
// sauvegarde des reactions aux ddl bloque
|
|
lesCondLim->ReacApresCHrepere(vglobal,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom
|
|
|
|
// mise en place des conditions limites, uniquement sur le second membre
|
|
///!!!!! on considère que les conditions limites sont identiques à celle utilisée avec Xtd
|
|
///!!!!! au moment de la résolution (qui a précédé l'appel de AccelerationConvergence)
|
|
///!!!!! donc on ne s'occupe pas de CoLinCHrepere
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobal,nb_casAssemb,cas_combi_ddl);
|
|
double new_norme = vglobal.Max_val_abs ();
|
|
cout << "\n new_norme = " << new_norme;
|
|
*/
|
|
|
|
// fin pour le débug !!!!!!!!!!!!!!!!!!!!!!
|
|
|
|
|
|
|
|
|
|
// --- 5) exploitation: comparaison des résidus
|
|
if (norme_residu_entree < nouvelle_norme)
|
|
{ // dans le cas où le nouveau résidu est plus grand que l'ancien on ne fait rien, et on affiche éventuellement
|
|
if (affiche && (ParaGlob::NiveauImpression() > 1))
|
|
cout << "\n ..pas d'acceleration....koz_res= " << norme_residu_entree << " nevez_res= " << nouvelle_norme;
|
|
// on remet en place le vecteur position
|
|
X_extrapol = X_t; X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
|
|
retour = 2;
|
|
}
|
|
else
|
|
{ // cas où on est meilleurs, petit message éventuel
|
|
if (affiche && (ParaGlob::NiveauImpression() > 1))
|
|
cout << "\n ... acceleration positive....koz_res= " << norme_residu_entree << " nevez_res= " << nouvelle_norme;
|
|
// puis on appel de la convergence, pour voir si en plus on aurait convergé
|
|
double maxReaction = MaX(maxPuissExt,maxPuissInt); // on simplifie
|
|
bool arret_convergence; // ne sert pas ici
|
|
double last_var_ddl_max = delta_delta_X.Max_val_abs (); // le dernier accroissement de ddl
|
|
if (Convergence(affiche,last_var_ddl_max,vglobal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence))
|
|
// a priori on a convergé donc on laisse le nouveau vecteur position en conséquence
|
|
{ retour = 4; }
|
|
else
|
|
// c'est meilleur mais on n'a pas convergé donc on remet en place le vecteur position
|
|
{ X_extrapol = X_t; X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
|
|
retour = 3;
|
|
};
|
|
};
|
|
}
|
|
|
|
//---- fin du cas de l'accélération avec la méthode MMPE (modified minimal polynomial extrapolation)
|
|
|
|
else
|
|
{
|
|
// --- cas simple où l'on essaie de gérer le cas d'une oscillation infinie entre deux positions ---------
|
|
// tout d'abord on regarde si effectivement on est dans le cas en question, pour cela il faut que l'on ait au moins 4 iterations enregistrées
|
|
|
|
// borne maxi du cycle qui varie de 1 à nb_vec_cycle (==2 a priori)
|
|
// indique le nombre de vecteur actif
|
|
int N = compteur % (nb_vec_cycle+2);
|
|
if (N==0) N=(nb_vec_cycle+2);
|
|
|
|
|
|
Yi(N)=delta_X; // 1) stockage des delta_X
|
|
Vi(N)(1) = vres.Max_val_abs(); // 2) stockage du maxi du résidu a priori non nul sinon cela veut dire que l'on a convergé
|
|
if (Vi(N)(1) < ConstMath::trespetit ) return 1; // ce n'est pas la pein de continuer
|
|
|
|
retour = 2; // par défaut
|
|
if (compteur < 4) return 1;
|
|
// sinon
|
|
// def des 4 indices successifs
|
|
int j1 = (N+1) % (nb_vec_cycle+2); if (j1 == 0) j1 = (nb_vec_cycle+2);
|
|
int j2 = (N+2) % (nb_vec_cycle+2); if (j2 == 0) j2 = (nb_vec_cycle+2);
|
|
int j3 = (N+3) % (nb_vec_cycle+2); if (j3 == 0) j3 = (nb_vec_cycle+2);
|
|
int j4 = N ;
|
|
// on regarde s'il y a matière à s'inquiéter
|
|
// si le j4 > J3, J3 < J2, J2 > J1 : on a une forme de dent de scie ou
|
|
// si le j4 < J3, J3 > J2, J2 < J1 : on a une forme de dent de scie
|
|
double taux=0.15; // on se met une marge de 15%
|
|
if ( (( Vi(j4)(1) > Vi(j3)(1)) && ( Vi(j3)(1) < Vi(j2)(1)) && ( Vi(j2)(1) > Vi(j1)(1)))
|
|
|| (( Vi(j4)(1) < Vi(j3)(1)) && ( Vi(j3)(1) > Vi(j2)(1)) && ( Vi(j2)(1) < Vi(j1)(1))) )
|
|
// si on retombe deux à deux sur les mêmes résidus à taux près
|
|
{if ((!diffpourcent(Vi(j4)(1),Vi(j2)(1),Vi(j4)(1),taux)) && (!diffpourcent(Vi(j3)(1),Vi(j1)(1),Vi(j3)(1),taux)))
|
|
// dans ce cas on est dans une boucle: on choisit un vecteur x = à la moitié des deux précédents delta_delta_X
|
|
{ X_extrapol = X_t;
|
|
X_extrapol += delta_X; // on se sert de X_extrapol comme contenaire intermédiaire
|
|
X_extrapol += 0.5*delta_delta_X;
|
|
lesMail->Vect_glob_vers_local(TEMPS_tdt,X1,X_extrapol,X1);
|
|
retour = 4;
|
|
}
|
|
else retour = 1.;
|
|
}
|
|
else
|
|
{ retour = 1.;
|
|
};
|
|
|
|
// --- fin cas simple où l'on essaie de gérer le cas d'une oscillation infinie entre deux positions ---------
|
|
};
|
|
|
|
// retour
|
|
return retour;
|
|
};
|
|
|
|
//---- gestion des commndes interactives --------------
|
|
// écoute et prise en compte d'une commande interactive
|
|
// ramène true tant qu'il y a des commandes en cours
|
|
bool AlgoriNonDyna::ActionInteractiveAlgo()
|
|
{ cout << "\n commande? ";
|
|
return false;
|
|
};
|
|
|
|
// sortie du schemaXML: en fonction de enu
|
|
void AlgoriNonDyna::SchemaXML_Algori(ofstream& sort,const Enum_IO_XML enu) const
|
|
{
|
|
switch (enu)
|
|
{ case XML_TYPE_GLOBAUX :
|
|
{
|
|
break;
|
|
}
|
|
case XML_IO_POINT_INFO :
|
|
{
|
|
break;
|
|
}
|
|
case XML_IO_POINT_BI :
|
|
{
|
|
break;
|
|
}
|
|
case XML_IO_ELEMENT_FINI :
|
|
{
|
|
break;
|
|
}
|
|
case XML_ACTION_INTERACTIVE :
|
|
{sort << "\n <!-- ********** algorithme implicite non dynamique ******************** -->"
|
|
<< "\n<xs:complexType name=\"INIT\" >"
|
|
<< "\n <xs:annotation>"
|
|
<< "\n <xs:documentation> initialisation de l'algo "
|
|
<< "\n </xs:documentation>"
|
|
<< "\n </xs:annotation>"
|
|
<< "\n</xs:complexType>";
|
|
sort << "\n<xs:complexType name=\"EXECUTION\" >"
|
|
<< "\n <xs:annotation>"
|
|
<< "\n <xs:documentation> execution de l'ensemble de l'algo, sans l'initialisation et la derniere passe "
|
|
<< "\n </xs:documentation>"
|
|
<< "\n </xs:annotation>"
|
|
<< "\n</xs:complexType>";
|
|
sort << "\n<xs:complexType name=\"FIN_ALGO_EXPLI\" >"
|
|
<< "\n <xs:annotation>"
|
|
<< "\n <xs:documentation> fin de l'algo "
|
|
<< "\n </xs:documentation>"
|
|
<< "\n </xs:annotation>"
|
|
<< "\n</xs:complexType>";
|
|
break;
|
|
}
|
|
case XML_STRUCTURE_DONNEE :
|
|
{
|
|
break;
|
|
}
|
|
};
|
|
};
|
|
|
|
// Calcul de l'équilibre de la pièce avec pilotage de longueur d'arc
|
|
void AlgoriNonDyna::Calcul_Equilibre_longueur_arc
|
|
(ParaGlob * paraGlob,LesMaillages * lesMail,
|
|
LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD
|
|
,VariablesExporter* varExpor,LesLoisDeComp* lesLoisDeComp,
|
|
DiversStockage* diversStockage,Charge* charge,
|
|
LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats)
|
|
|
|
{ // INITIALISATION globale
|
|
tempsInitialisation.Mise_en_route_du_comptage(); // temps cpu
|
|
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(NON_DYNA); // transfert info
|
|
// on défini globalement que l'on a pas de combinaison de ddl
|
|
int cas_combi_ddl=0; // c'est-à-dire que le seul ddl libre est X
|
|
// cas du chargement, on verifie egalement la bonne adequation des references
|
|
charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD);
|
|
// on définit un nouveau cas d'assemblage
|
|
// à travers la définition d'une instance de la classe assemblage
|
|
Nb_assemb cas_a = lesMail->InitNouveauCasAssemblage(1); // récup du numéro
|
|
Assemblage Ass(cas_a); // stockage numéro
|
|
// mise à jour du nombre de cas d'assemblage pour les conditions limites
|
|
// c-a-d le nombre maxi possible (intégrant les autres pb qui sont résolu en // éventuellement)
|
|
lesCondLim->InitNombreCasAssemblage(lesMail->Nb_total_en_cours_de_cas_Assemblage());
|
|
// mise a zero de tous les ddl et creation des tableaux a t+dt
|
|
// les ddl de position ne sont pas mis a zero ! ils sont initialise
|
|
// a la position courante
|
|
lesMail->ZeroDdl(true);
|
|
// on vérifie que les noeuds sont bien attachés à un élément sinon on met un warning si niveau > 2
|
|
if (ParaGlob::NiveauImpression() > 2)
|
|
lesMail->AffichageNoeudNonReferencer();
|
|
// init des ddl avec les conditions initials
|
|
lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl);
|
|
// activation des ddl de position
|
|
lesMail->Active_un_type_ddl_particulier(X1);
|
|
lesMail->MiseAJourPointeurAssemblage(Ass.Nb_cas_assemb());// mise a jour des pointeurs d'assemblage
|
|
// calcul de la largeur de bande effective
|
|
int demi,total;
|
|
lesMail->Largeur_Bande(demi,total,Ass.Nb_cas_assemb());
|
|
int nbddl = lesMail->NbTotalDdlActifs(); // nb total de ddl
|
|
total = std::min(total,nbddl);
|
|
// def de la matrice bande et d'un second membre globale
|
|
// a priori matrice symetrique
|
|
// initialisation a zero
|
|
MatBand matglob2(BANDE_SYMETRIQUE,demi,nbddl,0);
|
|
// vérification d'une singularité éventuelle de la matrice de raideur
|
|
VerifSingulariteRaideurMeca(nbddl,*lesMail);
|
|
// on groupe des vecteurs résidus sous forme de tableau pour des
|
|
// raison de facilité de manipulation par la suite
|
|
Tableau <Vecteur> tab_residu(2);
|
|
tab_residu(1).Change_taille(nbddl);
|
|
tab_residu(2).Change_taille(nbddl);
|
|
Vecteur& vglobin = tab_residu(1); // puissance interne
|
|
Vecteur& vglobex = tab_residu(2); // puissance externe
|
|
Vecteur vglobal(vglobin); // puissance totale
|
|
vglobal += vglobex;
|
|
|
|
// définition d'un pointeur de fonction d'assemblage ici symétrique
|
|
// utilisé dans la prise en compte des efforts extérieurs
|
|
void (Assemblage::* assembMat) // le pointeur
|
|
(Mat_abstraite & matglob2,const Mat_abstraite & matloc,
|
|
const DdlElement& tab_ddl,const Tableau<Noeud *>&tab_noeud)
|
|
= & Assemblage::AssembMatSym;
|
|
|
|
// dans le cas où l'on fait du line search on dimensionne des vecteurs
|
|
Vecteur * sauve_deltadept,*sauve_dept_a_tdt,*Vres,*v_travail;
|
|
if (pa.Line_search())
|
|
{ sauve_deltadept = new Vecteur(nbddl);
|
|
Vres = new Vecteur(nbddl);
|
|
sauve_dept_a_tdt = new Vecteur(nbddl);
|
|
v_travail = new Vecteur(nbddl);
|
|
}
|
|
|
|
// boucle sur les increments de charge
|
|
icharge = 1;
|
|
|
|
// definition des elements de frontiere, ces elements sont utilises pour le contact
|
|
lesMail->CreeElemFront();
|
|
// calcul éventuel des normales aux noeuds -> init des normales pour t=0
|
|
lesMail->InitNormaleAuxNoeuds(); //utilisé pour la stabilisation des membranes par ex
|
|
// --- init du contact ---
|
|
// doit-être avant la lecture d'un restart, car il y a une initialisation de conteneurs qui est faites
|
|
// qui ensuite est utilisée en restart
|
|
// par exemple il faut initialiser les frontières et la répartition esclave et maître
|
|
// pour préparer la lecture de restart éventuel
|
|
if (lesMail->NbEsclave() != 0)
|
|
{ // definition des elements de frontiere, ces elements sont utilises pour le contact
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
// initialisation des zones de contacts éventuelles
|
|
lesContacts->Init_contact(*lesMail,*lesRef,lesFonctionsnD);
|
|
|
|
// verification qu'il n'y a pas de contact avant le premier increment de charge
|
|
lesContacts->Verification();
|
|
// definition des elements de contact eventuels
|
|
// et imposition éventuel de certaines des conditions de contact (dépend du modèle de contact)
|
|
try {
|
|
bool nevez_contact = lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
|
|
int niveau_substitution = 0; // on intervient sur toutes les matrices
|
|
bool premier_calcul = true;
|
|
// mise à jour éventuelle de la matrice de raideur en fonction du contact
|
|
//bool changement_sur_matrice =
|
|
Gestion_stockage_et_renumerotation_avec_contact
|
|
(premier_calcul,lesMail,nevez_contact,lesCondLim
|
|
,lesRef,tab_mato,Ass.Nb_cas_assemb(),lesContacts,niveau_substitution);
|
|
matglob=tab_mato(1);
|
|
}
|
|
// sortie anormale de l'initialisation du contact
|
|
catch (ErrSortieFinale)
|
|
// cas d'une direction voulue vers la sortie
|
|
// on relance l'interuption pour le niveau supérieur
|
|
{ ErrSortieFinale toto;
|
|
throw (toto);
|
|
}
|
|
catch (...)// erreur inconnue
|
|
{ cout << "\n **** >>>> ERREUR inconnuee en en initialisant le contact ***** ";
|
|
if (ParaGlob::NiveauImpression() >= 4)
|
|
cout << "\n AlgoriNonDyna::InitAlgorithme(..";
|
|
cout << endl;
|
|
};
|
|
};
|
|
//--cas de restart et/ou de sauvegarde------------
|
|
// tout d'abord récup du restart si nécessaire
|
|
// dans le cas ou un incrément différent de 0 est demandé -> seconde lecture à l'incrément
|
|
if (this->Num_restart() != 0)
|
|
{ int cas = 2;
|
|
// ouverture de base info
|
|
entreePrinc->Ouverture_base_info("lecture");
|
|
this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,(this->Num_restart()));
|
|
icharge = this->Num_restart();//+1;
|
|
// comme les conditions limites cinématiques peuvent être différentes en restart
|
|
// par rapport à celles sauvegardées, on commence par libérer toutes les CL imposées éventuelles
|
|
lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE);
|
|
lesMail->ChangeStatut(cas_combi_ddl,LIBRE);
|
|
// dans le cas d'un calcul axisymétrique on bloque le ddl 3
|
|
if (ParaGlob::AxiSymetrie())
|
|
lesMail->Inactive_un_ddl_particulier(X3);
|
|
// on valide l'activité des conditions limites et condition linéaires, pour le temps initial
|
|
// en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI)
|
|
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
|
|
// mise à jour pour le contact s'il y du contact présumé
|
|
if (pa.ContactType())
|
|
lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t);
|
|
};
|
|
// vérif de cohérence pour le contact
|
|
if ((pa.ContactType()) && (lesMail->NbEsclave() == 0)) // là pb
|
|
{cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact "
|
|
<< " la definition d'un type contact possible est donc incoherente "
|
|
<< " revoir la mise en donnees !! "<< flush;
|
|
Sortie(1);
|
|
};
|
|
// on regarde s'il y a besoin de sauvegarde
|
|
if (this->Active_sauvegarde())
|
|
{ // si le fichier base_info n'est pas en service on l'ouvre
|
|
entreePrinc->Ouverture_base_info("ecriture");
|
|
// dans le cas ou se n'est pas un restart on sauvegarde l'incrément actuel
|
|
// c'est-à-dire le premier incrément
|
|
// après s'être positionné au début du fichier
|
|
if (this->Num_restart() == 0)
|
|
{ (entreePrinc->Sort_BI())->seekp(0);
|
|
int cas = 1;
|
|
paraGlob->Ecriture_base_info(*(entreePrinc->Sort_BI()),cas);
|
|
this->Ecriture_base_info
|
|
(cas,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage
|
|
,charge,lesCondLim,lesContacts,resultats,OrdreVisu::INCRE_0);
|
|
}
|
|
else
|
|
{ // sinon on se place dans le fichier à la position du restart
|
|
// debut_increment a été définit dans algori (classe mère)
|
|
(entreePrinc->Sort_BI())->seekp(debut_increment);
|
|
}
|
|
}
|
|
//--fin cas de restart et/ou de sauvegarde--------
|
|
OrdreVisu::EnumTypeIncre type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
|
|
|
|
tempsInitialisation.Arret_du_comptage(); // temps cpu
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
|
|
|
|
// tant que la fin du chargement n'est pas atteinte
|
|
// dans le cas du premier chargement on calcul de toute manière, ce qui permet
|
|
// de calculer meme si l'utilisateur indique un increment de charge supérieur
|
|
// au temps final
|
|
bool arret_pilotage=false; // pour arrêt du calcul au niveau du pilotage
|
|
while (((!charge->Fin(icharge))||(icharge == 1))
|
|
&& (charge->Fin(icharge,true)!=2) // si on a dépassé le nombre d'incrément permis on s'arrête dans tous les cas
|
|
&& (charge->Fin(icharge,false)!=3) // idem si on a dépassé le nombre d'essai d'incrément permis
|
|
// 1er appel avec true: pour affichage et second avec false car c'est déjà affiché
|
|
)
|
|
{ double maxPuissExt; // maxi de la puissance des efforts externes
|
|
double maxPuissInt; // maxi de la puissance des efforts internes
|
|
double maxReaction; // maxi des reactions
|
|
int inReaction = 0; // pointeur d'assemblage pour le maxi de reaction
|
|
int inSol =0 ; // pointeur d'assemblage du maxi de variation de ddl
|
|
double max_delta_X=0.; // le maxi du delta X
|
|
double max_var_delta_X=0.; // idem d'une itération à l'autre
|
|
double maxDeltaDdl=0; // // maxi de variation de ddl
|
|
double last_var_ddl_max=0; // maxi var ddl juste après résolutuion, que l'on sauvegarde d'une it à l'autre
|
|
|
|
// mise à jour du calcul éventuel des normales aux noeuds -> mise à jour des normales à t
|
|
// mais ici, on calcule les normales à tdt, et on transfert à t
|
|
// comme on est au début de l'incrément, la géométrie à tdt est identique à celle à t
|
|
// sauf "au premier incrément", si l'algo est un sous algo d'un algo combiné
|
|
// et que l'on suit un précédent algo sur un même pas de temps
|
|
// qui a aboutit à une géométrie à tdt différente de celle de t
|
|
// du coup cela permet d'utiliser la nouvelle géométrie pour ce premier incrément
|
|
lesMail->MiseAjourNormaleAuxNoeuds_de_tdt_vers_T();
|
|
// passage aux noeuds des vecteurs globaux: F_INT, F_EXT
|
|
Algori::Passage_aux_noeuds_F_int_t_et_F_ext_t(lesMail);
|
|
|
|
// initialisation de la variable puissance_précédente d'une itération à l'autre
|
|
double puis_precedente = 0.;
|
|
Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
|
|
Pilotage_du_temps(charge,arret_pilotage); // appel du Pilotage
|
|
if (arret_pilotage) break; // pilotage -> arret du calcul
|
|
|
|
// affichage de l'increment de charge
|
|
bool aff_incr=pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde); // pour simplifier
|
|
if (aff_incr)
|
|
{cout << "\n======================================================================"
|
|
<< "\nINCREMENT DE CHARGE : " << icharge
|
|
<< " intensite " << charge->IntensiteCharge()
|
|
<< " t= " << charge->Temps_courant()
|
|
<< " dt= " << ParaGlob::Variables_de_temps().IncreTempsCourant()
|
|
<< "\n======================================================================";
|
|
};
|
|
lesLoisDeComp->MiseAJour_umat_nbincr(icharge); // init pour les lois Umat éventuelles
|
|
// initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement et des conditions linéaires imposées
|
|
bool change_statut = false; // init des changements de statut, ne sert pas ici
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
|
|
/* // mise en place du chargement impose sur le second membre
|
|
// et éventuellement sur la raideur en fonction de sur_raideur
|
|
vglobex.Zero();
|
|
// bool sur_raideur = false; // pour l'instant pas de prise en compte sur la raideur
|
|
bool sur_raideur = true; // essai
|
|
charge->ChargeSMembreRaideur_Im_mecaSolid
|
|
(Ass,lesMail,lesRef,vglobex,sur_raideur,matglob2,assembMat,pa,lesCourbes1D);
|
|
maxPuissExt = vglobex.Max_val_abs(); */
|
|
|
|
// boucle de convergence sur un increment
|
|
Vecteur * sol; // pointeur du vecteur solution delta ddl classique
|
|
Vecteur * solF; // idem pour la solution delta ddl pour uniquement la puissance externe
|
|
|
|
// bool ifresol = false;// drapeau pour le cas d'une charge sans resolution
|
|
int compteur; // déclaré à l'extérieur de la boucle car utilisé après la boucle
|
|
bool arret_convergence = false;
|
|
for (compteur = 0; compteur<= pa.Iterations();compteur++)
|
|
{// initialisation de la matrice et du second membre
|
|
matglob2.Initialise (0.);
|
|
vglobin.Zero();
|
|
vglobex.Zero();
|
|
if (pa.ContactType())
|
|
vcontact.Zero();
|
|
vglobaal.Zero(); // puissance totale
|
|
// prise en compte du cas particulier ou l'utilisateur demande
|
|
// une mise à jour des conditions limites à chaque itération
|
|
if (cL_a_chaque_iteration)
|
|
{// -- initialisation des coordonnees et des ddl a tdt en fonctions des
|
|
// ddl imposes et de l'increment du chargement: change_statut sera recalculé ensuite
|
|
lesCondLim->MiseAJour_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// on récupère les nouvelles positions globalement de manière à pouvoir calculer le delta_X pour le contact
|
|
lesMail->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1);
|
|
// delta_X = X_tdt; delta_X -= X_t; // X_tdt - X_t
|
|
Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X);
|
|
};
|
|
// renseigne les variables définies par l'utilisateur
|
|
// via les valeurs déjà calculées par Herezh
|
|
Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales
|
|
(lesMail,varExpor,Ass.Nb_cas_assemb(),*lesRef);
|
|
varExpor->RenseigneVarUtilisateur(*lesMail,*lesRef);
|
|
lesMail->CalStatistique(); // calcul éventuel de statistiques
|
|
// init de var glob
|
|
Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(compteur);
|
|
lesMail->Force_Ddl_aux_noeuds_a_une_valeur(R_X1,0.0,TEMPS_tdt,true); // mise à 0 des ddl de réactions, qui sont uniquement des sorties
|
|
lesMail->Force_Ddl_etendu_aux_noeuds_a_zero(Ddl_enum_etendu::Tab_FN_FT()); // idem pour les composantes normales et tangentielles
|
|
// mise en place du chargement impose sur le second membre
|
|
// et éventuellement sur la raideur en fonction de sur_raideur
|
|
// mise en place des conditions linéaires
|
|
lesCondLim->MiseAJour_condilineaire_tdt
|
|
(pa.Multiplicateur(),lesMail,charge->Increment_de_Temps(),lesRef,charge->Temps_courant()
|
|
,lesCourbes1D,lesFonctionsnD,charge->MultCharge(),change_statut,cas_combi_ddl);
|
|
// affichage ou non de l'itération
|
|
bool aff_iteration = (pa.freq_affich_iter() > 0) ?
|
|
(aff_incr && (compteur % pa.freq_affich_iter()==0) &&(compteur!=0)) : false ;
|
|
lesLoisDeComp->MiseAJour_umat_nbiter(compteur); // init pour les lois Umat éventuelles
|
|
// bool sur_raideur = false; // pour l'instant pas de prise en compte sur la raideur
|
|
// bool sur_raideur = true; // essai
|
|
// mise en place du chargement impose, c-a-d calcul de la puissance externe
|
|
// si pb on sort de la boucle
|
|
if (!(charge->ChargeSMembreRaideur_Im_mecaSolid
|
|
(Ass,lesMail,lesRef,vglobex,matglob2,assembMat,pa,lesCourbes1D,lesFonctionsnD)))
|
|
{ Change_PhaseDeConvergence(-10);break;};
|
|
maxPuissExt = vglobex.Max_val_abs();
|
|
// -- appel du calcul de la raideur et du second membre, énergies
|
|
// dans le cas d'un calcul inexploitable arrêt de la boucle
|
|
if (!RaidSmEner(lesMail,Ass,vglobin,matglob2)) break;
|
|
// calcul des maxi des puissances internes
|
|
maxPuissInt = vglobin.Max_val_abs();
|
|
// second membre total
|
|
vglobal += vglobex ; vglobal += vglobin;
|
|
// initialisation des sauvegardes sur matrice et second membre
|
|
lesCondLim->InitSauve(Ass.Nb_cas_assemb());
|
|
// sauvegarde des reactions aux ddl bloque
|
|
lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass.Nb_cas_assemb(),cas_combi_ddl); // a voir au niveau du nom
|
|
// mise en place des conditions limites
|
|
lesCondLim->ImposeConLimtdt(lesMail,lesRef,matglob2,vglobal,Ass.Nb_cas_assemb()
|
|
,cas_combi_ddl,vglob_stat);
|
|
// ************* il faut aussi les conditions limites sur vglobex***********
|
|
// calcul du maxi des reactions
|
|
maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
|
|
// resolution
|
|
// matglob2.Affiche(1,6,1,1,6,1);
|
|
// matglob2.Affiche(1,8,1,7,8,1);
|
|
// matglob2.Affiche(1,18,1,13,18,1);
|
|
// vglobal.Affiche();
|
|
// matglob2.Affiche(1,12,1,1,6,1);
|
|
// matglob2.Affiche(1,12,1,7,12,1);
|
|
// matglob2.Affiche(1,12,1,9,12,1);
|
|
// matglob2.Affiche(1,18,1,13,18,1);
|
|
// vglobal.Affiche();
|
|
// sortie d'info sur l'increment concernant les réactions
|
|
if (compteur != 0)
|
|
if (aff_iteration) InfoIncrementReac(lesMail,compteur,inReaction,maxReaction,Ass.Nb_cas_assemb());
|
|
// test de convergence sur un increment
|
|
if (Convergence(aff_iteration,last_var_ddl_max,vglobal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret_convergence))
|
|
{ // sortie des itérations sauf si l'on est en loi simplifiée
|
|
if (lesLoisDeComp->Test_loi_simplife() )
|
|
// cas d'une loi simplifié on remet normal
|
|
lesLoisDeComp->Loi_simplifie(false);
|
|
else
|
|
// cas normal,
|
|
break;
|
|
}
|
|
else if (arret_convergence) {break;} // cas ou la méthode Convergence() demande l'arret
|
|
// sinon on continue
|
|
// pour le pilotage, sauvegarde du résidu
|
|
if (pa.Line_search()) (*Vres) = vglobal;
|
|
// on résoud deux systèmes, correspondant pour le premier
|
|
// aux déplacements classiques stockés en sortie dans tab_résidu(1)
|
|
// ce dernier contenant en entrée le résidu interne + externe
|
|
// tab_résidu(2) en entrée correspond uniquement aux puissances externes
|
|
// en sortie il correspond aux delta ddl relativement uniquement aux puissances
|
|
// externes
|
|
tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu
|
|
matglob2.Resol_systID(tab_residu);
|
|
tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu
|
|
sol = &tab_residu(1); // solution d'incrément de déplacement classique
|
|
solF = &tab_residu(2); // delta ddl pour le résidu externe uniquement
|
|
// calcul du maxi de variation de ddl
|
|
maxDeltaDdl = sol->Max_val_abs(inSol);
|
|
double maxDeltatDdl_signe=(*sol)(inSol); // récupération de la grandeur signée
|
|
// pilotage à chaque itération: ramène: maxDeltaDdl,csol modifiés éventuellement et insol
|
|
Pilotage_chaque_iteration(sol,maxDeltaDdl,compteur,lesMail);
|
|
// sortie d'info sur l'increment concernant les variations de ddl
|
|
if ((aff_iteration)&&(ParaGlob::NiveauImpression() > 1))
|
|
InfoIncrementDdl(lesMail,inSol,maxDeltatDdl_signe,Ass.Nb_cas_assemb());
|
|
|
|
// suite du pilotage
|
|
// ------------------------------------------------------------
|
|
// |on regarde s'il faut utiliser l'algorithme de line search |
|
|
// ------------------------------------------------------------
|
|
bool avec_line_search = false;
|
|
if (pa.Line_search())
|
|
{ // la méthode de line_search incrémente la solution
|
|
// même s'il n'y a pas de mise en oeuvre de la méthode
|
|
avec_line_search = Line_search1
|
|
(*sauve_deltadept,puis_precedente,*Vres,lesMail,sol
|
|
,compteur,*sauve_dept_a_tdt,charge,vglobex,Ass,*v_travail,
|
|
lesCondLim,vglobal,lesRef,vglobin,Ass.Nb_cas_assemb()
|
|
,cas_combi_ddl,lesCourbes1D,lesFonctionsnD);
|
|
}
|
|
else
|
|
//cas ou l'on ne fait pas de line seach
|
|
{ // actualisation des ddl actifs a t+dt
|
|
lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb());
|
|
}
|
|
//---//\\//\\// fin de la boucle sur les itérations d'équilibres //\\//\\//
|
|
}
|
|
// gestion de la fin des itérations
|
|
if (!Pilotage_fin_iteration_implicite(compteur))
|
|
{ // cas d'une non convergence
|
|
// comme on incrémente pas les ddl on remet cependant les ddl
|
|
// et les grandeurs actives de tdt aux valeurs de ceux de t
|
|
lesMail->TversTdt();
|
|
}
|
|
else
|
|
{// sinon calcul correcte
|
|
// actualisation des ddl et des grandeurs actives de t+dt vers t
|
|
lesMail->TdtversT();
|
|
// cas du calcul des énergies, passage des grandeurs de tdt à t
|
|
Algori::TdtversT();
|
|
// sauvegarde de l'incrément si nécessaire
|
|
tempsCalEquilibre.Arret_du_comptage(); // on arrête le compteur pour la sortie
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
|
|
,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
// visualisation éventuelle au fil du calcul
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur
|
|
// test de fin de calcul effectue dans charge via : charge->Fin()
|
|
icharge++;
|
|
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
|
|
}
|
|
}
|
|
// fin des calculs
|
|
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
|
|
// fin des calculs
|
|
type_incre = OrdreVisu::DERNIER_INCRE;
|
|
VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge
|
|
,lesCondLim,lesContacts,resultats,type_incre,icharge);
|
|
// sauvegarde de l'incrément si nécessaire
|
|
Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD
|
|
,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts
|
|
,resultats,type_incre,icharge);
|
|
// enregistrement du num d'incrément et du temps correspondant
|
|
list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant()));
|
|
};
|
|
|