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