// This file is part of the Herezh++ application.
//
// The finite element software Herezh++ is dedicated to the field
// of mechanics for large transformations of solid structures.
// It is developed by Gérard Rio (APP: IDDN.FR.010.0106078.000.R.P.2006.035.20600)
// INSTITUT DE RECHERCHE DUPUY DE LÔME (IRDL) .
//
// Herezh++ is distributed under GPL 3 license ou ultérieure.
//
// Copyright (C) 1997-2022 Université Bretagne Sud (France)
// AUTHOR : Gérard Rio
// E-MAIL : gerardrio56@free.fr
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License,
// or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// For more information, please consult: .
#include "AlgoriFlambLineaire.h"
#include "ElemMeca.h"
// CONSTRUCTEURS :
AlgoriFlambLineaire::AlgoriFlambLineaire () : // par defaut
Algori()
{ };
// constructeur en fonction du type de calcul et du sous type
// il y a ici lecture des parametres attaches au type
AlgoriFlambLineaire::AlgoriFlambLineaire (const bool avec_typeDeCal
,const list & soustype
,const list & avec_soustypeDeCal
,UtilLecture& entreePrinc) :
Algori(FLAMB_LINEAIRE,avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc)
,vglobin(),vglobex(),vglobaal()
,vcontact(),matglob(NULL),forces_vis_num(0)
// ,methode(NULL),nbValPropre(NULL)
{ // lecture des paramËtres attachÈs au type de calcul
switch (entreePrinc.Lec_ent_info())
{ case 0 :
{ lecture_Parametres(entreePrinc); break;}
case -11 : // cas de la crÈation d'un fichier de commande
{ Info_commande_parametres(entreePrinc); break;}
case -12 : // cas de la crÈation d'un schÈma XML, on ne fait rien ‡ ce niveau
{ break;}
default:
Sortie(1);
}
};
// constructeur de copie
AlgoriFlambLineaire::AlgoriFlambLineaire (const AlgoriFlambLineaire& algo):
Algori(algo)
,methode(algo.methode),nbValPropre(algo.nbValPropre)
,vglobin(),vglobex(),vglobaal()
,vcontact(),matglob(NULL),forces_vis_num(0)
{};
// destructeur
AlgoriFlambLineaire::~AlgoriFlambLineaire ()
{
};
// execution de l'algorithme pour la recherche des modes de flambement
//dans le cas non dynamique, implicit, sans contact
void AlgoriFlambLineaire::Execution(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(FLAMB_LINEAIRE); // transfert info
// mise à jour au cas où
Algori::MiseAJourAlgoMere(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp,diversStockage
,charge,lesCondLim,lesContacts,resultats);
// on dÈfini globalement que l'on a pas de combinaison des c'est ‡ dire que le seul ddl est X
int 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);
// 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 actifs 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 actifs 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
// choix de la matrice de raideur du système linéaire en Xi
Choix_matriciel(nbddl,tab_mato,lesMail,lesRef,Ass.Nb_cas_assemb(),lesCondLim);
matglob = tab_mato(1); // par défaut c'est la première matrice
// $$$ essai newton modifié $$$
// bool newton_modifie=true;Mat_abstraite matsauv(matglob);
// if (newton_modifie) matsauv=new Mat_abstraite(matglob);
// choix de la résolution
matglob->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement());
// vérification d'une singularité éventuelle de la matrice de raideur
VerifSingulariteRaideurMeca(nbddl,*lesMail);
vglobin.Change_taille(nbddl); // puissance interne
vglobex.Change_taille(nbddl); // puissance externe
vglobaal.Change_taille(nbddl,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); // puissance de contact
// 6 vecteur pour une manipulation globale des positions vitesses et accélérations
// vecteur qui globalise toutes les positions de l'ensemble des noeuds
X_t.Change_taille(nbddl);X_tdt.Change_taille(nbddl); delta_X.Change_taille(nbddl);
var_delta_X.Change_taille(nbddl);
// vecteur qui globalise toutes les vitesses de l'ensemble des noeuds
vitesse_t.Change_taille(nbddl);vitesse_tdt.Change_taille(nbddl);
// vecteur qui globalise toutes les accélérations
acceleration_t.Change_taille(nbddl);acceleration_tdt.Change_taille(nbddl) ;
// vecteur de travail pour la viscosité artificielle
if (pa.Amort_visco_artificielle())
{ forces_vis_num.Change_taille(nbddl);
if (Arret_A_Equilibre_Statique()) // si on veut un équilibre statique, on sauvegarde les forces statiques
{ if (vglob_stat != NULL)
{vglob_stat->Change_taille(vglobaal.Taille());}
else
{vglob_stat = new Vecteur(vglobaal.Taille());}
};
};
// 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 & matglob,const Mat_abstraite & matloc,
const DdlElement& tab_ddl,const Tableau&tab_noeud)
= & Assemblage::AssembMatSym;
// un premier increment pour demmarer le processus
charge->Avance(); // premier increment de charge
// 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
lesContacts->DefElemCont(0.); // au début le déplacement des noeuds est nul
};
//--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--------
// 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);
};
tempsInitialisation.Arret_du_comptage(); // temps cpu
tempsCalEquilibre.Mise_en_route_du_comptage(); // temps cpu
//----------------------------------------------------------------------
// calcul prÈliminaire pour prÈcharger Èventuellement la structure
//----------------------------------------------------------------------
OrdreVisu::EnumTypeIncre type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul
// 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=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 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
Transfert_ParaGlob_NORME_CONVERGENCE(ConstMath::grand);// on met une norme grande par défaut au début
// 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);
Pilotage_du_temps(charge,arret); // appel du Pilotage
if (arret) 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
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);
lesCondLim->MiseAJour_condilineaire_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();
int compteur=0; // dÈclarÈ ‡ l'extÈrieur de la boucle car utilisÈ aprËs la boucle
// 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);
// 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,*matglob,assembMat,pa,lesCourbes1D,lesFonctionsnD)))
{ Change_PhaseDeConvergence(-10);break;};
maxPuissExt = vglobex.Max_val_abs();
F_ext_tdt = vglobex; // sauvegarde des forces généralisées extérieures
// boucle de convergence sur un increment
Vecteur * sol; // pointeur du vecteur solution
// bool ifresol = false;// drapeau pour le cas d'une charge sans resolution
for (compteur = 0; compteur<= pa.Iterations();compteur++)
{// initialisation de la matrice et du second membre
matglob->Initialise (0.);
vglobin.Zero();
if (pa.ContactType())
vcontact.Zero();
vglobaal.Zero(); // puissance totale
// 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
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
// 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
// boucle sur les elements
for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
{
//calcul de la raideur local et du residu local
Element & el = lesMail->Element_LesMaille(nbMail,ne); // l'element
Tableau& taN = el.Tab_noeud(); // tableau de noeuds de l'el
Element::ResRaid resu = el.Calcul_implicit(pa);
// (resu.res)->Affiche();
// (resu.raid)->Affiche();
// assemblage
Ass.AssemSM (vglobin,*(resu.res),el.TableauDdl(),taN); // du second membre
Ass.AssembMatSym (*matglob,*(resu.raid),el.TableauDdl(),taN); // de la raideur
}
// calcul des maxi des puissances internes
maxPuissInt = vglobin.Max_val_abs();
F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures
// second membre total
vglobaal += vglobex ;vglobaal += vglobin ;
// 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);
// sauvegarde des reactions pour les ddl bloques (simplement)
// ***dans le cas statique il semble (cf. commentaire dans l'algo) que ce soit inutile donc a voir
// ***donc pour l'instant du a un bug je commente
// sauvegarde des reactions aux ddl bloque
// 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,*matglob,vglobaal,Ass.Nb_cas_assemb()
,cas_combi_ddl,vglob_stat);
// calcul du maxi des reactions
maxReaction = lesCondLim->MaxEffort(inReaction,Ass.Nb_cas_assemb());
// resolution
// matglob.Affiche(1,6,1,1,6,1);
// matglob.Affiche(1,8,1,7,8,1);
// matglob.Affiche(1,18,1,13,18,1);
// vglobal.Affiche();
// matglob.Affiche(1,12,1,1,6,1);
// matglob.Affiche(1,12,1,7,12,1);
// matglob.Affiche(1,12,1,9,12,1);
// matglob.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,vglobaal,maxPuissExt,maxPuissInt,maxReaction,compteur,arret))
{ // 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) {break;} // cas ou la mÈthode Convergence() demande l'arret
// sinon on continue
// ici sol en fait = vecglob qui est ecrase par la resolution
// ---- resolution ----
bool erreur_resolution_syst_lineaire = false; // init
try
{// ici sol en fait = vecglob qui est ecrase par la resolution
sol = &(matglob->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
lesCondLim->RepInitiaux( *sol,Ass.Nb_cas_assemb());
//---debug
//cout << "\ndelta ddl "; for(int i=1;i<=3;i++) { cout << "\nnoe:"<Affiche(); // --- pour le debug
}
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
}
// effacement du marquage de ddl bloque du au conditions lineaire imposée par l'entrée
lesCondLim->EffMarque();
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
};
// affichage Èventuelle du vecteur solution : deltat_ddl
if (ParaGlob::NiveauImpression() >= 10)
{ string entete = " affichage du vecteur solution (delta_ddl) ";
sol->Affichage_ecran(entete); };
// 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());
// sol->Affiche();
// actualisation des ddl actifs a t+dt
lesMail->PlusDelta_tdt(*sol,Ass.Nb_cas_assemb());
// indication qu'un calcul a ete effectue
// ifresol = true;
}
// 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();
// on valide l'activitÈ des conditions limites et condition linÈaires
lesCondLim->Validation_blocage (lesRef,charge->Temps_courant());
// 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);
// test de fin de calcul effectue dans charge via : charge->Fin()
icharge++;
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
}
}
// on remet à jour le nombre d'incréments qui ont convergés:
icharge--;
Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge);
// passage finale dans le cas d'une visualisation au fil du calcul
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()));
//--------------------------------------------------------------------
// calcul particulier ‡ la recherche de valeurs et vecteurs propres
//--------------------------------------------------------------------
// affichage
cout << "\n================================================================="
<< "\n calcul des valeurs et vecteurs propres "
<< "\n=================================================================";
// def de la matrice bande gÈomÈtrique
// a priori matrice symetrique
// initialisation a zero
MatBand matgeom(BANDE_SYMETRIQUE,demi,nbddl,0);
// initialisation de la matrice de raideur
matglob->Initialise (0.);
// boucle sur les elements
for (int nbMail =1; nbMail<= lesMail->NbMaillage(); nbMail++)
for (int ne=1; ne<= lesMail->Nombre_element(nbMail);ne++)
{
ElemMeca * el = (ElemMeca *) &(lesMail->Element_LesMaille(nbMail,ne)); // l'element
Tableau& taN = el->Tab_noeud(); // tableau de noeuds de l'elÈment
//calcul de la raideur local et de la matrice gÈomÈtrique locale
ElemMeca::MatGeomInit resu = el->MatricesGeometrique_Et_Initiale (pa);
// (resu.matInit)->Affiche();
// (resu.matGeom)->Affiche();
// assemblage
Ass.AssembMatSym(*matglob,*(resu.matInit),el->TableauDdl(),taN); // de la raideur
Ass.AssembMatSym(matgeom,*(resu.matGeom),el->TableauDdl(),taN); // de la raideur
}
// pour mettre les conditions limites on se sert des informations sauvegardÈes dans
// lesCondLim
// mise en place des conditions limites
lesCondLim->ImpConLimtdt2Mat(lesMail,lesRef,*matglob,matgeom,Ass.Nb_cas_assemb(),cas_combi_ddl);
// matglob.Affiche(1,6,1,1,6,1);
// matglob.Affiche(1,8,1,7,8,1);
// matglob.Affiche(1,18,1,13,18,1);
// vglobal.Affiche();
// matglob.Affiche(1,12,1,1,6,1);
// matglob.Affiche(1,12,1,7,12,1);
// matglob.Affiche(1,12,1,9,12,1);
// matglob.Affiche(1,18,1,13,18,1);
// vglobal.Affiche();
// calcul des valeurs et vecteurs propres
Tableau VP((int)*nbValPropre);
// matglob.Affiche1(1,6,1,1,6,1);
// matgeom.Affiche1(1,6,1,1,6,1);
matglob->V_Propres(matgeom,VP);
// sauvegarde dans Resultat
resultats->VeaPropre() = LesValVecPropres(VP);
// fin des calculs
tempsCalEquilibre.Arret_du_comptage(); // temps cpu
};
// lecture des paramËtres du calcul
void AlgoriFlambLineaire::lecture_Parametres(UtilLecture& entreePrinc)
{ // dimensionnement
paraTypeCalcul.Change_taille(2);
Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(FLAMB_LINEAIRE); // transfert info
MotCle motCle; // ref aux mots cle
deja_lue_entete_parametre = 1; // a priori pas de lecture d'entÍte
// on se positionne sur le prochain mot clÈ
do
{ entreePrinc.NouvelleDonnee();
}
while ( !motCle.SimotCle(entreePrinc.tablcar)) ;
// si le mot clÈ est "PARA_TYPE_DE_CALCUL" cela signifie
// qu'il y a un paramËtre ‡ lire
bool lecture_effective = false;
if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL)
{ //cas de la dÈfinition de paramËtres
// on signale ‡ Algori qu'il y a eu dÈj‡ une lecture de paramËtre
deja_lue_entete_parametre=2;
// lecture du premier paramËtres de l'algorithme
entreePrinc.NouvelleDonnee(); // ligne suivante
// lecture du nom du paramËtre et vÈrification
string st1;
*(entreePrinc.entree) >> st1 ;
if (st1 != "methode_et_nbDeValeurPropre=")
{ cout << "\n erreur en lecture du paramËtre de l'algorithme de flambement lineaire"
<< "\n on attendait le mot : methode_et_nbDeValeurPropre= , au lieu de "
<< st1
<< "\n AlgoriFlambLineaire::lecture_Parametres( ... ";
Sortie(1);
}
// lecture du parametre
*(entreePrinc.entree) >> paraTypeCalcul(1) >> paraTypeCalcul(2);
lecture_effective = true;
}
else // sinon on met une valeur par dÈfaut
{ paraTypeCalcul(1) = 1; paraTypeCalcul(2) = 0;
}
// on relie les paramËtres ‡ bÈta et gamma
methode = & paraTypeCalcul(1);
nbValPropre = & paraTypeCalcul(2);
// on prÈpare la prochaine lecture si la lecture a ÈtÈ effective et que l'on n'est pas
// sur un mot clÈ
if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar)))
entreePrinc.NouvelleDonnee(); // ligne suivante
// puis appel de la mÈthode de la classe mËre
Algori::lecture_Parametres(entreePrinc);
};
// Ècriture des paramËtres dans la base info
// = 1 : on Ècrit tout
// = 2 : on Ècrot uniquement les donnÈes variables (supposÈes comme telles)
void AlgoriFlambLineaire::Ecrit_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas)
{
// récup du flot
ofstream * sort = entreePrinc.Sort_BI();
// (*sort) << "\n parametres_algo_specifiques_ "<< Nom_TypeCalcul(this->TypeDeCalcul());
if (cas == 1)
{
// ecriture du parametre
*(sort) << "methode_et_nbDeValeurPropre= " << paraTypeCalcul(1) << " "
<< paraTypeCalcul(2) << " ";
};
// (*sort) << "\n fin_parametres_algo_specifiques_ ";
};
// lecture des paramËtres dans la base info
// = 1 : on rÈcupËre tout
// = 2 : on rÈcupËre uniquement les donnÈes variables (supposÈes comme telles)
// choix = true : fonctionnememt normal
// choix = false : la mÈthode ne doit pas lire mais initialiser les donnÈes ‡ leurs valeurs par dÈfaut
// car la lecture est impossible
void AlgoriFlambLineaire::Lecture_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas,bool choix)
{if (cas == 1)
{// dimensionnement
paraTypeCalcul.Change_taille(2);
if (choix)
{// cas d'une lecture normale
// rÈcup du flot
ifstream * ent = entreePrinc.Ent_BI();
string toto;
// lecture du premier parametre
*(ent) >> toto ;
if (toto != "methode_et_nbDeValeurPropre=")
{ cout << "\n erreur en lecture du paramËtre de l'algorithme explicite "
<< "\n on attendait le mot : methode_et_nbDeValeurPropre= , au lieu de "
<< toto
<< "\n AlgoriFlambLineaire::Lecture_Base_info_Parametre( ... ";
Sortie(1);
}
*(ent) >> paraTypeCalcul(1) >> paraTypeCalcul(2);
}
else
{// cas o˘ la lecture n'est pas possible, attribution des valeurs par dÈfaut
paraTypeCalcul(1) = 1; paraTypeCalcul(2) = 0;
}
// on relie les paramËtres ‡ bÈta et gamma
methode = & paraTypeCalcul(1);
nbValPropre = & paraTypeCalcul(2);
}
};
// crÈation d'un fichier de commande: cas des paramËtres spÈcifiques
void AlgoriFlambLineaire::Info_commande_parametres(UtilLecture& entreePrinc)
{ // Ècriture dans le fichier de commande
ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier
sort << "\n#----------------------------------------------------------------------"
<< "\n| parametres (falcultatifs) associe au calcul de flambement lineaire |"
<< "\n#----------------------------------------------------------------------"
<< "\n"
<< "\n PARA_TYPE_DE_CALCUL"
<< "\n # ................................................................................."
<< "\n # / seule la methode 1 est valide actuellement pour des matrices carres uniquement/"
<< "\n # / le second chiffre = nb de valeur propre /"
<< "\n #................................................................................"
<< "\n methode_et_nbDeValeurPropre= 1 1 ";
// appel de la classe mère
Algori::Info_com_parametres(entreePrinc);
sort << "\n" << endl;
};