// 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 "AlgoBonelli.h" // CONSTRUCTEURS : AlgoBonelli::AlgoBonelli () : // par defaut Algori() { // message d'erreur cout << "\n constructeur par defaut de AlgoBonelli, ne doit pas etre utilise !!"; Sortie(1);}; // constructeur en fonction du type de calcul et du sous type // il y a ici lecture des parametres attaches au type AlgoBonelli::AlgoBonelli (const bool avec_typeDeCal ,const list & soustype ,const list & avec_soustypeDeCal ,UtilLecture& entreePrinc) : Algori(DYNA_EXP_BONELLI,avec_typeDeCal,soustype,avec_soustypeDeCal,entreePrinc) ,delta_t(0.),unsurdeltat(0.),deltatSurDeux(0.),deltat2(0.) ,delta_t_total(0.),unsurdeltat_total(0.),deltatSurDeux_total(0.),deltat2_total(0.) ,q_0(),p_0(),q_1(),p_1(),q_2(),p_2() // les vecteurs ddl globaux ,a_a(0.),b_b(0.322),k_max(2),omega_b(2.171),rho_b(0.6) ,pt_seg_temps(NULL),nb_pt_int_t(3) ,pPoint_i(),P_i_1(),P_i_2(),P_q1_k(),P_q2_k(),r_1_k(),r_2_k() ,vec_travail1(),vec_travail2(),dernier_phi() ,maxPuissExt(0.),maxPuissInt(0.),maxReaction(0.),inReaction(0),inSol(0.),maxDeltaDdl(0.) ,cas_combi_ddl(0),icas(),erreurSecondMembre(false),prepa_avec_remont(false) ,brestart(false),type_incre(OrdreVisu::PREMIER_INCRE) ,lesMail_(NULL),lesRef_(NULL),lesCourbes1D_(NULL),lesFonctionsnD_(NULL),charge_(NULL) ,lesCondLim_(NULL),lesContacts_(NULL),Ass1(NULL),Ass2(NULL),Ass3(NULL) ,vglobin(),vglobex(),vglobaal(),vcontact() ,vitesse_tplus() ,X_Bl(),V_Bl(),G_Bl(),forces_vis_num(0) ,li_gene_asso(),t_assemb(),tenuXVG(),mat_masse(NULL),mat_masse_sauve(NULL),mat_C_pt(NULL) { a_a =1./3. - b_b ; // init par défaut de a_a // pt_seg_temps est défini dans lecture_Parametres // 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 AlgoBonelli::AlgoBonelli (const AlgoBonelli& algo): Algori(algo) ,delta_t(0.),unsurdeltat(0.),deltatSurDeux(0.),deltat2(0.) ,delta_t_total(0.),unsurdeltat_total(0.),deltatSurDeux_total(0.),deltat2_total(0.) ,q_0(algo.q_0),p_0(algo.p_0),q_1(algo.q_1),p_1(algo.p_1),q_2(algo.q_2),p_2(algo.p_2) ,a_a(algo.a_a),b_b(algo.b_b),k_max(algo.k_max),omega_b(algo.omega_b) ,pt_seg_temps(NULL),nb_pt_int_t(algo.nb_pt_int_t) ,pPoint_i(algo.pPoint_i),P_i_1(algo.P_i_1),P_i_2(algo.P_i_2) ,P_q1_k(algo.P_q1_k),P_q2_k(algo.P_q2_k),r_1_k(algo.r_1_k),r_2_k(algo.r_2_k) ,vec_travail1(algo.vec_travail1),vec_travail2(algo.vec_travail2),dernier_phi(algo.dernier_phi) ,maxPuissExt(0.),maxPuissInt(0.),maxReaction(0.),inReaction(0),inSol(0.),maxDeltaDdl(0.) ,cas_combi_ddl(0),icas(0),erreurSecondMembre(false) ,prepa_avec_remont(false) ,brestart(false),type_incre(OrdreVisu::PREMIER_INCRE) ,lesMail_(NULL),lesRef_(NULL),lesCourbes1D_(NULL),lesFonctionsnD_(NULL),charge_(NULL) ,lesCondLim_(NULL),lesContacts_(NULL),Ass1(algo.Ass1),Ass2(algo.Ass2),Ass3(algo.Ass3) ,vglobin(),vglobex(),vglobaal(),vcontact() ,vitesse_tplus() ,X_Bl(),V_Bl(),G_Bl(),forces_vis_num(0) ,li_gene_asso(),t_assemb(),tenuXVG(),mat_masse(NULL),mat_masse_sauve(NULL),mat_C_pt(NULL) {pt_seg_temps = new GeomSeg(*(algo.pt_seg_temps)); //vglobal = &vglobin; }; // destructeur AlgoBonelli::~AlgoBonelli () { if (pt_seg_temps != NULL) delete pt_seg_temps; delete mat_masse; delete mat_masse_sauve;delete mat_C_pt; }; // execution de l'algorithme dans le cas dynamique explicite, sans contact void AlgoBonelli::Execution(ParaGlob * paraGlob,LesMaillages * lesMail ,LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD ,VariablesExporter* varExpor,LesLoisDeComp* lesLoisDeComp, DiversStockage* divStock ,Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts,Resultats* resultats) { Tableau < Fonction_nD* > * tb_combiner = NULL; // ici ne sert pas // on définit le type de calcul a effectuer : if ( soustypeDeCalcul->size()==0 ) // cas où il n'y a pas de sous type, on fait le calcul d'équilibre classique // signifie que le type principal est forcément valide { // initialisation du calcul InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi // bref que l'on n'a pas fini, sinon on passe if (! (charge->Fin(icharge,true) ) ) { // calcul de l'équilibre CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ,tb_combiner); // fin du calcul, pour l'instant on ne considère pas les autres sous-types FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); }; } else {if ( avec_typeDeCalcul ) // cas où le type principal est valide et qu'il y a des sous_types { // on regarde si le sous-type "commandeInteractive" existe, si oui on le met en place // détermine si le sous type de calcul existe et s'il est actif if (paraGlob->SousTypeCalcul(commandeInteractive)) {// -- cas avec commandes interactives // initialisation du calcul InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); // calcul de l'équilibre tant qu'il y a des commandes while (ActionInteractiveAlgo()) { // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi // bref que l'on n'a pas fini, sinon on passe if (! (charge->Fin(icharge,true) ) ) { CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ,tb_combiner); }; }; // fin du calcul, pour l'instant on ne considère pas les autres sous-types FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); } else // cas sans commandes interactives { // 1- on fait le calcul d'équilibre // initialisation du calcul InitAlgorithme(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); // on ne continue que si on n'a pas dépasser le nombre d'incréments maxi ou le temps maxi // bref que l'on n'a pas fini, sinon on passe if (! (charge->Fin(icharge,true) ) ) { // calcul de l'équilibre CalEquilibre(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ,tb_combiner); // fin du calcul, pour l'instant on ne considère pas les autres sous-types FinCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,varExpor,lesLoisDeComp ,divStock,charge,lesCondLim,lesContacts,resultats ); }; // ensuite on teste en fonction des calculs complémentaires // dépendant des sous_types. Pour l'instant ici uniquement la remontée list ::const_iterator ili,ili_fin = soustypeDeCalcul->end(); list ::const_iterator ila; for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin(); ili!=ili_fin;ili++,ila++) if (*ila) // cas où le sous type est valide {if (Remonte_in(*ili)) // on test la présence du calcul de remonté { // certaines initialisations sont nécessaires car c'est le premier calcul Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats); Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats); Algori::RemontSigma(lesMail); Algori::RemontErreur(lesMail); } else if ( (*ili) == sauveMaillagesEnCours ) { cout << "\n=================================================================" << "\n| ecriture des maillages en cours en .her et .lis |" << "\n=================================================================" << endl; // ----- sort les informations sur fichiers // Affichage des donnees des maillages dans des fichiers dont le nom est construit // à partir du nom de chaque maillage au format ".her" et ".lis" lesMail->Affiche_maillage_dans_her_lis(TEMPS_tdt,*lesRef); }; }; };// fin du cas sans commandes interactives } else // cas ou le type principal n'est pas valide // on ne fait que le calcul complémentaire { list ::const_iterator ili,ili_fin = soustypeDeCalcul->end(); list ::const_iterator ila; for (ili = soustypeDeCalcul->begin(),ila = avec_soustypeDeCalcul->begin(); ili!=ili_fin;ili++,ila++) if (*ila) // cas où le sous type est valide {if (Remonte_in(*ili)) // on test la présence du calcul de remonté { // certaines initialisations sont nécessaires car c'est le premier calcul Algori::InitRemontSigma(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats); Algori::InitErreur(lesMail,lesRef,divStock,charge,lesCondLim,lesContacts,resultats); Algori::RemontSigma(lesMail); Algori::RemontErreur(lesMail); } else if ( (*ili) == sauveMaillagesEnCours ) { cout << "\n=================================================================" << "\n| ecriture des maillages en cours en .her et .lis |" << "\n=================================================================" << endl; // ----- sort les informations sur fichiers // Affichage des donnees des maillages dans des fichiers dont le nom est construit // à partir du nom de chaque maillage au format ".her" et ".lis" lesMail->Affiche_maillage_dans_her_lis(TEMPS_0,*lesRef); }; }; } } }; // é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 AlgoBonelli::Ecrit_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas) { // récup du flot ofstream& sort = *entreePrinc.Sort_BI(); // sort << "\n parametres_algo_specifiques_ "<< Nom_TypeCalcul(this->TypeDeCalcul()); switch (cas) {case 1 : // ------- on sauvegarde tout ------------------------- { // ecriture des parametres de l'algorithme sort << "\n k_max= " << k_max << " a_a= " << a_a << " b_b= " << b_b << " rho_b= " << rho_b << " omega_b= " << omega_b << " nb_pt_int_t= " << nb_pt_int_t << " "; break; } case 2 : // ----------- on sauvegarde en minimaliste -------------------- { // ici rien break; } default : {// cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n"; cout << "AlgoBonelli::Ecrit_Base_info_Parametre(UtilLecture& ,const int& )" << " cas= " << cas << endl; Sortie(1); } }; // sort << "\n fin_parametres_algo_specifiques_ "; }; // lecture des paramètres dans la base info // = 1 : on récupère tout // = 2 : on récupère uniquement les données variables (supposées comme telles) // choix = true : fonctionememt normal // choix = false : la méthode ne doit pas lire mais initialiser les données à leurs valeurs par défaut // car la lecture est impossible void AlgoBonelli::Lecture_Base_info_Parametre(UtilLecture& entreePrinc,const int& cas,bool choix) {// récup du flot ifstream& ent = *entreePrinc.Ent_BI(); string toto; if (choix) {switch (cas) {case 1 : // ------- on récupère tout ------------------------- { // lecture des parametres de l'algorithme ent >> toto >> k_max >> toto >> a_a >> toto >> b_b >> toto >> rho_b >> toto >> omega_b >> toto >> nb_pt_int_t; if (pt_seg_temps != NULL) delete pt_seg_temps; pt_seg_temps = new GeomSeg(nb_pt_int_t); break; } case 2 : // ----------- on récupère en minimaliste -------------------- { break; // ici rien } default : { cout << "\nErreur : valeur incorrecte du type de sauvegarde !\n"; cout << "AlgoBonelli::Lecture_Base_info_Parametre(UtilLecture& ,const int& )" << " cas= " << cas << endl; Sortie(1); } }; }; // ici on n'initialise pas les paramètre de réglage de l'algo, car ceux sont à initialiser en lecture // uniquement ce qui permet de les modifiers par un restart par exemple }; // gestion et vérification du pas de temps et modif en conséquence si nécessaire // cas = 0: premier passage à blanc, delta t = 0 // cas = 1: initialisation du pas de temps et vérif / au pas de temps critique // ceci pour le temps t=0 // cas = 2: initialisation du pas de temps et vérif / au pas de temps critique // ceci pour le temps t. et on divise par nbstep // ceci pour garantir que l'on fait le calcul avec 1 step void AlgoBonelli::Gestion_pas_de_temps(LesMaillages * lesMail,int cas,int ) { bool modif_deltat = false; // booleen pour la prise en compte éventuelle de la modif du temps éventuelle switch (cas) { case 0 : { // cas d'un passage à blanc, rien ne bouge et delta t est mis à 0 delta_t = 0.; unsurdeltat = ConstMath::unpeugrand;deltatSurDeux = 0.; break; } case 1 : { // ---- récup du pas de temps, proposé par l'utilisateur delta_t = pa.Deltat(); double delta_t_old = delta_t; // double delta_tSauve = delta_t; // sauvegarde de la situation actuelle // ---- on calcul le pas de temps minimal pour cela on utilise // les caractéristiques dynamiques d'une biellette de longueur // valant le minimum d'un coté d'arrête double l_sur_c = lesMail->Longueur_arrete_mini_sur_c(TEMPS_0); double delta_t_essai = l_sur_c ; // on prend en compte la particularité de l'algorithme / au pas de temps critique classique delta_t_essai *= omega_b * 0.5; // On utilise le omega de bifurcation et non celui critique, c'est plus sur // de toute façon , omega_b est très proche d'omega critique (cf. courbes d'évolution) // mise à jour éventuel du pas de temps et du pas de temps maxi et mini s'ils sont définit à partir du temps critique pa.Modif_Deltat_DeltatMaxi(delta_t_essai,l_sur_c); // mais pas de test vis-a-vis des bornes delta_t = pa.Deltat(); // mise à jour éventuelle du pas de temps // maintenant on vérifie le pas de temps choisit if (pa.Limit_temps_stable() && ( delta_t > delta_t_essai)) { cout << "\n ** ATTENTION ** , l'increment de temps propose : " << delta_t << ", ne satisfait pas la condition de Courant (C-F-L), " << "\n on le regle donc pour que cette condition soit satisfaite: nouvel increment: " << delta_t_essai; delta_t = delta_t_essai; // modification de l'increment de temps dans les paramètres switch (pa.Modif_Deltat(delta_t)) {case -1: { cout << "\n initialisation du pas de temps avec la condition de Courant impossible, le nouveau pas" << "\n de temps calcule est plus petit que le pas de temps mini limite: " << pa.Deltatmini(); Sortie(1); break; } case 0: { break;} // cas normal case 1: { pa.Modif_Detat_dans_borne(delta_t); cout << "\n >>>> rectification du pas de temps "<Longueur_arrete_mini_sur_c(TEMPS_t); double delta_t_essai = l_sur_c ;double ancien_pas=delta_t; // on prend en compte la particularité de l'algorithme / au pas de temps critique classique delta_t_essai *= omega_b * 0.5; // On utilise le omega de bifurcation et non celui critique, c'est plus sur // de toute façon , omega_b est très proche d'omega critique (cf. courbes d'évolution) // on intervient que si le nouveau pas de temps critique est inférieur au pas de temps en cours if ( delta_t_essai < delta_t) {// mise à jour éventuel du pas de temps et du pas de temps maxi s'ils sont définit à partir du temps critique bool modif = pa.Modif_Deltat_DeltatMaxi(delta_t_essai,l_sur_c); // mais pas de test vis-a-vis des bornes // s'il y a eu modif du pas de temps on met à jour le pas courant if (modif) { delta_t = pa.Deltat(); modif_deltat=true;} // maintenant on vérifie néanmoins le pas de temps choisit au cas où // en particulier cette vérification n'est en fait pas utile si l'utilisateur // à utilisé un facteur du pas critique < 1 if (pa.Limit_temps_stable() && ( delta_t > delta_t_essai)) { if (pa.Coefficient_pas_critique_deltat() <= 1.) { delta_t = pa.Coefficient_pas_critique_deltat() * delta_t_essai;} else { delta_t = delta_t_essai;}; // modification de l'increment de temps dans les paramètres switch (pa.Modif_Deltat(delta_t)) {case -1: { cout << "\n **** modification du pas de temps impossible," << " le nouveau pas de temps calcule est plus petit que le pas de temps mini limite: " << pa.Deltatmini(); Sortie(1); break; } case 0: { break;} // cas normal case 1: { pa.Modif_Detat_dans_borne(delta_t); break;} // cas ou on dépasse la borne maxi }; modif_deltat=true; } if (modif_deltat) cout << "\n --->>>> modif increment de temps de " << ancien_pas << " a " << delta_t; } break; } //-- fin du cas == 2 default : {cout << "\nErreur : valeur incorrecte du cas = " << cas << "\n"; cout << "AlgoBonelli::Gestion_pas_de_temps(... \n"; Sortie(1); } }; // fin du switch // ---- mise à jour éventuelle des variables simplificatrices pour le temps if ((cas==1) || ( modif_deltat)) { unsurdeltat = 1./delta_t;deltatSurDeux = delta_t/2.; deltat2 = delta_t * delta_t; delta_t_total = delta_t; deltatSurDeux_total = deltatSurDeux; deltat2_total = deltat2; unsurdeltat_total = unsurdeltat; if (ParaGlob::NiveauImpression() >= 6) cout << "\n omega_b/2= " << omega_b*0.5 << " a_a= " << a_a << " b_b = " << b_b << " rho_b= " << rho_b << "\n"; } }; // modification transitoire du pas de temps et modif en conséquence si nécessaire // utilisée pour les différentes intégrales temporelles // delta_t : nouveau pas de temps transitoire imposé void AlgoBonelli::Modif_transi_pas_de_temps(double del_t) { // modification de l'increment de temps suivant l'entrée delta_t = del_t; switch (pa.Modif_Deltat(delta_t)) {case -1: { cout << "\n ** AlgoBonelli: initialisation du pas de temps non acceptee, le nouveau pas" << "\n de temps calcule est plus petit que le pas de temps mini limite: " << pa.Deltatmini(); Sortie(1); break; } case 0: { break;} // cas normal case 1: { cout << "\n ** AlgoBonelli: initialisation du pas de temps non acceptee, le nouveau pas" << "\n de temps calcule est plus grand que le pas de temps maxi limite: " << pa.Deltatmaxi(); Sortie(1); break; } }; // --- mise à jour des variables simplificatrices pour le temps unsurdeltat = 1./delta_t;deltatSurDeux = delta_t/2.; deltat2 = delta_t * delta_t; }; // lecture des paramètres du calcul void AlgoBonelli::lecture_Parametres(UtilLecture& entreePrinc) { MotCle motCle; // ref aux mots cle Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(DYNA_EXP_BONELLI); // transfert info deja_lue_entete_parametre = 1; // a priori pas de lecture d'entête // on se positionne sur le prochain mot clé do { entreePrinc.NouvelleDonnee(); } while ( !motCle.SimotCle(entreePrinc.tablcar)) ; // si le mot clé est "PARA_TYPE_DE_CALCUL" cela signifie // qu'il y a un paramètre à lire bool lecture_effective = false; 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 if (strstr(entreePrinc.tablcar,"k_max_")!=NULL) { // on lit le nombre d'iteration de correction string st1; *(entreePrinc.entree) >> st1 >> k_max; if (st1 != "k_max_") { cout << "\n erreur en lecture du nombre d'iteration de correction " << "\n on attendait le mot : k_max_ , au lieu de " << st1 << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; // on vérifie la valeur lue if ((k_max < 1) && (k_max > 3)) { cout << "\n erreur en lecture du nombre d'iteration de correction " << "\n on attendait une valeur comprise entre 1 et 3 au lieu de: " << k_max << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; lecture_effective = true; } else // sinon on met une valeur par défaut { k_max=2; }; // lecture du rayon spectral de la matrice d'amplification, a la bifurcation if (strstr(entreePrinc.tablcar,"rho_b_")!=NULL) { // on lit le rayon spectral string st1; *(entreePrinc.entree) >> st1 >> rho_b; if (st1 != "rho_b_") { cout << "\n erreur en lecture du rayon spectral " << "\n on attendait le mot : rho_b_ , au lieu de " << st1 << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; lecture_effective = true; } else // sinon on met une valeur par défaut { rho_b = 0.6; // si k_max =3, ce sera modifié par la suite }; // lecture directe du coefficient b --> pour test, a la bifurcation if (strstr(entreePrinc.tablcar,"b_b_")!=NULL) { // on lit le coefficient b string st1; *(entreePrinc.entree) >> st1 >> b_b; if (st1 != "b_b_") { cout << "\n erreur en lecture du facteur b_bl " << "\n on attendait le mot : b_b_ , au lieu de " << st1 << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; lecture_effective = true; } else // sinon on met une valeur par défaut { b_b=0.; // pour signaler que b_b n'a pas été lue }; // lecture du nombre de points d'integration pour la quadrature temporelle if (strstr(entreePrinc.tablcar,"nb_pt_int_t_")!=NULL) { // on lit le nombre de point string st1; *(entreePrinc.entree) >> st1 >> nb_pt_int_t; if (st1 != "nb_pt_int_t_") { cout << "\n erreur en lecture du nombre de point d'integration " << "\n on attendait le mot : nb_pt_int_t_ , au lieu de " << st1 << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; lecture_effective = true; } else // sinon on met une valeur par défaut { nb_pt_int_t = 3; }; // on détermine les paramètres utils pour le calcul pt_seg_temps = new GeomSeg(nb_pt_int_t); switch (k_max) {case 1: { if ((rho_b < 0.34) || (rho_b > 1.)) // vérif de la valeur demandée { cout << "\n erreur: le rayon spectral demande n'est pas possible " << "\n il doit etre compris entre 0.34 et 1. alors que l'on a lu " << rho_b << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; if (b_b == 0.) {// calcul de b_b et omega_b b_b = ((0.0909 * rho_b - 0.3824) * rho_b + 0.8043) * rho_b - 0.0622 ; omega_b = ((0.0107 * rho_b -0.064) * rho_b + 0.3722) * rho_b + 1.8827 ; } else // cas où b_b est directement lue {omega_b = 1. ; // fixé arbitrairement car on ne le connait pas }; a_a =1./3. - b_b ; break; } case 2: { if ((rho_b < 0.) || (rho_b > 1.)) // vérif de la valeur demandée { cout << "\n erreur: le rayon spectral demande n'est pas possible " << "\n il doit etre compris entre 0. et 1. alors que l'on a lu " << rho_b << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; if (b_b == 0.) {// calcul de b_b et omega_b b_b = ((-0.5624 * rho_b + 1.0679) * rho_b - 1.0313) * rho_b + 0.6776 ; omega_b = ((0.2778 * rho_b -1.057) * rho_b + 1.1186) * rho_b + 1.8199 ; } else // cas où b_b est directement lue {omega_b = 2. ; // fixé arbitrairement car on ne le connait pas }; a_a =1./3. - b_b ; break; } case 3: { if (rho_b != 0.4) // vérif de la valeur demandée { cout << "\n erreur: le rayon spectral demande n'est pas possible " << "\n il doit etre egal a 0.4 (valeur par defaut) alors que l'on a lu " << rho_b << "\n AlgoBonelli::lecture_Parametres( ... "; Sortie(1); }; if (b_b == 0.) {// calcul de b_b et omega_b rho_b = 0.4; b_b = 0.332; omega_b = 2.753; } else // cas où b_b est directement lue {omega_b = 2. ; // fixé arbitrairement car on ne le connait pas }; a_a =1./3. - b_b ; break; } }; } else // sinon on met les valeurs par défaut c'est-à-dire E-2C (deux itérations de correction) { b_b=0.322;k_max=2; omega_b=2.171; a_a =1./3. - b_b ; rho_b = 0.6; nb_pt_int_t = 3; pt_seg_temps = new GeomSeg(nb_pt_int_t); }; // on prépare la prochaine lecture si la lecture a été effective et que l'on n'est pas // sur un mot clé if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar))) entreePrinc.NouvelleDonnee(); // ligne suivante // puis appel de la méthode de la classe mère Algori::lecture_Parametres(entreePrinc); }; // création d'un fichier de commande: cas des paramètres spécifiques void AlgoBonelli::Info_commande_parametres(UtilLecture& entreePrinc) { // écriture dans le fichier de commande ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier sort << "\n#-----------------------------------------------------------------------------" << "\n| parametres (falcultatifs ) associes au calcul de dynamique explicite DG |" << "\n| definition des parametres de controle pour Bonelli (Galerkin Discontinu) |" << "\n#-----------------------------------------------------------------------------" << "\n" << "\n PARA_TYPE_DE_CALCUL" << "\n # ..................................................................................." << "\n # / k_max : 2 nombre de boucle de correction (1, 2 ou 3), l'optimun est a priori 2 /" << "\n # / rho_b : 0.6 le rayon spectral de la matrice d'amplification, a la bifurcation /" << "\n # / pour k_max=1 (E-1C) -> rho_b peut appartenir a [0.34,1.] /" << "\n # / pour k_max=2 (E-2C) -> rho_b peut appartenir a [0.0,1.] /" << "\n # / pour k_max=3 (E-3C) -> rho_b = 0.4 (de maniere arbitraire) /" << "\n # / nb_pt_int_t : 3 le nombre de points d'integration pour la quadrature temporelle /" << "\n # / forces internes et externes /" << "\n # / ** parametres facultatifs : (mettre les parametres sur une meme ligne et /" << "\n # / dans l'ordre (meme si certain manque) *** /" << "\n #....................................................................................." << "\n k_max_ 2 rho_b_ 0.4 nb_pt_int_t_ 3 " << "\n # / a titre de test il est egalement possible d'indiquer directement la valeur de b /" << "\n # / au lieu de celle de rho_b, selon la syntaxe b_b_ et une valeur par ex: b_b_ 0.5 /" << "\n # / dans ce cas le pas critique est celui de la dfc /"; sort << "\n" << endl; // appel de la classe mère Algori::Info_com_parametres(entreePrinc); }; //------- 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 AlgoBonelli::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(DYNA_EXP_BONELLI); // 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); distribution_CPU_algo.Passage_Equilibrage_aux_CPU(); paraGlob->Init_tableau(distribution_CPU_algo.Tableau_element_CPU_en_cours() ,distribution_CPU_algo.Tab_indique_CPU_en_cours() ,distribution_CPU_algo.Tableau_noeud_CPU_en_cours() ,distribution_CPU_algo.Tab_indique_noeud_CPU_en_cours()); }; #endif // avant toute chose, au cas où l'algo interviendrait après un autre algo // on inactive tous les ddl existants lesMail->Inactive_ddl(); // on regarde s'il s'agit d'un pb purement non méca, dans ce cas il faut cependant initialiser les positions // à t et tdt pour le calcul de la métrique associée { const list & type_pb = lesMail->Types_de_problemes(); bool purement_non_meca = true; list ::const_iterator il,ilfin=type_pb.end(); for (il=type_pb.begin();il != ilfin; il++) {switch (*il) { case MECA_SOLIDE_DEFORMABLE: case MECA_SOLIDE_INDEFORMABLE: case MECA_FLUIDE: purement_non_meca=false; break; default: break; // sinon on ne fait rien }; }; if (purement_non_meca) // si pas de méca, on initialise les coordonnées à t et tdt avec celles de 0 {lesMail->Init_Xi_t_et_tdt_de_0();} else // sinon a minima on active X1 { lesMail->Active_un_type_ddl_particulier(X1); }; }; // -- 1) on met à jour les pointeurs internes de classes lesMail_ =lesMail; lesRef_ =lesRef; lesCourbes1D_ = lesCourbes1D; lesFonctionsnD_ = lesFonctionsnD; charge_ = charge; lesCondLim_ = lesCondLim; lesContacts_ = lesContacts; // cas du chargement, on verifie egalement la bonne adequation des references charge->Initialise(lesMail,lesRef,pa,*lesCourbes1D,*lesFonctionsnD); // on indique que l'on ne souhaite pas le temps fin stricte // (sinon erreur non gérée après un changement de delta t), que l'on suppose négligeable // après plusieurs incréments charge->Change_temps_fin_non_stricte(1); // dans le cas où l'on calcul des contraintes et/ou déformation et/ou un estimateur d'erreur // à chaque incrément, initialisation tenuXVG.Change_taille(3);tenuXVG(1)=X1;tenuXVG(2)=V1;tenuXVG(3)=GAMMA1; prepa_avec_remont = Algori::InitRemont(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); if ( prepa_avec_remont)// remise enservice des ddl du pab {lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(X1);}; // 01 ---- récup du pas de temps, proposé par l'utilisateur, initialisation et vérif / pas critique this->Gestion_pas_de_temps(lesMail,1,1); // 1 signifie qu'il y a initialisation // 00 ---- on crée les ddl d'accélération et de vitesse non actif mais libres // car les forces intérieures et extérieures sont les entitées duales // des déplacements, qui sont donc les seules grandeurs actives à ce stade lesMail->Plus_Les_ddl_Vitesse( HSLIBRE); lesMail->Plus_Les_ddl_Acceleration( HSLIBRE); // on défini globalement que l'on a une combinaison des ddl X V GAMMA en même temps cas_combi_ddl=1; // mise en place éventuelle du bulk viscosity lesMail->Init_bulk_viscosity(pa.BulkViscosity(),pa.CoefsBulk()); // mise a zero de tous les ddl et creation des tableaux a t+dt // les ddl de position ne sont pas mis a zero ! ils sont initialise // a la position courante lesMail->ZeroDdl(true); // on vérifie que les noeuds sont bien attachés à un élément sinon on met un warning si niveau > 2 if (ParaGlob::NiveauImpression() > 2) lesMail->AffichageNoeudNonReferencer(); // init des ddl avec les conditions initials // les conditions limites initiales de vitesse et d'accélération sont prise en compte // de manière identiques à des ddl quelconques, ce ne sont pas des ddl fixé !! lesCondLim->Initial(lesMail,lesRef,lesCourbes1D,lesFonctionsnD,true,cas_combi_ddl); // mise à jour des différents pointeur d'assemblage et activation des ddl // a) pour les déplacements qui sont à ce stade les seuls grandeurs actives // on définit un nouveau cas d'assemblage pour les Xi // à travers la définition d'une instance de la classe assemblage Ass1 = new Assemblage(lesMail->InitNouveauCasAssemblage(1)); lesMail->MiseAJourPointeurAssemblage(Ass1->Nb_cas_assemb());// mise a jour des pointeurs d'assemblage int nbddl_X = lesMail->NbTotalDdlActifs(X1); // nb total de ddl de déplacement // qui est le même pour les accélérations et les vitesses // b) maintenant le cas des vitesses qui doivent donc être activées // on définit un nouveau cas d'assemblage pour les Vi Ass2= new Assemblage(lesMail->InitNouveauCasAssemblage(1)); lesMail->Inactive_un_type_ddl_particulier(X1); // on inactive les Xi lesMail->Active_un_type_ddl_particulier(V1); // on active les Vi lesMail->MiseAJourPointeurAssemblage(Ass2->Nb_cas_assemb()); // mise a jour des pointeurs d'assemblage // c) idem pour les accélérations // on définit le numéro de second membre en cours // on définit un nouveau cas d'assemblage pour les pour GAMMAi Ass3= new Assemblage(lesMail->InitNouveauCasAssemblage(1)); lesMail->Inactive_un_type_ddl_particulier(V1); // on inactive les Vi lesMail->Active_un_type_ddl_particulier(GAMMA1); // on active les GAMMAi lesMail->MiseAJourPointeurAssemblage(Ass3->Nb_cas_assemb()); // mise a jour des pointeurs d'assemblage // d) activation de tous les ddl, maintenant ils peuvent être les 3 actifs lesMail->Active_un_type_ddl_particulier(X1); lesMail->Active_un_type_ddl_particulier(V1); // en fait ces trois pointeurs d'assemblage ne sont utils que pour la mise en place des conditions // limites // mise à jour du nombre de cas d'assemblage pour les conditions limites // c-a-d le nombre maxi possible (intégrant les autres pb qui sont résolu en // éventuellement) lesCondLim->InitNombreCasAssemblage(lesMail->Nb_total_en_cours_de_cas_Assemblage()); // définition d'un tableau globalisant les numéros d'assemblage de X V gamma t_assemb.Change_taille(3); t_assemb(1)=Ass1->Nb_cas_assemb();t_assemb(2)=Ass2->Nb_cas_assemb();t_assemb(3)=Ass3->Nb_cas_assemb(); // récupération des tableaux d'indices généraux des ddl bloqués, y compris les ddls associés icas = 1; // pour indiquer au module Tableau_indice que l'on travaille avec l'association X V GAMMA lesCondLim->Tableau_indice (lesMail,t_assemb ,lesRef,charge->Temps_courant(),icas); // on définit quatre tableaux qui serviront à stocker transitoirement les X V GAMMA correspondant au ddl imposés int ttsi = li_gene_asso.size(); X_Bl.Change_taille(ttsi),V_Bl.Change_taille(ttsi),G_Bl.Change_taille(ttsi); // def vecteurs globaux vglobin.Change_taille(nbddl_X); // puissance interne vglobex.Change_taille(nbddl_X); // puissance externe vglobaal.Change_taille(nbddl_X,0.); // puissance totale // même si le contact n'est pas encore actif, il faut prévoir qu'il le deviendra peut-être ! if (lesMail->NbEsclave() != 0) vcontact.Change_taille(nbddl_X); // puissance de contact // 04 ---- 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);X_tdt.Change_taille(nbddl_X); delta_X.Change_taille(nbddl_X); var_delta_X.Change_taille(nbddl_X); // vecteur qui globalise toutes les vitesses de l'ensemble des noeuds vitesse_t.Change_taille(nbddl_X);vitesse_tplus.Change_taille(nbddl_X); vitesse_tdt.Change_taille(nbddl_X); // vecteur qui globalise toutes les accélérations acceleration_t.Change_taille(nbddl_X);acceleration_tdt.Change_taille(nbddl_X) ; // calcul des énergies if (pa.Amort_visco_artificielle()) // dans le cas d'un amortissement artificiel forces_vis_num.Change_taille(nbddl_X,0.); E_cin_tdt = 0.; E_int_t = 0.; E_int_tdt = 0.; // init des différentes énergies E_ext_t = 0.; E_ext_tdt = 0.; bilan_E = 0.; // " et du bilan F_int_t.Change_taille(nbddl_X); F_ext_t.Change_taille(nbddl_X); // forces généralisées int et ext au pas précédent F_int_tdt.Change_taille(nbddl_X); F_ext_tdt.Change_taille(nbddl_X); // forces généralisées int et ext au pas actuel residu_final.Change_taille(nbddl_X); // pour la sauvegarde du résidu pour le post-traitement // initialisation du compteur d'increments de charge 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) { // definition des elements de frontiere, ces elements sont utilises pour le contact // int cal_front = lesMail->CreeElemFront(); 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 brestart=false; // booleen qui indique si l'on est en restart ou pas if (this->Num_restart() != 0) { int cas = 2; // ouverture de base info entreePrinc->Ouverture_base_info("lecture"); this->Lecture_base_info(cas ,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage ,charge,lesCondLim,lesContacts,resultats,(this->Num_restart())); icharge = this->Num_restart();//+1; // récup du pas de temps, proposé par l'utilisateur, initialisation et vérif / pas critique this->Gestion_pas_de_temps(lesMail,2,1); // 2 signifie cas courant brestart = true; // on oblige les ddls Vi GAMMAi a avoir le même statut que celui des Xi // comme les conditions limites cinématiques peuvent être différentes en restart // par rapport à celles sauvegardées, on commence par libérer toutes les CL imposées éventuelles lesMail->Libere_Ddl_representatifs_des_physiques(LIBRE); lesMail->ChangeStatut(cas_combi_ddl,LIBRE); // dans le cas d'un calcul axisymétrique on bloque le ddl 3 if (ParaGlob::AxiSymetrie()) lesMail->Inactive_un_ddl_particulier(X3); // on valide l'activité des conditions limites et condition linéaires, pour le temps initial // en conformité avec les conditions lues (qui peuvent éventuellement changé / aux calcul qui a donné le .BI) lesCondLim->Validation_blocage (lesRef,charge->Temps_courant()); li_gene_asso = lesCondLim->Tableau_indice (lesMail,t_assemb,lesRef,charge->Temps_courant(),icas); int ttsi = li_gene_asso.size(); X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi); // mise à jour pour le contact s'il y du contact présumé if (pa.ContactType()) lesMail->Mise_a_jour_boite_encombrement_elem_front(TEMPS_t); } // vérif de cohérence pour le contact if ((pa.ContactType()) && (lesMail->NbEsclave() == 0)) // là pb {cout << "\n *** erreur: il n'y a pas de maillage disponible pour le contact " << " la definition d'un type contact possible est donc incoherente " << " revoir la mise en donnees !! "<< flush; Sortie(1); }; // on regarde s'il y a besoin de sauvegarde if (this->Active_sauvegarde() && (ParaGlob::param->TypeCalcul_maitre() == this->typeCalcul) ) { // si le fichier base_info n'est pas en service on l'ouvre entreePrinc->Ouverture_base_info("ecriture"); // dans le cas ou se n'est pas un restart on sauvegarde l'incrément actuel // c'est-à-dire le premier incrément // après s'être positionné au début du fichier if (this->Num_restart() == 0) { (entreePrinc->Sort_BI())->seekp(0); int cas = 1; paraGlob->Ecriture_base_info(*(entreePrinc->Sort_BI()),cas); this->Ecriture_base_info (cas,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage ,charge,lesCondLim,lesContacts,resultats,OrdreVisu::INCRE_0); } else { // sinon on se place dans le fichier à la position du restart // debut_increment a été définit dans algori (classe mère) (entreePrinc->Sort_BI())->seekp(debut_increment); } } //--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); }; // choix de la matrice de masse, qui est en fait celle qui correspond au ddl Xi // ici le numéro d'assemblage est celui de X car on projette bien sur des vitesses virtuelles c-a-d ddl X*. mat_masse = Choix_matrice_masse(nbddl_X,mat_masse,lesMail,lesRef ,Ass1->Nb_cas_assemb(),lesContacts,lesCondLim); mat_masse_sauve = Choix_matrice_masse(nbddl_X,mat_masse_sauve,lesMail,lesRef ,Ass1->Nb_cas_assemb(),lesContacts,lesCondLim); // choix de la résolution if (mat_masse->Type_matrice() == DIAGONALE) // dans le cas d'une matrice diagonale on force la résolution directe quelque soit l'entrée mat_masse->Change_Choix_resolution(DIRECT_DIAGONAL,pa.Type_preconditionnement()); else mat_masse->Change_Choix_resolution(pa.Type_resolution(),pa.Type_preconditionnement()); // on signale que l'on utilise un comportement matériel normal lesLoisDeComp->Loi_simplifie(false); // on calcul la matrice de masse qui est supposée identique dans le temps // c'est-à-dire que l'on considère que la masse volumique est constante Cal_matrice_masse(lesMail,*Ass1,*mat_masse,diversStockage,lesRef,X1,lesFonctionsnD); // on sauvegarde la matrice masse (*mat_masse_sauve) = (*mat_masse); // dans le cas où l'on utilise de l'amortissement numérique // if (pa.Amort_visco_artificielle()) // { bool initial = true; // def de la matrice (place et valeurs) // mat_C_pt = Cal_mat_visqueux_num_expli(*mat_masse,mat_C_pt,delta_X,initial,vitesse_tdt); // forces_vis_num.Change_taille(nbddl_X); // }; // mise en place des conditions limites // ---- initialisation des sauvegardes sur matrice et second membre // ce qui ne correspond à rien ici normalement lesCondLim->InitSauve(Ass3->Nb_cas_assemb()); // lesCondLim->ImposeConLimtdt(lesMail,lesRef,*mat_masse,vglobaal,Ass3->Nb_cas_assemb() ,cas_combi_ddl,vglob_stat); // puis on prépare (si besoin est en fonction du type de matrice) la résolution mat_masse->Preparation_resol(); type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul // --- cas des vecteurs --- // les différents vecteurs de ddl intermédiaires discontinues sont initialisés à 0 q_0.Change_taille(nbddl_X);p_0.Change_taille(nbddl_X); q_1.Change_taille(nbddl_X);p_1.Change_taille(nbddl_X); q_2.Change_taille(nbddl_X);p_2.Change_taille(nbddl_X); // on initialise q_0 à la valeur de X_t lesMail_->Vect_loc_vers_glob(TEMPS_t,X1,q_0,X1); lesMail_->Vect_loc_vers_glob(TEMPS_t,V1,vitesse_t,V1); // on initialise de même la quantité de mouvement //// mat_masse->Prod_mat_vec ( vitesse_t, p_0); mat_masse_sauve->Prod_mat_vec ( vitesse_t, p_0); // on dimensionne les vecteurs de travail, et les vecteurs intermédiaires pPoint_i.Change_taille(nbddl_X); P_i_1.Change_taille(nbddl_X);P_i_2.Change_taille(nbddl_X); P_q1_k.Change_taille(nbddl_X);P_q2_k.Change_taille(nbddl_X); r_1_k.Change_taille(nbddl_X);r_2_k.Change_taille(nbddl_X); vec_travail1.Change_taille(nbddl_X); vec_travail2.Change_taille(nbddl_X); dernier_phi.Change_taille(2); // 2 noeuds temporels if (amortissement_cinetique) Algori::InitialiseAmortissementCinetique(); // initialisation des compteurs pour l'amortissement au cas ou tempsInitialisation.Arret_du_comptage(); // temps cpu }; // mise à jour void AlgoBonelli::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(DYNA_EXP_BONELLI); // transfert info // activation des ddl lesMail->Inactive_ddl(); // on commence par inactiver tous les ddl lesMail->Active_un_type_ddl_particulier(X1); // puis on active les ddl qu'ils faut ici lesMail->Active_un_type_ddl_particulier(V1); // on active les Vi lesMail->Active_un_type_ddl_particulier(GAMMA1); // on active les GAMMAi // 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 }; // Résolution du problème mécanique en explicite dynamique // 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 AlgoBonelli::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(DYNA_EXP_BONELLI); // transfert info // init var glob: du num d'itération. De manière arbitraire, en dynamique explicite Transfert_ParaGlob_COMPTEUR_ITERATION_ALGO_GLOBAL(1); // on a toujours une seule itération OrdreVisu::EnumTypeIncre type_incre = OrdreVisu::PREMIER_INCRE; // pour la visualisation au fil du calcul // préparation pour les aspects validation du calcul et sortie contrôlée des incréments int validation_calcul = 1; // init : par défaut la validation est effective si le calcul converge int sortie_boucle_controler_par_fctnD = 0; // init : par défaut la sortie n'est pas contrôler // boucle sur les increments de charge qui sont également les incréments de temps // tant que la fin du chargement n'est pas atteinte // dans le cas du premier chargement on calcul de toute manière, ce qui permet // de calculer meme si l'utilisateur indique un increment de charge supérieur // au temps final const double untiers = 1./3.; cout << "\n a_a=" << a_a << " b_b= " << b_b; // --- récupération des ddl position, vitesse et accélération initial lesMail_->Vect_loc_vers_glob(TEMPS_t,X1,X_t,X1); lesMail_->Vect_loc_vers_glob(TEMPS_t,V1,vitesse_t,V1); lesMail_->Vect_loc_vers_glob(TEMPS_t,GAMMA1,acceleration_t,GAMMA1); icharge++; // on incrémente le chargement -> donne le num d'incr du prochain incr chargé double max_delta_X=0.; // le maxi du delta X double max_var_delta_X=0.; // idem d'une itération à l'autre int nb_step=1; // a priori bool arret=false; // booleen pour arrêter indépendamment de la charge 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é && !arret) { // renseigne les variables définies par l'utilisateur via les valeurs déjà calculées par Herezh Algori::Passage_de_grandeurs_globales_vers_noeuds_pour_variables_globales(lesMail,varExpor,Ass1->Nb_cas_assemb(),*lesRef); varExpor->RenseigneVarUtilisateur(*lesMail,*lesRef); lesMail->CalStatistique(); // calcul éventuel de statistiques // 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); // gestion du pas de temps, vérif du delta_t / pas critique this->Gestion_pas_de_temps(lesMail,2,nb_step); // 2 signifie cas courant // init des temps début et fin, permet ainsi de les sauvegarder, car le temps va évoluer pendant l'intégration double tdeb = pa.Variables_de_temps().TempsCourant(); double tfi = tdeb + pa.Deltat(); // affichage de l'increment de charge if ( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde)) {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 // ----- calcul des dérivées temporelles des quantités de mouvement au temps ti^{-} // on considère que X_tdt au niveau des noeuds est celui de ti^{-}, dernière valeur calculée // mise en place du chargement impose, c-a-d calcul de la puissance externe vglobin.Zero(); vglobex.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 // 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 (*Ass1,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { Change_PhaseDeConvergence(-10);break;}; // appel du calcul de la puissance interne et des énergies // dans le cas d'un calcul inexploitable arrêt de la boucle if (!SecondMembreEnerg(lesMail,*Ass1,vglobin)) break; // calcul des maxi des puissances internes maxPuissInt = vglobin.Max_val_abs(); F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures 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 ; // pPoint_i = puissance externe - puissance interne pPoint_i= (vglobaal); // ----- calcul de la prédiction avec les CL de déplacement au point d'intégration temporelle // mise en place des conditions limites et mise à jour de la matrice de masse si nécessaire const Vecteur phii1_avec_rien; // phii qui ne sert pas dans la phase de prédiction charge_->Avance(); // avancement de la charge et donc du temps courant AvanceDDL_avec_CL(phii1_avec_rien,PREDICTION_bonelli); bool retour_exacte=true; // pour ne pas comptabiliser les appels intermédiaires à Avance() charge_->Precedant(retour_exacte); // retour au temps initial // ----- Phase de correction int k_k = 0; // cout << "\n kk=0 "; do {// ----- calcul des vecteurs P_i_1, P_i_2, P_q1_k, P_q2_k P_i_1.Zero(); P_i_2.Zero(); P_q1_k.Zero(); P_q2_k.Zero(); // on utilise une quadrature de gauss for (int i_pt_integ = 1;i_pt_integ <= nb_pt_int_t; i_pt_integ++ ) { // calcul du temps correspondant au pt d'integ Vecteur const & phii= pt_seg_temps->ElemGeomC0::Phi((int)i_pt_integ); dernier_phi = phii; // sauvegarde, pour CalEnergieAffichageBonelli() double phii_1 = phii(1); double phii_2 = phii(2); double temps = tdeb * phii_1 + tfi * phii_2; // temps courant d'intégration // on valide le pas de temps effectivement fait Modif_transi_pas_de_temps(temps-tdeb); charge_->Avance(); // avancement de la charge et donc du temps courant // --- quadrature // mise en place des conditions limites sur les ddl stockés aux noeuds: positions et vitesses // mise à jour des conditions limites sur la matrice de masse si nécessaire AvanceDDL_avec_CL(phii,INTEGRATION_bonelli); // -- cas P_i_1 et P_i_2 : formule un peu différente de l'article // mise en place du chargement impose, c-a-d calcul de la puissance externe 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 (*Ass1,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { Change_PhaseDeConvergence(-10);break;}; F_ext_tdt = vglobex; if (pa.ContactType()) vcontact.Zero(); if (pa.ContactType()) vglobex += vcontact; maxPuissExt = MaX(maxPuissExt,F_ext_tdt.Max_val_abs()); // integ double poids = pt_seg_temps->ElemGeomC0::Wi((int)i_pt_integ); P_i_1 += (phii_1 * deltatSurDeux_total * poids) * F_ext_tdt ; P_i_2 += (phii_2 * deltatSurDeux_total * poids) * F_ext_tdt ; // -- cas P_q1_k et P_q2_k // appel du calcul de la puissance interne et des énergies au niveau des éléments // dans le cas d'un calcul inexploitable on enregistre l'erreur vglobin.Zero(); if (!SecondMembreEnerg(lesMail_,*Ass1,vglobin)) {arret=true; erreurSecondMembre = true; cout << "\n erreur dans le calcul du second membre ! "; break; }; F_int_tdt = vglobin; // sauvegarde des forces généralisées intérieures // second membre total (vglobaal) = vglobex ; // dans mon cas j'ajoute alors que dans la théorie de bonelli on retranche // il y a bien donc une différence de signe entre bonelli et moi pour F_int et F_ext vglobaal += vglobin ; maxPuissInt = MaX(maxPuissInt,F_int_tdt.Max_val_abs()); // integ P_q1_k += (phii_1 * deltatSurDeux_total * poids) * F_int_tdt; P_q2_k += (phii_2 * deltatSurDeux_total * poids) * F_int_tdt; // on revient aux conditions initiales de début d'incrément concernant le temps charge_->Precedant(retour_exacte); }; if (arret) break; // cas d'une erreur dans le calcul du second membre // vec_travail2 = unsurdeltat_total * (matrice_mas * q_0); //// mat_masse->Prod_mat_vec ( q_0, vec_travail2); vec_travail2 *= unsurdeltat_total; mat_masse_sauve->Prod_mat_vec ( q_0, vec_travail2); vec_travail2 *= unsurdeltat_total; // --- calcul des vecteurs résidus // formules différentes de l'article // r_1_k = unsurdeltat_total * M * q_2 + P_q1_k - P_i_1 - p_0 - unsurdeltat_total * M * q_0; // r_2_k = unsurdeltat_total * M * q_1 - 1/3 * P_q2_k - 1/3 * P_i_1 + 1/3 * unsurdeltat_total * M * q_0; // r_1_k = unsurdeltat_total * mat_masse->Prod_mat_vec(q_2,vec_travail1) + P_q1_k - P_i_1 - p_0 - vec_travail2; // r_2_k = unsurdeltat_total * mat_masse->Prod_mat_vec(q_1,vec_travail1) - untiers * (P_q2_k - P_i_2) - vec_travail2 ; //// r_1_k = unsurdeltat_total * mat_masse->Prod_mat_vec(q_2,vec_travail1) - P_q1_k - P_i_1 - p_0 - vec_travail2; //// r_2_k = unsurdeltat_total * mat_masse->Prod_mat_vec(q_1,vec_travail1) + untiers * (P_q2_k + P_i_2) - vec_travail2 ; r_1_k = unsurdeltat_total * mat_masse_sauve->Prod_mat_vec(q_2,vec_travail1) - P_q1_k - P_i_1 - p_0 - vec_travail2; r_2_k = unsurdeltat_total * mat_masse_sauve->Prod_mat_vec(q_1,vec_travail1) + untiers * (P_q2_k + P_i_2) - vec_travail2 ; // cout << "\n (fint -fex)1 " << (P_q1_k - P_i_1 - p_0 - vec_travail2).Norme() // << " (fint -fex)2 " << (- untiers * (P_q2_k - P_i_2) - vec_travail2).Norme(); // --- calcul des nouvelles positions AvanceDDL_avec_CL(phii1_avec_rien,CORRECTION_bonelli); // --- incrémente la boucle k_k ++; } while (k_k < k_max); // } while (k_k < 5); if (arret && erreurSecondMembre) break; // cas d'une erreur dans le calcul du second membre // --- calcul des réactions au dernier point d'intégration temporelle, c-a-d à l'aide // des derniers efforts internes et externes calculés (et mémorisés) // initialisation des sauvegardes sur second membre (uniquement pour les gammai) // car ce sont les ddl de l'équation d'équilibre instantanée lesCondLim->InitSauve(Ass3->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,Ass3->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 (vglobin = vglobal : somme des forces généralisées) // lesCondLim->ReacApresCHrepere(vglobin,lesMail,lesRef,Ass3->Nb_cas_assemb(),cas_combi_ddl); // mise en place des conditions limites sur les Gammai -> calcul et sauvegarde des réactions lesCondLim->ImposeConLimtdt(lesMail,lesRef,(vglobaal),Ass3->Nb_cas_assemb() ,cas_combi_ddl,vglob_stat); // calcul du maxi des reactions maxReaction = lesCondLim->MaxEffort(inReaction,Ass3->Nb_cas_assemb()); // sortie d'info sur l'increment concernant les réactions if ( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde)) InfoIncrementReac(lesMail,inReaction,maxReaction,Ass3->Nb_cas_assemb()); // --- calcul et affichage éventuel du maxi de variation de ddl // contrairement aux autres algos dynamique, on affiche la variation maxi de x Algori::Cal_Transfert_delta_et_var_X(max_delta_X,max_var_delta_X); maxDeltaDdl = delta_X.Max_val_abs(inSol); // sortie d'info sur l'increment concernant les variations de ddl if ( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde) &&(ParaGlob::NiveauImpression() > 1)) InfoIncrementDdl(lesMail,inSol,maxDeltaDdl,Ass3->Nb_cas_assemb()); // --- validation du pas de temps effectivement effectué Modif_transi_pas_de_temps(tfi-tdeb); charge_->Avance(); // avancement de la charge et donc du temps courant // --- calcul des ddl finaux // et mise en place de: X_td, vitesse_tdt et acceleration_tdt au niveau des noeuds AvanceDDL_avec_CL(phii1_avec_rien,FIN_DELTA_T_bonelli); // --- calcul de la vitesse à tplus ainsi que de la quantité de mouvement final à tdt^{-} vitesse_tplus = unsurdeltat_total * (3. * q_1 + q_2 - 4. * q_0); // sert dans CalEnergieAffichageBonelli() //// mat_masse->Prod_mat_vec(vitesse_tdt,p_2); //vitesse_tdt = M^{-1} * p_2 mat_masse_sauve->Prod_mat_vec(vitesse_tdt,p_2); //vitesse_tdt = M^{-1} * p_2 // --- préparation des grandeurs pour le pas de temps suivant p_0=p_2; q_0 = q_2; // calcul des énergies et affichage des balances CalEnergieAffichageBonelli(1.,icharge); if (icharge==1)// dans le cas du premier incrément on considère que la balance vaut l'énergie // cinétique initiale, car vu que l'on ne met pas de CL à t=0, E_cin_0 est difficile à calculer {E_cin_0 = E_cin_tdt - bilan_E + E_int_tdt - E_ext_tdt; }; // calcul éventuelle de l'amortissement cinétique // int relax_vit_acce = AmortissementCinetique(delta_X,1.,X_tdt,*mat_masse_sauve,icharge,vitesse_tdt); // s'il y a amortissement cinétique il faut re-updater les vitesses // if (Abs(relax_vit_acce) == 1) {lesMail->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1);}; // if (relax_vit_acce == -1) // {arret=true; }; // arrêt du calcul car deltaddl satisfait le critère de relaxation cinétique // 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); }; // 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(); X_t = X_tdt; vitesse_t=vitesse_tdt; acceleration_t=acceleration_tdt; // 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()); // sauvegarde de l'incrément si nécessaire tempsCalEquilibre.Arret_du_comptage(); // pour enregistrer Ecriture_base_info(2,lesMail,lesRef,lesCourbes1D,lesFonctionsnD ,lesLoisDeComp,diversStockage,charge,lesCondLim,lesContacts ,resultats,type_incre,icharge); // enregistrement du num d'incrément et du temps correspondant list_incre_temps_calculer.push_front(Entier_et_Double(icharge,pa.Variables_de_temps().TempsCourant())); // visualisation éventuelle au fil du calcul VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD ,lesLoisDeComp,diversStockage,charge ,lesCondLim,lesContacts,resultats,type_incre,icharge); tempsCalEquilibre.Mise_en_route_du_comptage(); // on remet en route le compteur }; // -- fin du test: if (validation_calcul) //s'il y a remonté des sigma et/ou def aux noeuds et/ou calcul d'erreur bool change =false; // calcul que s'il y a eu initialisation if(prepa_avec_remont) {change = Algori::CalculRemont(lesMail,type_incre,icharge);}; if (change) // dans le cas d'une remonté il faut réactiver les bon ddls {lesMail->Inactive_ddl(); lesMail->Active_un_type_ddl_particulier(tenuXVG);}; brestart = false; // dans le cas où l'on était en restart, on passe l'indicateur en cas courant // test de fin de calcul effectue dans charge via : charge->Fin() if (validation_calcul) {icharge++; Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge); }; // --cas particulier où la sortie de la boucle est pilotée // ici, cas d'un calcul explicite au sens classique, il n'y a pas de notion de convergence // celle-ci est toujours considérée comme effective if (sortie_boucle_controler_par_fctnD) break; } // on remet à jour le nombre d'incréments qui ont été effectués: if (validation_calcul) {icharge--; Transfert_ParaGlob_COMPTEUR_INCREMENT_CHARGE_ALGO_GLOBAL(icharge); } 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);} ; tempsCalEquilibre.Arret_du_comptage(); // temps cpu }; // dernière passe void AlgoBonelli::FinCalcul(ParaGlob * paraGlob,LesMaillages * lesMail, LesReferences* lesRef,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD ,VariablesExporter* varExpor ,LesLoisDeComp* lesLoisDeComp,DiversStockage* diversStockage, Charge* charge,LesCondLim* lesCondLim,LesContacts* lesContacts ,Resultats* resultats) { // passage finale dans le cas d'une visualisation au fil du calcul Transfert_ParaGlob_ALGO_GLOBAL_ACTUEL(DYNA_EXP_BONELLI); // transfert info type_incre = OrdreVisu::DERNIER_INCRE; VisuAuFilDuCalcul(paraGlob,lesMail,lesRef,lesCourbes1D,lesFonctionsnD,lesLoisDeComp,diversStockage,charge ,lesCondLim,lesContacts,resultats,type_incre,icharge); // sauvegarde de l'état finale 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 des ddl avec prise en comptes des conditions limites suivant une technique // s'appuyant sur une différence finie décentrée à droite // utilise les vecteurs globaux : q_2, q_1, q_0 // --> mise à jour des ddl au niveau globaux sur les X, V, gamma puis au niveau des noeuds // --> ou mise à jour des composantes adoc des vecteurs globaux q_2, q_1, q_0, selon "phasage" // phii : interpolation en fonction du temps, ne sert que pour phasage = INTEGRATION_bonelli // phasage = // PREDICTION_bonelli: phase de prédiction, on n'utilise "pas" l'interpolation en temps (phii) // --> calcul de q_1 et q_2 avec les conditions limites // INTEGRATION_bonelli: phase d'intégration, "on utilise l'interpolation en temps" // --> calcul de X_tdt et vitesse_tdt // CORRECTION_bonelli: phase de correction, on n'utilise "pas" l'interpolation en temps (phii) // --> calcul de q_1 et q_2 avec les conditions limites // FIN_DELTA_T_bonelli: phase final, on n'utilise "pas" l'interpolation en temps (phii) // --> calcul de X_tdt et vitesse_tdt pour le temps final void AlgoBonelli::AvanceDDL_avec_CL(const Vecteur & phii,enuTypePhase phasage) { // --- imposition des ddls bloqués // initialisation des coordonnees et des ddl a tdt en fonctions des // ddl imposes et de l'increment du chargement // on regarde s'il y a changement de statut de certains ddl ==> modif de tableau d'indiçage bool change_statut = false; // init des changements de statut lesCondLim_->MiseAJour_tdt (pa.Multiplicateur(),lesMail_,charge_->Increment_de_Temps(),lesRef_,charge_->Temps_courant() ,lesCourbes1D_,lesFonctionsnD_,charge_->MultCharge(),change_statut,cas_combi_ddl); // dans le cas ou il y a changement de statut il faut remettre à jour // les conditions limites sur la matrice masse if (change_statut) {li_gene_asso = lesCondLim_->Tableau_indice (lesMail_,t_assemb ,lesRef_,charge_->Temps_courant(),icas); int ttsi = li_gene_asso.size(); X_Bl.Change_taille(ttsi);V_Bl.Change_taille(ttsi);G_Bl.Change_taille(ttsi); // récupération de la matrice masse sans conditions limites (*mat_masse) = (*mat_masse_sauve); // normalement sur la matrice visqueuse il n'y a rien n'a faire // if (pa.Amort_visco_artificielle()) // initialisation de la matrice visqueuse // { bool initial = false; // Cal_mat_visqueux_num_expli(matrice_mas,mat_C_pt,delta_X,initial,vitesse_tdt); // } // mise en place des conditions limites // ---- initialisation des sauvegardes sur matrice et second membre // ce qui ne correspond à rien ici normalement lesCondLim_->InitSauve(Ass3->Nb_cas_assemb()); lesCondLim_->ImposeConLimtdt(lesMail_,lesRef_,*mat_masse,vglobaal ,Ass3->Nb_cas_assemb(),cas_combi_ddl,vglob_stat); // puis on prépare (si besoin est en fonction du type de matrice) la résolution mat_masse->Preparation_resol(); } // --- récupération (initialisation) des ddl position, vitesse et accélération // récupération au niveau global des ddl locaux avec conditions limite à tdt // pour le vecteur accélération, seules les ddl avec CL sont différents de la précédente // récupération lesMail_->Vect_loc_vers_glob(TEMPS_tdt,X1,X_tdt,X1); lesMail_->Vect_loc_vers_glob(TEMPS_tdt,V1,vitesse_tdt,V1); lesMail_->Vect_loc_vers_glob(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1); // maintenant on met les conditions limites sur les ddls bloqués secondaires c-a-d associés // aux ddl bloqués par l'utilisateur, leur calcul dépend de l'algorithme d'où un calcul global list ::iterator ie,iefin=li_gene_asso.end();; // def d'un iterator adoc int ih=1; // indice for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++) // comme les valeurs des X V Gamma vont être écrasé par le calcul global, on utilise // des conteneurs intermédiaires {//trois cas LesCondLim::Gene_asso & s = (*ie); // pour simplifier int ix=s.pointe(1); // début des Xi int iv=s.pointe(2); // début des Vi int ig=s.pointe(3); // début des gammai // on utilise le schéma des différences finis décentré à droite // pour calculer les valeurs des ddl dans le cas de ddl bloqué if (PremierDdlFamille(s.ty_prin) == X1) // cas ou les Xi sont imposés, on calcul Vi et Gammai { X_Bl(ih) = X_tdt(ix); V_Bl(ih) = (X_tdt(ix) - X_t(ix))*unsurdeltat ; G_Bl(ih)= (V_Bl(ih)-vitesse_t(iv))*unsurdeltat ; } else if (PremierDdlFamille(s.ty_prin) == V1) // cas ou les Vi sont imposés, calcul des Xi et Gammai { V_Bl(ih) = vitesse_tdt(iv); G_Bl(ih) = (vitesse_tdt(iv)-vitesse_t(iv))*unsurdeltat ; X_Bl(ih) = X_t(ix) + delta_t * vitesse_tdt(iv); } else if (PremierDdlFamille(s.ty_prin) == GAMMA1) // cas ou les gammai sont imposés, calcul des Vi et Xi { G_Bl(ih) = acceleration_tdt(ig); V_Bl(ih) = vitesse_t(iv) + delta_t * acceleration_t(iv); X_Bl(ih) = X_t(ix) + delta_t * vitesse_t(iv) + deltat2 * acceleration_t(ig); } acceleration_t(ig) = G_Bl(ih); // pour le cas ou il y a relachement des conditions limites // au prochain pas de temps }; // ---- choix entre les différentes phases switch (phasage) {case PREDICTION_bonelli: {// ----- calcul de la prédiction de déplacement au point d'intégration temporelle tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu mat_masse->Simple_Resol_systID_2 (pPoint_i,vec_travail1); // M^{-1} * pPoint_i tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu // q_1 = q_0 + (a_a * delta2_total) * M^{-1} * pPoint_i q_1 = q_0 + (a_a * deltat2_total) * vec_travail1; // q_2 = q_0 + deltat_total * M^{-1} * p_i + b_b * deltat2_total * M^{-1} * pPoint_i tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu mat_masse->Simple_Resol_systID_2 (p_0,vec_travail2); // M^{-1} * p_i , (p_i = p_0) tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu q_2 = q_0 + delta_t_total * vec_travail2 + (b_b * deltat2_total) * vec_travail1; // -- maintenant on met réellement en place les CL a partir de la sauvegarde // on considère que les X_t ont les bonnes conditions limites for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++) {LesCondLim::Gene_asso & s = (*ie); // pour simplifier int ix=s.pointe(1); // début des Xi // int iv=s.pointe(2); // début des Vi // int ig=s.pointe(3); // début des gammai q_2(ix) = X_Bl(ih); q_1(ix) = X_t(ix); }; break; } case INTEGRATION_bonelli: {// -- calcul du champ de position à t+dt X_tdt = q_1 * phii(1) + q_2 * phii(2); // calcul des coordonnées au point d'integ en temps // -- calcul du champ de vitesse vitesse_tdt = unsurdeltat_total *( (3. * (phii(1) - phii(2))) * q_1 + (phii(1) + phii(2)) * q_2 + (2. * phii(2) - 4. * phii(1)) * q_0); // -- maintenant on met réellement en place les CL a partir de la sauvegarde for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++) {LesCondLim::Gene_asso & s = (*ie); // pour simplifier int ix=s.pointe(1); // début des Xi int iv=s.pointe(2); // début des Vi int ig=s.pointe(3); // début des gammai X_tdt(ix) = X_Bl(ih); vitesse_tdt(iv) = V_Bl(ih); acceleration_tdt(ig) = G_Bl(ih); }; // -- passage des valeurs calculées aux niveaux des maillages lesMail_->Vect_glob_vers_local(TEMPS_tdt,X1,X_tdt,X1); lesMail_->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1); lesMail_->Vect_glob_vers_local(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1); break; } case CORRECTION_bonelli: {// ----- calcul de la correction de déplacement au point d'intégration temporelle tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu q_1 -= delta_t_total * mat_masse->Simple_Resol_systID_2 (r_2_k,vec_travail1); //delta_t* M^{-1} * r_2_k q_2 -= delta_t_total * mat_masse->Simple_Resol_systID_2 (r_1_k,vec_travail1); //delta_t* M^{-1} * r_1_k tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu // Vecteur toto1 = delta_t_total * mat_masse->Simple_Resol_systID_2 (r_2_k,vec_travail1); // Vecteur toto2 = delta_t_total * mat_masse->Simple_Resol_systID_2 (r_1_k,vec_travail1); // cout << "\n r_1_k * q2= " << r_1_k * q_1 << " r_2_k * q1= " << r_2_k * q_2 // << " || delta q1 || " << (toto1).Norme()/q_1.Norme() // << " || delta q2 || " << (toto2).Norme()/q_2.Norme(); // -- maintenant on met réellement en place les CL a partir de la sauvegarde // on considère que les X_t ont les bonnes conditions limites for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++) {LesCondLim::Gene_asso & s = (*ie); // pour simplifier int ix=s.pointe(1); // début des Xi // int iv=s.pointe(2); // début des Vi // int ig=s.pointe(3); // début des gammai q_2(ix) = X_Bl(ih); q_1(ix) = X_t(ix); }; break; } case FIN_DELTA_T_bonelli: {// -- calcul du champ de position à t+dt X_tdt = q_2; vitesse_tdt = unsurdeltat_total * (-3. * q_1 + q_2 + 2. * q_0); // calcul de l'accélération du dernier point d'intégration = M^{-1} * (fex-fint) // stocker à tdt pour simplifier, mais correspond en fait au dernier point d'integ !!!!! tempsResolSystemLineaire.Mise_en_route_du_comptage(); // temps cpu mat_masse->Simple_Resol_systID_2 ((vglobaal),acceleration_tdt); tempsResolSystemLineaire.Arret_du_comptage(); // temps cpu // -- maintenant on met réellement en place les CL a partir de la sauvegarde for(ie=li_gene_asso.begin(),ih=1;ie!=iefin;ie++,ih++) {LesCondLim::Gene_asso & s = (*ie); // pour simplifier int ix=s.pointe(1); // début des Xi int iv=s.pointe(2); // début des Vi int ig=s.pointe(3); // début des gammai X_tdt(ix) = X_Bl(ih); vitesse_tdt(iv) = V_Bl(ih); acceleration_tdt(ig) = G_Bl(ih); }; // -- passage des valeurs calculées aux niveaux des maillages lesMail_->Vect_glob_vers_local(TEMPS_tdt,X1,X_tdt,X1); lesMail_->Vect_glob_vers_local(TEMPS_tdt,V1,vitesse_tdt,V1); lesMail_->Vect_glob_vers_local(TEMPS_tdt,GAMMA1,acceleration_tdt,GAMMA1); break; } }; }; // calcul une approximation des différences énergie en jeux dans le cas Bonelli // affichage éventuelle des ces énergies et du bilan // V : ddl de vitesse // coef_mass : en fait il faut utiliser 1/coef_mass * mat_mass pour la matrice masse, ceci due à la spécificité de l'algo // les différentes énergie et efforts généralisées sont des variables internes à l'algo // en sortie: énergie cinétique : E_cin_tdt, énergie interne : E_int_tdt, énergie externe = E_ext_tdt, bilan : bilan_E // idem avec les puissances // énergie visqueuse due aux forces visqueuses numériques // icharge : compteur d'increment // brestart : booleen qui indique si l'on est en restart ou pas void AlgoBonelli::CalEnergieAffichageBonelli(const double& coef_mass,int icharge) { // -- le calcul est conditionnelle if (icharge >= pa.NbIncrCalEnergie()) { // --- cas des énergies ------ // initialisation Vecteur & v_int = vec_travail1; v_int.Change_taille(vitesse_tdt.Taille()); v_int.Zero(); // calcul de l'énergie cinétique E_cin_tdt = (0.5/coef_mass) * (vitesse_tdt * (mat_masse_sauve->Prod_vec_mat(vitesse_tdt,v_int))); // v_int contient les quantités de mouvement locales à chaque ddl // d'où calcul de la quantité de mouvement globale q_mov_tdt = v_int.Somme(); // calcul de l'énergie interne dépensée E_int_tdt = E_int_t - (P_q1_k * vitesse_t + P_q2_k * vitesse_tdt); // calcul de l'énergie externe dépensée E_ext_tdt = E_ext_t + (P_i_1 * vitesse_t + P_i_2 * vitesse_tdt); // bilan des énergies (on retire l'énergie cinétique initiale si elle exite) bilan_E = E_cin_tdt - E_cin_0 + E_int_tdt - E_ext_tdt; // --- cas des puissances ------ // calcul de la puissance d'accélération // en fait ici correspond au dernier point d'intégration !!!! v_int.Zero(); P_acc_tdt = (1./coef_mass) * (vitesse_tdt * (mat_masse_sauve->Prod_vec_mat(acceleration_tdt,v_int))); // calcul de la puissance interne au dernier point d'integ Vecteur& vitesse = vec_travail1; vitesse = dernier_phi(1) * vitesse_tplus + dernier_phi(2) * vitesse_tdt; P_int_tdt = vitesse * F_int_tdt; // calcul de la puissance externe au dernier point d'integ P_ext_tdt = vitesse * F_ext_tdt; // bilan des puissances au dernier point d'integ bilan_P_tdt = P_acc_tdt - P_int_tdt - P_ext_tdt; // cas des forces visqueuses numériques // if (pa.Amort_visco_artificielle()) // E_visco_numerique_tdt = E_visco_numerique_t + delta_X * forces_vis_num; // --- affichage ---- if (( pa.Vrai_commande_sortie(icharge,temps_derniere_sauvegarde)) &&(pa.AfficheIncrEnergie())) {// cas des énergies cout << "\n energies: cin= "<< E_cin_tdt <<" int= " << E_int_tdt << " ext= " << E_ext_tdt << " bilan= " << bilan_E << " qmv= " << q_mov_tdt; // cas des puissances cout << "\n puissances: acc= "<< P_acc_tdt <<" int= " << P_int_tdt << " ext= " << P_ext_tdt << " bilan= " << bilan_P_tdt; }; } }; //---- 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 AlgoBonelli::ActionInteractiveAlgo() { cout << "\n commande? "; return false; // pour l'instant !!!!!!! }; // sortie du schemaXML: en fonction de enu void AlgoBonelli::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 " << "\n" << "\n " << "\n initialisation de l'algo " << "\n " << "\n " << "\n"; sort << "\n" << "\n " << "\n execution de l'ensemble de l'algo, sans l'initialisation et la derniere passe " << "\n " << "\n " << "\n"; sort << "\n" << "\n " << "\n fin de l'algo " << "\n " << "\n " << "\n"; break; } case XML_STRUCTURE_DONNEE : { break; } }; };