// 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_Positionnement_offset(entreePrinc->position_debut_fichier); 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_Positionnement_offset(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(ostream& sort,const int& cas) { 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(istream& ent,const int& cas,bool choix) {if (cas == 1) {// dimensionnement paraTypeCalcul.Change_taille(2); if (choix) {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; };