// 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 "Algori.h" #include "string" #include "MathUtil.h" #include // pour utiliser la classe istrstream #include // nouveau dans CW5.3 //====================================================================================================== // troisième fichier pour l'implantation des méthodes d'Algori //====================================================================================================== // lecture des paramètres du calcul généraux pour tous les algos (dans le cas où il y en a) // qui peuvent éventuellement ne pas servir !! void Algori::lecture_Parametres(UtilLecture& entreePrinc) { bool a_lire = false; MotCle motCle; // ref aux mots cle // dans le cas où l'entête des paramètres n'a pas été lue par l'algorithme spécifique // on regarde s'il existe if (deja_lue_entete_parametre == 2) // on peut directement lire {a_lire = true;} else // sinon { // deux cas suivant que l'algo spécifique a une méthode de lecture de paramètre ou non if (deja_lue_entete_parametre == 0) { // cas ou l'algo spécifique n'a pas de méthode de lecture de paramètre donc il n'y a pas // eu d'essai de lecture de l'entête // on se positionne sur le prochain mot clé do { entreePrinc.NouvelleDonnee();} while ( !motCle.SimotCle(entreePrinc.tablcar)) ; // si le mot clé est "PARA_TYPE_DE_CALCUL" cela signifie // qu'il y a une zone de paramètre éventuellement à lire if (strstr(entreePrinc.tablcar,"PARA_TYPE_DE_CALCUL")!=NULL) {entreePrinc.NouvelleDonnee(); a_lire = true; } else // sinon le mot clé ne concerne pas les paramètres il n'y a rien n'a lire {a_lire = false; }; } else if (deja_lue_entete_parametre == 1) { // cas ou l'algo spécifique a une méthode de lecture de paramètre donc il a // déjà essayer de lire l'entête et n'a rien trouvé: il n'y a rien n'a lire a_lire = false; } else { cout << "\n erreur deja_lue_entete_parametre = " << deja_lue_entete_parametre << " alors qu'il devrait etre soit 1 ou 0 ou 2 !! " << "\n Algori::lecture_Parametres(...."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage(); if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage(); Sortie(1); }; }; // maintenant on lit en fonction du booléen a_lire if (a_lire) {// on s'arrête lorsqu'il n'y a plus de mot clé spécifique à lire while ( (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL) || (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL) || (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL) || (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL) || (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL) || (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL) || (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL) ) {bool lecture_effective = false; string nom_class_methode("Algori::lecture_Parametres((..."); // pour la lecture int min=1,max=0;string mot_cle;int int_defaut=0; double double_defaut=0;// variables inter qui servent pour la lecture //=== parametres de controle du calcul de la matrice de viscosite ===== if (strstr(entreePrinc.tablcar,"parametre_calcul_de_la_viscosite_")!=NULL) { mot_cle="parametre_calcul_de_la_viscosite_"; lecture_effective = entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle); // si on arrive ici c'est que l'on a bien lue le mot clé "parametre_calcul_de_la_viscosite_" // donc il faudra passer une ligne de toute manière, donc ce n'est plus la peine de tester les booleen // --- lecture éventuelle de type_calcul_visqu_critique int_defaut=0; mot_cle="type_calcul_visqu_critique="; min=1;max=3; entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,type_calcul_visqu_critique); // on change le paramètre de viscosité numérique général en conséquence if (type_calcul_visqu_critique) pa.Change_amort_visco_artificielle(4); // on indique qu'il s'agit d'une gestion par un amortissement visqueux critique // utilisé par de la relaxation dynamique // --- lecture éventuelle de opt_cal_C_critique int_defaut=-1; mot_cle="opt_cal_C_critique="; min=-1;max=2; entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,opt_cal_C_critique); // --- lecture éventuelle de f_ double_defaut=1.; mot_cle="f_="; min=1;max=0; entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,f_); // --- lecture éventuelle de ampli_visco double_defaut=1.; mot_cle="ampli_visco_="; min=1;max=0; entreePrinc.Lecture_un_parametre_double(double_defaut,nom_class_methode,min,max,mot_cle,ampli_visco); }; // else // sinon on met les valeurs par défaut // { type_calcul_visqu_critique= 0; // opt_cal_C_critique= 1; f_= 1.; ampli_visco= 1.; // }; //=== cas où l'on veut de l'amortissement cinétique global avec éventuellement des paramètres particuliers de contrôle if (strstr(entreePrinc.tablcar,"avec_amortissement_cinetique_")!=NULL) { mot_cle="avec_amortissement_cinetique_"; entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle); amortissement_cinetique=true; // on active l'amortissement cinétique string st1; // lecture des paramètres de l'amortissement cinétique while (st1 != "fi_parametre_amortissement_cinetique_") { entreePrinc.NouvelleDonnee(); *(entreePrinc.entree) >> st1; if (st1 == "max_nb_decroit_pourRelaxDyn_") {*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn; } else if (st1 == "inter_nb_entre_relax_") {// il faut que l'on regarde s'il y a éventuellement un remplacement par une // fonction nD if (strstr(entreePrinc.tablcar,"nom_fct_nD_inter_nb_entre_relax_")!=NULL) {mot_cle="nom_fct_nD_inter_nb_entre_relax_"; entreePrinc.Lecture_mot_cle_et_string(nom_class_methode,mot_cle,nom_fct_nD_inter_nb_entre_relax); } else // cas sans fonction nD {nom_fct_nD_inter_nb_entre_relax=""; *(entreePrinc.entree) >> inter_nb_entre_relax; }; } else if (st1 == "taille_moyenne_glissante_") {*(entreePrinc.entree) >> taille_moyenne_glissante;} else if (st1 == "test_fraction_energie_") {*(entreePrinc.entree) >> test_fraction_energie;} else if (st1 == "coef_arret_pourRelaxDyn_") {*(entreePrinc.entree) >> coef_arret_pourRelaxDyn; } else if (st1 == "coef_redemarrage_pourRelaxDyn_") {*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn; } else if (st1 == "max_deltaX_pourRelaxDyn_") {*(entreePrinc.entree) >> max_deltaX_pourRelaxDyn; } else if (st1 == "nb_max_dX_OK_pourRelaxDyn_") {*(entreePrinc.entree) >> nb_max_dX_OK_pourRelaxDyn; } else if (st1 == "nb_deb_testfin_pourRelaxDyn_") {*(entreePrinc.entree) >> nb_deb_testfin_pourRelaxDyn; } else if (st1 == "nb_deb_test_amort_cinetique_") {*(entreePrinc.entree) >> nb_deb_test_amort_cinetique;}; if ((st1 != "max_nb_decroit_pourRelaxDyn_") && (st1 != "inter_nb_entre_relax_") && (st1 != "taille_moyenne_glissante_") && (st1 != "test_fraction_energie_") && (st1 != "coef_arret_pourRelaxDyn_") && (st1 != "coef_redemarrage_pourRelaxDyn_") && (st1 != "max_deltaX_pourRelaxDyn_") && (st1 != "nb_max_dX_OK_pourRelaxDyn_") && (st1 != "nb_deb_testfin_pourRelaxDyn_") && (st1 != "nb_deb_test_amort_cinetique_") && (st1 != "fi_parametre_amortissement_cinetique_")) { cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique" << "\n on attendait un mot cle , au lieu de " << st1 << "\n Algori::lecture_Parametres( ... "; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage(); if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage(); Sortie(1); }; }; // préparation pour une nouvelle donnée lecture_effective= true; }; //=== idem mais pour de l'amortissement cinétique à chaque noeud if (strstr(entreePrinc.tablcar,"avec_au_noeud_amortissement_cinetique_")!=NULL) { mot_cle="avec_au_noeud_amortissement_cinetique_"; entreePrinc.Lecture_et_verif_mot_cle(nom_class_methode,mot_cle); amortissement_cinetique_au_noeud=true; // on active l'amortissement cinétique string st1; // lecture des paramètres de l'amortissement cinétique while (st1 != "fi_parametre_au_noeud_amortissement_cinetique_") { entreePrinc.NouvelleDonnee(); *(entreePrinc.entree) >> st1; if (st1 == "max_nb_decroit_pourRelaxDyn_noe_") {*(entreePrinc.entree) >> max_nb_decroit_pourRelaxDyn_noe; } else if (st1 == "coef_arret_pourRelaxDyn_noe_") {*(entreePrinc.entree) >> coef_arret_pourRelaxDyn_noe; } else if (st1 == "coef_redemarrage_pourRelaxDyn_noe_") {*(entreePrinc.entree) >> coef_redemarrage_pourRelaxDyn_noe; } else if (st1 == "nb_deb_test_amort_cinetique_noe_") {*(entreePrinc.entree) >> nb_deb_test_amort_cinetique_noe;}; if ((st1 != "max_nb_decroit_pourRelaxDyn_noe_") && (st1 != "coef_arret_pourRelaxDyn_noe_") && (st1 != "coef_redemarrage_pourRelaxDyn_noe_") && (st1 != "nb_deb_test_amort_cinetique_noe_") && (st1 != "fi_parametre_au_noeud_amortissement_cinetique_")) { cout << "\n erreur en lecture du coef d'arret pour l'amortissement cinetique" << "\n on attendait un mot cle , au lieu de " << st1 << "\n Algori::lecture_Parametres( ... "; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsInitialisation.Comptage_en_cours()) tempsInitialisation.Arret_du_comptage(); if (tempsMiseAjourAlgo.Comptage_en_cours()) tempsMiseAjourAlgo.Arret_du_comptage(); Sortie(1); }; }; // préparation pour une nouvelle donnée lecture_effective= true; }; //=== contrôle éventuel d'un arrêt sur équilibre statique if (strstr(entreePrinc.tablcar,"ARRET_A_EQUILIBRE_STATIQUE_")!=NULL) { // on commence par regarder si l'on est en dynamique, si non on met un warning if (Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE) cout << "\n *** Attention, on demande un arret sur l'equilibre statique, (cf. para de l'algo) " << " alors que l'algorithme n'est pas dynamique ?????? il y a peut-etre une erreur de parametres " << endl; // --- lecture éventuelle de opt_cal_C_critique int_defaut=0; mot_cle="ARRET_A_EQUILIBRE_STATIQUE_"; min=0;max=2; lecture_effective= false; lecture_effective = entreePrinc.Lecture_un_parametre_int(int_defaut,nom_class_methode,min,max,mot_cle,arret_a_equilibre_statique); // sert aussi en fait pour retirer éventuellement la partie visqueuse numérique }; //=== contrôle d'un mode débug éventuel // cas où le paramètre de mode débug existe if (strstr(entreePrinc.tablcar,"mode_debug_=")!=NULL) { int_defaut=0; mot_cle="mode_debug_=";min=1;max=ConstMath::tresgrand; { bool lec_eff = entreePrinc.Lecture_un_parametre_int (int_defaut,nom_class_methode,min,max,mot_cle,mode_debug); lecture_effective = lecture_effective || lec_eff; }; }; //=== contrôle d'un niveau de commentaire spécifique à l'algo if (strstr(entreePrinc.tablcar,"permet_affichage_")!=NULL) { int_defaut=0; mot_cle="permet_affichage_";min=1;max=ConstMath::tresgrand; { bool lec_eff = entreePrinc.Lecture_un_parametre_int (int_defaut,nom_class_methode,min,max,mot_cle,permet_affichage); lecture_effective = lecture_effective || lec_eff; }; }; //=== cas où on veut moduler la précision de la convergence globale via une fct nD if (strstr(entreePrinc.tablcar,"modulation_precision_equilibre_=")!=NULL) { mot_cle="modulation_precision_equilibre_="; { bool lec_eff = entreePrinc.Lecture_mot_cle_et_string (nom_class_methode,mot_cle,nom_modulation_precision); lecture_effective = lecture_effective || lec_eff; }; }; if ((lecture_effective) && ( !motCle.SimotCle(entreePrinc.tablcar))) {entreePrinc.NouvelleDonnee(); // si on a lue des para sur la ère ligne on passe à la suivante lecture_effective=false; }; }; // si le paramètre est activé, on définit le vecteur intermédiaire de sauvegarde du résidu statique // un pb cependant, la lecture de l'amortissement artificielle n'est éventuellement pas encore fait // c'est le cas d'une première lecture du .info, l'amortissement visqueux s'effectue au niveau des paramètres // de contrôle donc bien après l'algo, dans ce cas il faut prévoir dans l'initialisation des algo spécifiques // le dimensionnement de vglob_stat if ( (arret_a_equilibre_statique ) // le dimensionnement se fera à l'affectation (=) && (type_calcul_visqu_critique || pa.Amort_visco_artificielle())) { if (vglob_stat == NULL) vglob_stat = new Vecteur();} else // dans le cas on ne veut pas un arret statique spécifique sans viscosité numérique { if (vglob_stat != NULL) {delete vglob_stat; vglob_stat=NULL ;};}; // on se positionne éventuellement sur le prochain mot clé si on n'y est pas déjà while ( !motCle.SimotCle(entreePrinc.tablcar)) entreePrinc.NouvelleDonnee(); }; //-- fin du cas où on a regardé }; // création d'un fichier de commande: cas des paramètres spécifiques // par défaut on indique qu'il n'y a pas de paramètres. void Algori::Info_com_parametres(UtilLecture& entreePrinc) { // écriture dans le fichier de commande ofstream & sort = *(entreePrinc.Commande_pointInfo()); // pour simplifier cout << "\n# exemple para facultatifs generaux d'algorithme (rep o ou n defaut) ? "; string rep; rep = "_"; // procédure de lecture avec prise en charge d'un retour chariot rep = lect_return_defaut(true,"n"); // si la taille de rep == 0 cela veut dire que c'est un retour chariot if (rep.size()==0) {rep = "n"; cout << "--> valeur par defaut : n "<= 0)&&(num< 7)) { choix_valide=true; } else { cout << "\n Erreur on attendait un entier entre 0 et 6 !!, " << "\n redonnez une bonne valeur" << "\n ou taper f ou 0 pour arreter le programme"; choix_valide=false; } switch (num) { case 0: //fin { break;} // normalement cela a déjà été filtré avant case 1: // amortissement cinetique { sort << "\n#---------------------------------------------------------------------" << "\n| parametres communs a differents algorithmes (voir doc specifique) |" << "\n#---------------------------------------------------------------------" << "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! " << "\n # ---------------------------------------------------------------------- " << "\n # --- parametres de controle du calcul de l'amortissement cinetique --- " << "\n # ---------------------------------------------------------------------- " << "\n # Il est possible de prendre en compte un amortissement cinetique, dont l'objectif " << "\n # est d'obtenir une solution statique a l'aide d'un algorithme dynamique." << "\n # Pour cela on introduit le mot cle: avec_amortissement_cinetique_ suivi " << "\n # de mots cles eventuels qui precisent des parametres. Ce groupe de parametres " << "\n # se termine par le mot cle fi_parametre_amortissement_cinetique_ " << "\n # Chaque parametre est suivi d'un nombre. Chaque parametre + nombre, doit etre sur une ligne a part." << "\n # deux techniques pour appliquer le test, qui conduit a mettre les vitesses à 0 " << "\n # 1) on regarde si l'|energie cinetique| diminue n1 fois (consécutives) " << "\n # ou est inferieure n1 fois fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle " << "\n # NB: le test ne se declanche que lorsque l'on a scrute au moins n1 valeurs de l'energie cinetique " << "\n # 2) on regarde si la moyenne glissante de n2 |energie cinetique| consecutive diminue n1 fois (consecutives) " << "\n # ou est inferieure n1 fois fraction * dernier_max_E_cin, si fraction (= test_fraction_energie) est non nulle " << "\n # NB: le test ne se declanche que lorsque l'on a au moins n2 valeurs consecutives disponibles de l'energie cinetique " << "\n # NB: le cas 1) est en fait un cas particulier du 2) pour lequel n2 == 1 " << "\n # Les parametres sont: " << "\n # max_nb_decroit_pourRelaxDyn_ : nombre n2 de diminution de de la moyenne glissante de l'energie cinetique a" << "\n # (Par exemple si = 3, cela signifie qu'il faut attendre 3 baisses de " << "\n # l'energie cinetique pour valider la relaxation. Ces 3 baisses peuvent apparaître au " << "\n # cours de n iterations, n etant plus grand que 3 ! De plus pendant ces en iterations," << "\n # on peut egalement avoir des elevations de l'energie cinetique suivi de diminutions." << "\n # Seules les diminutions sont prises en compte. Apres une relaxation, le compteur de " << "\n # diminution est remis à 0 " << "\n # )" << "\n # partir de laquelle on met les vitesses a 0 " << "\n # inter_nb_entre_relax_ : intervalle autorise entre deux relaxation " << "\n # (Par exemple si = 10, cela signifie qu'apres une relaxation, une nouvelle relaxation" << "\n # ne sera accepte qu'apres 10 nouvelles iterations. " << "\n # Il est egalement possible de remplacer la valeur numerique par le resultat d'une fonction nD " << "\n # pour cela on indique le mot cle : nom_fct_nD_inter_nb_entre_relax_ " << "\n # suivi du nom de la fonction nD qui sera appelee a chaque fois que l'on aura besoin " << "\n # du parametre inter_nb_entre_relax_ " << "\n # )" << "\n # taille_moyenne_glissante_ : valeur du nombre n2 de la moyenne glissante d'energie cinetique " << "\n # test_fraction_energie_ : si diff de 0, indique la valeur de fraction " << "\n # coef_arret_pourRelaxDyn_ : arret de l'amortissement lorsque l'energie cinetique est" << "\n # inferieur à ce coef * le dernier pic d'energie cinetique " << "\n # coef_redemarrage_pourRelaxDyn_ : redemarrage de l'amortissement lorsque l'energie cinetique" << "\n # est sup a ce coef * le maxi des pic d'energie enregistre" << "\n # max_deltaX_pourRelaxDyn_ : limite inferieur de delta x_(t->tdt) a partir de laquelle" << "\n # on arrete le calcul" << "\n # nb_max_dX_OK_pourRelaxDyn_ : nombre de fois que le critere precedent doit etre satisfait" << "\n # pour que le calcul s'arrete" << "\n # nb_deb_testfin_pourRelaxDyn_ : le nombre mini de passage dans l'amortissement, a partir duquel on test la fin" << "\n # nb_deb_test_amort_cinetique_ : le nombre mini d'iteration, a partir duquel on demarre l'algorithme" << "\n # fi_parametre_amortissement_cinetique_ : mot cle obligatoire indiquant la fin des parametres" << "\n # exemple de declaration" << "\n # " << "\n # avec_amortissement_cinetique_ " << "\n # max_nb_decroit_pourRelaxDyn_ 1 " << "\n # inter_nb_entre_relax_ 1 " << "\n # ou " << "\n # inter_nb_entre_relax_ nom_fct_nD_inter_nb_entre_relax_ toto " << "\n # taille_moyenne_glissante_ 1 " << "\n # coef_arret_pourRelaxDyn_ 0. " << "\n # coef_redemarrage_pourRelaxDyn_ 0.01 " << "\n # max_deltaX_pourRelaxDyn_ 0.4 " << "\n # nb_max_dX_OK_pourRelaxDyn_ 5 " << "\n # nb_deb_testfin_pourRelaxDyn_ 100 " << "\n # nb_deb_test_amort_cinetique_ 100 " << "\n # fi_parametre_amortissement_cinetique_ " << "\n # " << endl; break;} case 2: // calcul d'une matrice de viscosite numerique { sort << "\n#---------------------------------------------------------------------" << "\n| parametres communs a differents algorithmes (voir doc specifique) |" << "\n#---------------------------------------------------------------------" << "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! " << "\n # ---------------------------------------------------------------------- " << "\n # --- parametres de controle du calcul de la matrice de viscosite --- " << "\n # ---------------------------------------------------------------------- " << "\n # Il est possible de prendre en compte de l'amortissement critique numerique " << "\n # classiquement utilise dans le cas de la relaxation dynamique " << "\n # " << "\n # ** PARAMETRES FACULTATIF ** " << "\n # on indique tout d'abord le mot cle : parametre_calcul_de_la_viscosite_ suivi des parametres associes eventuelles " << "\n # type_calcul_visqu_critique= suivi du type de calcul " << "\n # si type_calcul_visqu_critique= 1 : la matrice C est calculee selon: C_{ii} = c * M_{ii} avec c = 2 * omega_0 " << "\n # si type_calcul_visqu_critique= 2 : la matrice C est calculee selon: C_{ii} = c * M_{ii} " << "\n # avec c = sqrt( 4*omega_0^2 - omega_0^4)" << "\n # si type_calcul_visqu_critique= 3 : la matrice C est calculee selon: C_{ii} = c * M_{ii} " << "\n # avec c = 2*sqrt(omega_0/(1+omega_0)) " << "\n # " << "\n # puis il y a un choix via le parametre opt_cal_C_critique= " << "\n # opt_cal_C_critique= 0 : (omega_0)^2 \approx (Delta X^T Delta R_{i(statique)}^n) / (Delta X^T M Delta X) " << "\n # opt_cal_C_critique= 1 : (omega_0)^2 \approx (dot X^T Delta R_{i(statique)}^n) / (dot X^T M dot X) " << "\n # " << "\n # a) si (omega_0)^2 est négative on met omega_0^2=0 " << "\n # b) si (omega_0)^2 > f^2 * 4, on pose (omega_0) = f^2 * 4, par defaut: f= 0.9 " << "\n # on peut changer la valeur de f avec le parametre: f_= suivi de la valeur " << "\n # " << "\n # il est possible egalement d'amplifier la valeur de la viscosite calculee (avec cependant toujours les limites a) et b) " << "\n # ampli_visco_= val_ampli " << "\n # " << "\n # Exemple de declaration: " << "\n ## parametre_calcul_de_la_viscosite_ type_calcul_visqu_critique= 1 opt_cal_C_critique= 0 f_= 1.3 " << "\n # " << "\n # tous les parametres sont facultatifs: les valeurs par defaut sont: " << "\n # opt_cal_C_critique= 1 ; f_= 0.9 ; ampli_visco_= 1.; " << "\n # " << "\n # " << endl; break;} case 3: // parametres supplementaires de controle du type d'arret de l'algo { sort << "\n#---------------------------------------------------------------------" << "\n| parametres communs a differents algorithmes (voir doc specifique) |" << "\n#---------------------------------------------------------------------" << "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! " << "\n # apres l'amortissement cinetique, apres la def de calcul de viscosite et les autres qui precedent!!! " << "\n # ---------------------------------------------------------------------- " << "\n # --- parametres de controle du type d'arret --- " << "\n # ---------------------------------------------------------------------- " << "\n # ce parametre est utile dans le cas d'un calcul dynamique " << "\n # on peut egalement indiquer un arret correspondant a un equilibre statique. Dans ce cas " << "\n # le calcul s'arrete lorsqu'on considere que l'on a atteind un regime statique dont le critere est:" << "\n # - le residu statique est inferieur au maxi indique dans les parametres generaux de controle" << "\n # - si l'on utilise de l'amortissement cinetique: le critere d'arret est celui de cet algo" << "\n # Pour activer cette possibilite d'arret il faut indiquer sur la ligne qui suit le mot cle" << "\n # ARRET_A_EQUILIBRE_STATIQUE_ suivant d'un nombre " << "\n # ARRET_A_EQUILIBRE_STATIQUE_ 1 signifie que le residu statique est utilise comme critere" << "\n # ARRET_A_EQUILIBRE_STATIQUE_ 2 le residu statique et le critere de l'amortissement cinetique " << "\n # sont conjointement utilises, on retient le plus defavorable" << "\n # ARRET_A_EQUILIBRE_STATIQUE_ 0 pas de prise en compte de ce parametre (valeur par defaut)" << "\n # " << "\n # exemple d'utilisation " << "\n # " << "\n # ARRET_A_EQUILIBRE_STATIQUE_ 1 " << "\n # " << endl; break;} case 4: // parametres de controle du mod debug { sort << "\n#---------------------------------------------------------------------" << "\n| parametres communs a differents algorithmes (voir doc specifique) |" << "\n#---------------------------------------------------------------------" << "\n # IMPORTANT: les parametres qui suivent sont à mettre apres ceux specifique de l'algorithme !!! " << "\n # apres les parametres de controle de type d'arret et les autres qui precedent !!! " << "\n # ---------------------------------------------------------------------- " << "\n # --- parametres de controle du mode debug --- " << "\n # ---------------------------------------------------------------------- " << "\n # ** PARAMETRES FACULTATIF ** " << "\n # mode_debug_= parametre de debug (= 0 par defaut -> calcul classique) " << "\n # = n : a chaque n iteration on sort une visualisation " << "\n ## mode_debug_= 0 # a mettre apres les para de relaxation " << "\n # " << "\n # modulation_precision_equilibre_= fonction_nD " << "\n # la fonction fonction_nD module par multiplication, la precision en cours " << "\n # **important**: ces parametres doivent etre mis chacun sur une ligne differente " << endl; break;} case 5: // def de fichiers externes contenant des contraintes, deformations ... { sort << "\n # --------------------------------------------------------------------------------- " << "\n # --- lecture sur fichiers externes de grandeurs preexistantes au calcul --- " << "\n # --------------------------------------------------------------------------------- " << "\n # ce referer a la doc pour la syntaxe dans les fichiers \n" << "\n flotExterne #--- # mot cle pour introduire la lecture \n"; string repi= " "; // init rep=" "; // init while ((Minuscules(repi) != "f")&&(Minuscules(repi) != "0")) { try { cout << "\n (0 ou f) (fin) " << "\n (1) nouveau fichier de contraintes aux point d'integration " << "\n (2) nouveau fichier de deplacement aux noeuds " << "\n "; // procédure de lecture avec prise en charge d'un retour chariot repi = lect_return_defaut(false,"f"); if ((Minuscules(repi) == "f") || (Minuscules(repi) == "0"))// sortie directe break; int numi = ChangeEntier(repi); bool choix_valide=false; if ((numi >= 0)&&(numi<=2)) { choix_valide=true; } else { cout << "\n Erreur on attendait un entier entre 0 et 2 !!, " << "\n redonnez une bonne valeur" << "\n ou taper f ou 0 pour arreter le programme"; choix_valide=false; } switch (numi) { case 0: //fin { break;} // normalement cela a déjà été filtré avant case 1: // nouveau fichier de contraintes aux point d'integration { string nom; cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _cab.isoe ) "; nom = lect_chaine(); sort << "\n 1 " << nom << "_cab.isoe " ; cout << "\n nom du maillage associe au fichier ? "; nom = lect_chaine(); sort << nom << endl; break; } case 2: // nouveau fichier de contraintes aux point d'integration { string nom; cout << "\n nom du fichier sans extension? (mais qui doit avoir l'extension _dpl.points ) "; nom = lect_chaine(); sort << "\n 2 " << nom << "_dpl.points " ; cout << "\n nom du maillage associe au fichier ? "; nom = lect_chaine(); sort << nom << endl; break; } default: cout << "\n le cas "<size() > 0) {if ((find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_sigma) != soustypeDeCalcul->end()) || (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),avec_remonte_erreur) != soustypeDeCalcul->end())) {Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); avec_remont=true;avec_remont_sigma=true;} if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_epsilon) != soustypeDeCalcul->end()) {Algori::InitRemontEps(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); avec_remont=true;avec_remont_eps=true;} if (find(soustypeDeCalcul->begin(),soustypeDeCalcul->end(),prevision_visu_erreur) != soustypeDeCalcul->end()) {if (!avec_remont_sigma) {Algori::InitRemontSigma(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); avec_remont_sigma=true;} Algori::InitErreur(lesMail,lesRef,diversStockage,charge,lesCondLim,lesContacts,resultats); avec_remont=true;avec_erreur=true;} }; return avec_remont; }; // calcul d'une remontée à des variables secondaires ou d'erreur, ceci pour un post traitement de visualisation // ce calcul dépend des paramètres utilisateurs, il n'est fait qu'à chaque sortie .BI // ramène true s'il y a un calcul effectif bool Algori::CalculRemont(LesMaillages * lesMail,OrdreVisu::EnumTypeIncre type_incre,int incre) { bool change=false; bool remont_contrainte=false; if (pa.SauvegardeAutorisee(incre,temps_derniere_sauvegarde,type_incre)) { if (avec_remont_sigma) {Algori::RemontSigma(lesMail);change=true;remont_contrainte=true;}; if (avec_remont_eps) {Algori::RemontEps(lesMail);change=true;}; if (avec_erreur) {Algori::RemontErreur(lesMail);change=true;}; }; return change; }; // affichage éventuelle de la matrice de raideur et du second membre void Algori::Affiche_RaidSM(const Vecteur & vglobin,const Mat_abstraite& matglob) const { // affichage éventuelle de la matrice de raideur et du second membre if (ParaGlob::NiveauImpression() >= 10) { string entete = " affichage de la matrice de raideur "; matglob.Affichage_ecran(entete); entete = " affichage du second membre "; vglobin.Affichage_ecran(entete); } }; // algorithme classique de line search // le line seach agit sur une partie de la puissance et non sur la norme du résidu // le line search à pour objectif de minimiser une partie de l'acroissement de la puissance // en jeux, ainsi on peut avoir une minimisation réussi tout en ayant une norme d'équilibre // qui continue à grandir // cependant en général les deux sont lié et l'application du line_seach garantit que dans // la direction de descente choisi on minimise norme (mais ce minimum peut cependant être // supérieur à l'ancienne norme!) bool Algori::Line_search1(Vecteur& sauve_deltadept,double& puis_precedente, Vecteur& vres,LesMaillages * lesMail,Vecteur* sol ,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex ,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal ,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb ,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD) { // ------------------------------------------------------------ // |on regarde s'il faut utiliser l'algorithme de line search | // ------------------------------------------------------------ // nombre d'incrément mini à partir duquel on exécute le line_search const int nb_incr_min_line_search = 2; // les mini et maxi du facteur de line _search const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit // le nombre de fois que l'algorithme bute sur le mini et maxi int nbfois_alphmin = 0; int nbfois_alphmax = 0; const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2; // nombre maxi de boucle de line_search const int iwwmax = 5; // limite sur la puissance pour activer le line_search const double epsilon_p = 0.01; double ancien_residu_norme = vres.Max_val_abs (); double norme_dep = sauve_deltadept.Max_val_abs (); double ancien_residuN = (- vres * (*sol)); // sauvegarde du déplacement sauve_deltadept = *sol; // il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre // en oeuvre l'algorithme // 1 - on sauvegarde les conditions actuelles // récupération de l'incrément total de t à tdt avant le déplacement lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb); // 2 - on met en place le nouveau déplacement lesMail->PlusDelta_tdt(*sol,nb_casAssemb); // 3 - initialisation de la puissance externe puis on la calcul vglobex.Zero(); if (!(charge->ChargeSecondMembre_Ex_mecaSolid (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul " << " des efforts externes: arret" << "\n Algori::Line_search1(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // 4 - idem pour la puissance interne vglobin.Zero(); // 5 - calcul du second membre et des énergies // dans le cas d'un calcul inexploitable arrêt de la boucle if (!SecondMembreEnerg(lesMail,Ass,vglobin)) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret" << "\n Algori::Line_search1(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // 6 - second membre total vglobaal = vglobex ;vglobaal += vglobin; // 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat); double nouvelle_norme = vglobaal.Max_val_abs (); // calcul d'une partie de la variation de puissance relative au delta ddl // cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl // et la direction du résidu double var_puis = - vglobaal * sauve_deltadept; // calcul de la puissance cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis; cout << "\n puissance " << var_puis ; cout << "\n ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme); if ((compteur >= nb_incr_min_line_search) && ((Abs(var_puis) > epsilon_p * norme_dep * nouvelle_norme) || (nouvelle_norme > 0.1 * ancien_residu_norme))) // ((var_puis > puis_precedente) || (nouvelle_norme > ancien_residu_norme))) // || (puis_reelle < 0.)) {// signifie que le déplacement précédent était trop grand // ou pas dans la bonne direction ! // 1) on revient aux conditions du début de l'itération v_travail -= sauve_dept_a_tdt; lesMail->PlusDelta_tdt(v_travail,nb_casAssemb); // 2) on traite la direction // si la puissance est négative cela signifie que la matrice n'est pas définie // positive, dans ce cas on utilise comme direction de descente // - la direction trouvée ou le résidu /* if (puis_reelle < 0.) { // message d'avertissement cout << "\n ********** attention puissance négative, changement de descente "; // ancien_dep = - vres; ancien_dep = - ancien_dep; } */ /* else if (Abs(puis_reelle) > pa.max_puissance) // si la puissance est trop grande arrêt des itérations { non_convergence = true; break; } */ // 3) Maintenant application du line search, //calcul d'alpha en utilisant une approximation linéaire de la puissance double alph = 1.; // initialisation du coef multiplicateur du delta ddl // dans le cas ou la nouvelle et l'ancienne puissance sont très proche // on change de alpha if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme) alph = 0.66; // par exemple // dans un premier temps on effectue un nombre de boucle fixé pour alpha bool reduc_reussi = false; bool reduc_possible = true; for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++) { // calcul du nouveau résidu // mise en place du nouveau déplacement // pour éviter de créer un nouveau vecteur qui peut être de grande taille // on utilise la place de vglobex pour le déplacement Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept; lesMail->TversTdt(); lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb ); //puissance externe vglobex.Zero(); if (!(charge->ChargeSecondMembre_Ex_mecaSolid (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul " << " des efforts externes: arret" << "\n Algori::Line_search1(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // puissance interne boucle sur les elements vglobin.Zero(); // calcul du second membre et des énergies // dans le cas d'un calcul inexploitable arrêt de la boucle if (!SecondMembreEnerg(lesMail,Ass,vglobin)) { cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret" << "\n Algori::Line_search1(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // second membre total vglobaal = vglobex ;vglobaal += vglobin; // mise en place des conditions limites lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat); // calcul du nouveau coefficient // double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep); // double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu * ancien_dep);//vres.Norme(); double nouveau_residuN = alph * (- vglobaal * sauve_deltadept); double ancien_alph = alph; nouvelle_norme = vglobaal.Max_val_abs (); alph = - alph* ancien_residuN/ (nouveau_residuN - ancien_residuN); // test d'arrêt if ((alph < alphmin) || (alph > alphmax)) { // troncature d'alpha if (alph < alphmin) {alph = alphmin;nbfois_alphmin++; if (nbfois_alphmin > nbfois_alphmin_max) /* if (nouvelle_norme < ancien_residu_norme) // soit la norme à diminuée => on prend le nouveau déplacement // et on arrête car dans tous les cas ce n'est pas une bonne convergence // d'être acculé à la borne { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobal; puis_precedente = Abs(nouveau_residuN); break; } else */ // sinon il n'y a pas en plus de convergence on arrête tout reduc_possible = false; } if (alph > alphmax) {alph = alphmax;nbfois_alphmax++; if (nbfois_alphmax > nbfois_alphmax_max) /* if (nouvelle_norme < ancien_residu_norme) // soit la norme à diminuée => on prend le nouveau déplacement // et on arrête car dans tous les cas ce n'est pas une bonne convergence // d'être acculé à la borne { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobal; puis_precedente = Abs(nouveau_residuN); break; } else */ // sinon il n'y a pas en plus de convergence on arrête tout reduc_possible = false; } } else // sinon on test la convergence // if (nouvelle_norme < 0.8 * ancien_residu_norme ) {if ((Abs(nouveau_residuN) < 0.5 * Abs(puis_precedente) ) && (nouvelle_norme < ancien_residu_norme)) { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobaal; puis_precedente = Abs(nouveau_residuN); break; } // else if (iww==iwwmax) else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme)) {reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobaal; puis_precedente = Abs(nouveau_residuN); break; } } // sinon on incrémente la position à tdt cout << "\n coefficient de line_search = " << alph << " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN; } // si la réduction c'est mal passée alors on laisse la solution // identique à avant le line_search if (!reduc_reussi) { // mise en place du déplacement existant avant le line_search // ainsi que les autres grandeurs actives lesMail->TversTdt(); v_travail = sauve_dept_a_tdt + sauve_deltadept; lesMail->PlusDelta_tdt( v_travail,nb_casAssemb); // retour du fait qu'il n'y a pas eu de line search return false; } else { // retour du fait que le line search a été effectué return true; } } else // cas ou l'on ne fait pas de line seach return false; }; // algorithme de line search qui utilise une approximation cubique du résidu ( (R).) // en fonction du paramètre lambda de line search ( X+lambda. delta_ddl) // la méthode renvoi si oui ou non le line search a été effecué // sauve_deltadept : vecteur de travail servant à sauver la valeur calculée de sol // vres : correspond en entrée au vecteur résidu // sauve_dept_a_tdt : vecteur de travail utilisé pour sauvegarder la totalité de l'incrément de t à t+dt // vglobex : puissance externe // v_travail : vecteur de travail à la même dimension que sol // vglobal : = & vglobin: vecteur puissance globale bool Algori::Line_search2(Vecteur& sauve_deltadept,double& puis_precedente, Vecteur& vres,LesMaillages * lesMail,Vecteur* sol ,int& compteur,Vecteur& sauve_dept_a_tdt,Charge* charge,Vecteur& vglobex ,Assemblage& Ass,Vecteur& v_travail,LesCondLim* lesCondLim,Vecteur& vglobaal ,LesReferences* lesRef,Vecteur & vglobin,const Nb_assemb& nb_casAssemb ,int cas_combi_ddl,LesCourbes1D* lesCourbes1D,LesFonctions_nD* lesFonctionsnD) { /* // initialisation des différentes grandeurs nécessaires pour le calcul du polynome cubique complet ou dégénéré double f1= ;// puissance pour lambda = 0 double f2= ;// puissance pour lambda = 1 double g1= ;// */ // ------------------------------------------------------------ // |on regarde s'il faut utiliser l'algorithme de line search | // ------------------------------------------------------------ // nombre d'incrément mini à partir duquel on exécute le line_search const int nb_incr_min_line_search = 2; // les mini et maxi du facteur de line _search const double alphmin = 0.1; const double alphmax = 1.5; // les mini et maxi permit // le nombre de fois que l'algorithme bute sur le mini et maxi int nbfois_alphmin = 0; int nbfois_alphmax = 0; const int nbfois_alphmin_max = 2; const int nbfois_alphmax_max = 2; // nombre maxi de boucle de line_search const int iwwmax = 5; // limite sur la puissance pour activer le line_search const double epsilon_p = 0.01; double ancien_residu_norme = vres.Max_val_abs (); double norme_dep = sauve_deltadept.Max_val_abs (); double ancien_residuN = (- vres * (*sol)); // sauvegarde du déplacement sauve_deltadept = *sol; // il est nécessaire de calculer le nouveau résidu pour conclure sur l'utilité de mettre // en oeuvre l'algorithme // 1 - on sauvegarde les conditions actuelles // récupération de l'incrément total de t à tdt avant le déplacement lesMail->RecupDepde_tatdt(sauve_dept_a_tdt,nb_casAssemb); // 2 - on met en place le nouveau déplacement lesMail->PlusDelta_tdt(*sol,nb_casAssemb); // 3 - initialisation de la puissance externe puis on la calcul vglobex.Zero(); if (!(charge->ChargeSecondMembre_Ex_mecaSolid (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul " << " des efforts externes: arret" << "\n Algori::Line_search2(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // 4 - idem pour la puissance interne vglobin.Zero(); // 5 - calcul du second membre et des énergies // dans le cas d'un calcul inexploitable arrêt de la boucle if (!SecondMembreEnerg(lesMail,Ass,vglobin)) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul du residu: arret" << "\n Algori::Line_search2(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // 6 - second membre total ( vglobal est identique a vglobin) vglobaal = vglobex ; vglobaal += vglobin; // 7 - mise en place des conditions limites, vglobal contiend le nouveau résidu lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat); double nouvelle_norme = vglobaal.Max_val_abs (); // calcul d'une partie de la variation de puissance relative au delta ddl // cette grandeur sert à mesurer l'écart de normalité entre la direction de delta ddl // et la direction du résidu double var_puis = - vglobaal * sauve_deltadept; // calcul de la puissance cout << "\n ecart de permendicularité entre deltat ddl et residu = " << var_puis; cout << "\n puissance " << var_puis ; cout << "\n ||dep|| * ||res|| " << ( norme_dep * nouvelle_norme); if ((compteur >= nb_incr_min_line_search) && ((Abs(var_puis) > epsilon_p * norme_dep * nouvelle_norme) || (nouvelle_norme > 0.1 * ancien_residu_norme))) // ((var_puis > puis_precedente) || (nouvelle_norme > ancien_residu_norme))) // || (puis_reelle < 0.)) {// signifie que le déplacement précédent était trop grand // ou pas dans la bonne direction ! // 1) on revient aux conditions du début de l'itération v_travail -= sauve_dept_a_tdt; lesMail->PlusDelta_tdt(v_travail,nb_casAssemb); // 2) on traite la direction // si la puissance est négative cela signifie que la matrice n'est pas définie // positive, dans ce cas on utilise comme direction de descente // - la direction trouvée ou le résidu /* if (puis_reelle < 0.) { // message d'avertissement cout << "\n ********** attention puissance négative, changement de descente "; // ancien_dep = - vres; ancien_dep = - ancien_dep; } */ /* else if (Abs(puis_reelle) > pa.max_puissance) // si la puissance est trop grande arrêt des itérations { non_convergence = true; break; } */ // 3) Maintenant application du line search, //calcul d'alpha en utilisant une approximation linéaire de la puissance double alph = 1.; // initialisation du coef multiplicateur du delta ddl // dans le cas ou la nouvelle et l'ancienne puissance sont très proche // on change de alpha if (Abs(var_puis- ancien_residuN) < epsilon_p * norme_dep * nouvelle_norme) alph = 0.66; // par exemple // dans un premier temps on effectue un nombre de boucle fixé pour alpha bool reduc_reussi = false; bool reduc_possible = true; for (int iww = 1;(iww<=iwwmax && reduc_possible) ;iww++) { // calcul du nouveau résidu // mise en place du nouveau déplacement // pour éviter de créer un nouveau vecteur qui peut être de grande taille // on utilise la place de vglobex pour le déplacement Vecteur& nouveau_dep = vglobex; // place pour un nouveau déplacement nouveau_dep = sauve_dept_a_tdt + alph * sauve_deltadept; lesMail->TversTdt(); lesMail->PlusDelta_tdt(nouveau_dep,nb_casAssemb ); //puissance externe vglobex.Zero(); if (!(charge->ChargeSecondMembre_Ex_mecaSolid (Ass,lesMail,lesRef,vglobex,pa,lesCourbes1D,lesFonctionsnD))) { cout << "\n erreur dans l'algo, du a une erreur sur le calcul " << " des efforts externes: arret" << "\n Algori::Line_search2(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // puissance interne boucle sur les elements vglobin.Zero(); // calcul du second membre et des énergies // dans le cas d'un calcul inexploitable arrêt de la boucle if (!SecondMembreEnerg(lesMail,Ass,vglobin)) { cout << "\n erreur2 dans l'algo, du a une erreur sur le calcul du residu: arret" << "\n Algori::Line_search1(..."; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // second membre total ( vglobal est identique a vglobin) vglobaal = vglobex ;vglobaal += vglobin; // mise en place des conditions limites lesCondLim->ImposeConLimtdt(lesMail,lesRef,vglobaal,nb_casAssemb,cas_combi_ddl,vglob_stat); // calcul du nouveau coefficient // double nouveau_residuN = vglobal.Max_val_abs ();//alph * (- vglobal * ancien_dep); // double ancien_residuN = ancien_residu.Max_val_abs ();//alph * (- ancien_residu * ancien_dep);//vres.Norme(); double nouveau_residuN = alph * (- vglobaal * sauve_deltadept); double ancien_alph = alph; nouvelle_norme = vglobaal.Max_val_abs (); alph = - alph* ancien_residuN/ (nouveau_residuN - ancien_residuN); // test d'arrêt if ((alph < alphmin) || (alph > alphmax)) { // troncature d'alpha if (alph < alphmin) {alph = alphmin;nbfois_alphmin++; if (nbfois_alphmin > nbfois_alphmin_max) /* if (nouvelle_norme < ancien_residu_norme) // soit la norme à diminuée => on prend le nouveau déplacement // et on arrête car dans tous les cas ce n'est pas une bonne convergence // d'être acculé à la borne { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobal; puis_precedente = Abs(nouveau_residuN); break; } else */ // sinon il n'y a pas en plus de convergence on arrête tout reduc_possible = false; } if (alph > alphmax) {alph = alphmax;nbfois_alphmax++; if (nbfois_alphmax > nbfois_alphmax_max) /* if (nouvelle_norme < ancien_residu_norme) // soit la norme à diminuée => on prend le nouveau déplacement // et on arrête car dans tous les cas ce n'est pas une bonne convergence // d'être acculé à la borne { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobal; puis_precedente = Abs(nouveau_residuN); break; } else */ // sinon il n'y a pas en plus de convergence on arrête tout reduc_possible = false; } } else // sinon on test la convergence // if (nouvelle_norme < 0.8 * ancien_residu_norme ) {if ((Abs(nouveau_residuN) < 0.5 * Abs(puis_precedente) ) && (nouvelle_norme < ancien_residu_norme)) { reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobaal; puis_precedente = Abs(nouveau_residuN); break; } // else if (iww==iwwmax) else if ((iww==iwwmax) && (nouvelle_norme < ancien_residu_norme)) {reduc_reussi = true; // on remet au mieux les choses comme au début de la méthode *sol = ancien_alph * sauve_deltadept; vres = vglobaal; puis_precedente = Abs(nouveau_residuN); break; } } // sinon on incrémente la position à tdt cout << "\n coefficient de line_search = " << alph << " puiss : " << nouveau_residuN << " old_puiss " << ancien_residuN; } // si la réduction c'est mal passée alors on laisse la solution // identique à avant le line_search if (!reduc_reussi) { // mise en place du déplacement existant avant le line_search // ainsi que les autres grandeurs actives lesMail->TversTdt(); v_travail = sauve_dept_a_tdt + sauve_deltadept; lesMail->PlusDelta_tdt( v_travail,nb_casAssemb); // retour du fait qu'il n'y a pas eu de line search return false; } else { // retour du fait que le line search a été effectué return true; } } else // cas ou l'on ne fait pas de line seach return false; }; // initialisation des paramètres pour l'amortissement cinétique (au cas ou on veut plusieurs amortissement) void Algori::InitialiseAmortissementCinetique() { compteur_decroit_pourRelaxDyn=0; dernier_pic = pic_E_cint_t = -1.; max_pic_E_cin = -1.; compteur_test_pourRelaxDyn = 0; compteur_pic_energie = 0;compteur_pic_energie_noe= 0; // cas de l'utilisation d'une moyenne glissante sauve_E_cin.Change_taille(taille_moyenne_glissante); nb_Ecin_stocker = 0;indice_EC1= 0; moyenne_glissante = 0.; moy_gliss_t = 0.; }; // méthode d'application de l'amortissement cinétique // on arrête l'amortissement lorsque E_cin_tdt < E_cin_t * pic_E_cint_t // on redémarre l'amortissement lorsque E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn // retour un int : // = 1 : il y a eu amortissement mais le calcul continue // = 0 : pas d'amortissement // = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait int Algori::AmortissementCinetique(const Vecteur & delta_ddl,const double& coef_mass,const Vecteur& X ,const Mat_abstraite& mat_mass,int icharge,Vecteur& V) {int relax_vit = 0; nb_depuis_derniere_relax++; // on incrémente à chaque passage // dans le cas où inter_nb_entre_relax dépend d'une fonction nD, on calcule sa valeur if (fct_nD_inter_nb_entre_relax != NULL) {int old_valeur = inter_nb_entre_relax; inter_nb_entre_relax = (fct_nD_inter_nb_entre_relax->Valeur_pour_variables_globales())(1); if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 1)) if (old_valeur != inter_nb_entre_relax) cout << "\n >>> changement de inter_nb_entre_relax de " << old_valeur << " en ==> "<< inter_nb_entre_relax; }; // // dans le cas où l'on veut un amortissement individuel aux noeuds, on appelle la méthode spécifique // int relax_vit_individuel = 0; // if (amortissement_cinetique_au_noeud && !relax_vit) // { relax_vit_individuel=AmortissementCinetique_individuel_aux_noeuds(delta_ddl,coef_mass,X,mat_mass,icharge,V);}; //*** je ne comprends pas le test que j'ai mis ici: abscon !! 16 oct 2018 // on ne continue que s'il n'y a pas d'amortissement cinétique en route if (!((icharge > nb_deb_test_amort_cinetique_noe) && amortissement_cinetique_au_noeud)) // ---- non la suite n'est pas bonne et converge beaucoup moins bien !! // je le remplace : on test si on est en amortissement cinétique, et que le nombre d'itérations // est suffisant /// if ((icharge > nb_deb_test_amort_cinetique_noe) && (!amortissement_cinetique_au_noeud) /// && amortissement_cinetique ) // --- fin modif avorté !!! { // if (!relax_vit_individuel) //// else // { // cout << "\n E_cin_t= " << E_cin_t << " E_cin_tdt= " << E_cin_tdt // << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn; // remarque: // compteur_decroit_pourRelaxDyn: indique combien de fois le test de pic a été effectué avec succés // si == -2 : indique que la procédure de test est gelé // si == 0 : indique que la procédure est active, et qu'il n'y a pas eu pour l'instant de pic détecté // si > 0 : indique que la procédure est active, et que, de manière consécutive, indique // le nombre de fois où il y a eu baisse bool relaxation_effectuee = false; // initialisation bool relaxation_reactive = false; // " if ((amortissement_cinetique)&&(icharge != 0) && (icharge > nb_deb_test_amort_cinetique)) { // on regarde si l'énergie cinétique a déjà été calculée, sinon on la calcule if (icharge < pa.NbIncrCalEnergie()) // ******* a revoir, car le test n'est peut-être pas suffisant avec tous les algos { // initialisation v_int.Change_taille(V.Taille()); v_int.Zero(); // calcul de l'énergie cinétique E_cin_tdt = (0.5/coef_mass) * (V * (mat_mass.Prod_vec_mat(V,v_int))); }; // on calcul éventuellement la moyenne glissante if (taille_moyenne_glissante > 1) { if (nb_Ecin_stocker < taille_moyenne_glissante) { // c'est le cas où la moyenne n'est pas finalisée nb_Ecin_stocker++; indice_EC1=1; sauve_E_cin(nb_Ecin_stocker) = E_cin_tdt; } else // cas ou la moyenne est finalisée { sauve_E_cin(indice_EC1) = E_cin_tdt; indice_EC1++; // mise à jour de l'indice pour le prochain stockage // si l'indice dépasse la taille du taille, on remet au début if (indice_EC1 > taille_moyenne_glissante) indice_EC1 = 1; }; // maintenant on regarde de nouveau si on peut calculer la moyenne if (nb_Ecin_stocker == taille_moyenne_glissante) {moy_gliss_t = moyenne_glissante; moyenne_glissante = sauve_E_cin.Moyenne();} else {moy_gliss_t= 0.; moyenne_glissante = 0.;}; // au cas où on met une valeur très grande }; // écriture d'info pour le débug au cas où if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3)) {if (taille_moyenne_glissante == 1) {cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn << " pic_E_cint_t= " << pic_E_cint_t << endl; } else {cout << "\n E_cin_tdt= " << E_cin_tdt << " compteur_decroit_pourRelaxDyn= " << compteur_decroit_pourRelaxDyn << " moyenne_glissante= " << moyenne_glissante << " moy_gliss_t= " << moy_gliss_t << " pic_E_cint_t= " << pic_E_cint_t << endl; }; }; // --- application de l'algo // a) dans le cas où la procédure a été gelée précédemment, on regarde // s'il faut la redémarrer if (compteur_decroit_pourRelaxDyn == -2) {if (E_cin_tdt > max_pic_E_cin * coef_redemarrage_pourRelaxDyn) {compteur_decroit_pourRelaxDyn = 0; // indique que l'amortissement est de nouveau active relaxation_reactive = true; }; }; // b) on regarde pour l'application de l'amortissement if (compteur_decroit_pourRelaxDyn != -2) // != -2 veut dire que la procédure est active {if (taille_moyenne_glissante == 1) { //debug ------ //cout << "\n E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl; // fin debug if ((E_cin_tdt > E_cin_t) && (E_cin_tdt > pic_E_cint_t)) //pic_E_cint_t) { //debug ------ //cout << "\n marquage d'un nouveau pic: E_cin_tdt " << E_cin_tdt << " , E_cin_t " << E_cin_t << " pic_E_cint_t " << pic_E_cint_t << endl; // fin debug pic_E_cint_t = E_cin_tdt; } //X_EcinMax = X; max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin); } else { if ((moyenne_glissante > moy_gliss_t) && (moyenne_glissante > pic_E_cint_t))//pic_E_cint_t) { pic_E_cint_t = moyenne_glissante; };// X_EcinMax = X; } max_pic_E_cin=MaX(pic_E_cint_t,max_pic_E_cin); }; // on considère qu'il y a décroissance, lorsque soit: // 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique // ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin // 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante // ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin // NB: si le pic_E_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide if ( ((test_fraction_energie == 0.) && ( ((taille_moyenne_glissante == 1) && (E_cin_tdt < pic_E_cint_t)) // cas sans moyenne glissante || ((taille_moyenne_glissante != 1) && (moyenne_glissante < pic_E_cint_t)) // cas avec moyenne glissante ) ) || ((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente ( ((taille_moyenne_glissante == 1) && (E_cin_tdt < (test_fraction_energie * pic_E_cint_t))) // cas sans moyenne glissante || ((taille_moyenne_glissante != 1) && (moyenne_glissante < (test_fraction_energie * pic_E_cint_t))) // cas avec moyenne glissante ) ) ) { //debug ------ //cout << "\n descente: E_cin_tdt " << E_cin_tdt << " pic_E_cint_t " << pic_E_cint_t << endl; // fin debug compteur_decroit_pourRelaxDyn++; if ((compteur_decroit_pourRelaxDyn >= max_nb_decroit_pourRelaxDyn) && (nb_depuis_derniere_relax >= inter_nb_entre_relax)) { // cas ou on met en place l'amortissement V.Zero();relaxation_effectuee=true; nb_depuis_derniere_relax = 0; dernier_pic = pic_E_cint_t; // on sauvegarde if (taille_moyenne_glissante != 1) // on remet tout à 0 {nb_Ecin_stocker = 0;indice_EC1= 0;}; relax_vit=1; compteur_pic_energie++; compteur_decroit_pourRelaxDyn=0; if ( dernier_pic == -1) // { if ( ((taille_moyenne_glissante != 1) && ( moyenne_glissante < dernier_pic*coef_arret_pourRelaxDyn)) // || ((taille_moyenne_glissante == 1) && ( E_cin_tdt < dernier_pic*coef_arret_pourRelaxDyn)) ) { pic_E_cint_t = 0.; // on remet à 0 le pic E_cin_tdt = 0.; } else { if ( dernier_pic < max_pic_E_cin*coef_arret_pourRelaxDyn) // if (E_cin_tdt <= pic_E_cint_t*coef_arret_pourRelaxDyn) // cas où on suspend l'amortissement pour la suite {compteur_decroit_pourRelaxDyn=-2;}; // inactive l'amortissement pic_E_cint_t = 0.; // on remet à 0 le pic E_cin_tdt = 0.; }; E_cinNoe_tdt.Zero(); pic_E_cint_t_noe.Zero(); }; } else // sinon cela signifie que la diminution n'est pas validée donc // on re-initialise le compteur de décroissance (qui sert à valider des décroissances consécutives) {compteur_decroit_pourRelaxDyn=0;}; // c) on regarde s'il faut arrêter le calcul, relativement au delta_ddl, seulement à partir d'un // certain nombre de fois que la méthode à été activé // ce qui permet d'éviter des pbs au démarrage, pour lequel l'énergie cinétique démarre forcément // de 0 puis petit à petit grandie // de plus on ne test le delta_ddl que: // 1) si on a passé au moins "un" pic d'énergie cinétique (sinon on peut avoir un deltat ddl = 0 car on est presqu'au // maxi et ce maxi = pas du tout l'équilibre !!) // non pour l'instant ... // 2) si l'énergie cinétique est suffisament faible compteur_test_pourRelaxDyn++; if (compteur_test_pourRelaxDyn > nb_deb_testfin_pourRelaxDyn) { if ((max_pic_E_cin != -1) || // on ajoute le cas très particulier où l'énergie cinétique reste nulle ((E_cin_tdt ==0.) && (E_cin_t==0.)) // c'est le cas où rien ne bouge !! ) { if (delta_ddl.Max_val_abs() <= max_deltaX_pourRelaxDyn) nb_dX_OK_pourRelaxDyn++; if (nb_dX_OK_pourRelaxDyn > nb_max_dX_OK_pourRelaxDyn) { relax_vit = -1; if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 6)) || (permet_affichage > 3)) cout << "\n critere en deplacement ok: max_deltaX= " << delta_ddl.Max_val_abs(); nb_dX_OK_pourRelaxDyn=0; // on initialise pour une prochaine fois // dans le cas ou l'arrêt réel n'est pas drivé par le déplacement // mais par exemple sur le résidu }; }; }; }; // -- fin du cas où l'on applique l'amortissement }; // on tente d'afficher que si l'amortissement a effectivement eu lieu // if (relax_vit && pa.AfficheIncrEnergie()) if (relaxation_effectuee) if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 2)) {cout << "\n N:" << icharge << " relaxation cinetique effectuee " << " pic_E_cint_t("< nb_deb_test_amort_cinetique_noe)) { // on va faire une boucle sur tous les noeuds int nbddl = delta_ddl.Taille(); int dim = ParaGlob::Dimension(); int NBN = nbddl / dim; // mise à jour des tailles if (E_cinNoe_tdt.Taille() == 0) { E_cinNoe_tdt.Change_taille(NBN,0.);E_cinNoe_t.Change_taille(NBN,0.); compteur_decroit_pourRelaxDyn_noe.Change_taille(NBN,0); dernier_pic_noe.Change_taille(NBN,-1); pic_E_cint_t_noe.Change_taille(NBN,-1); max_pic_E_cin_noe.Change_taille(NBN,-1); }; // un compteur de relaxation pour info int compteur_relaxation_ok=0; // init for (int noe =1; noe <= NBN; noe++) { // on calcul l'énergie pour le noeud bool relaxation_effectuee = false; // initialisation bool relaxation_reactive = false; // " double& eN_cin_tdt = E_cinNoe_tdt(noe); double& eN_cin_t = E_cinNoe_t(noe); double& pic_eN_cint_t = pic_E_cint_t_noe(noe); double& dernier_pic_eN = dernier_pic_noe(noe); eN_cin_tdt = 0.; // init int ptint = (noe-1)*dim; switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint); case 2: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint); case 1: ptint++; eN_cin_tdt += 0.5 * mat_mass(ptint,ptint) * V(ptint)*V(ptint); }; /* switch (dim) { case 3: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint); case 2: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint); case 1: ptint++; eN_cin_tdt += 0.5 * V(ptint)*V(ptint); }; */ // --- application de l'algo // a) dans le cas où la procédure a été gelée précédemment, on regarde // s'il faut la redémarrer double & max_pic_eN_cin = max_pic_E_cin_noe(noe); int & compt_decroit_pourRelaxDyn_noe = compteur_decroit_pourRelaxDyn_noe(noe); if (compt_decroit_pourRelaxDyn_noe == -2) {if (eN_cin_tdt > max_pic_eN_cin * coef_redemarrage_pourRelaxDyn_noe) {compt_decroit_pourRelaxDyn_noe = 0; // indique que l'amortissement est de nouveau active relaxation_reactive = true; }; }; // b) on regarde pour l'application de l'amortissement if (compt_decroit_pourRelaxDyn_noe != -2) // != -2 veut dire que la procédure est active { ////debug ------ //if (noe==220) //{ cout << "\n V(i)= "< eN_cin_t) && (eN_cin_tdt > pic_eN_cint_t)) //pic_eN_cint_t) { ////debug ------ //if (noe==220) //cout << "\n marquage d'un nouveau pic: eN_cin_tdt " << eN_cin_tdt << " , eN_cin_t " << eN_cin_t << " pic_eN_cint_t " << pic_eN_cint_t << endl; //// fin debug pic_eN_cint_t = eN_cin_tdt; }; //X_EcinMax = X; max_pic_eN_cin=MaX(pic_eN_cint_t,max_pic_eN_cin); }; // on considère qu'il y a décroissance, lorsque soit: // 1) on n'est pas en moyenne glissante et on a une décroissance de l'énergie cinétique // ou (si fraction != 0), l'énergie cinétique est inférieure à fraction * dernier_max_E_cin // 2) on est en moyenne glissante et on a une décroissance de la moyenne glissante // ou (si fraction != 0), la moyenne glissante est inférieure à fraction * dernier_max_E_cin // NB: si le pic_eN_cint_t a été updater dans le bloc précédent, le test qui suit ne peut pas être valide if ( ((test_fraction_energie == 0.) && (eN_cin_tdt < pic_eN_cint_t)) || ((test_fraction_energie != 0.) && // cas où on se réfère à une fraction de l'énergie maxi précédente (eN_cin_tdt < (test_fraction_energie * pic_eN_cint_t))) ) { //debug ------ //cout << "\n descente: eN_cin_tdt " << eN_cin_tdt << " pic_eN_cint_t " << pic_eN_cint_t << endl; // fin debug compt_decroit_pourRelaxDyn_noe++; if (compt_decroit_pourRelaxDyn_noe >= max_nb_decroit_pourRelaxDyn_noe) { // cas ou on met en place l'amortissement int depart = (noe-1)*dim+1; for (int i=0;i 7)) || (permet_affichage > 5)) {cout << "\n relax effectue au noeud " << noe << " pic_eN_cint_t("<0) // affichage global éventuel if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 2)) cout << "\n nb de relaxation individuelle effectuee: " << compteur_relaxation_ok; };// -- fin du cas où l'on applique l'amortissement return relax_vit; }; // pilotage de la convergence, ceci en fonction du type de pilotage choisit // ramène true si le pas de temps a été modifié, false sinon // arret = true: indique dans le cas d'une non convergence, neanmoins rien n'a changé, il faut donc arrêter bool Algori::Pilotage_du_temps(Charge* charge,bool& arret) { arret = false; // initialisation bool modif_pas_de_temps = false; // choix en fonction des différents cas switch (pa.TypeDePilotage()) { case AUCUN_PILOTAGE: // pas de pilotage {if (phase_de_convergence >= 0) // cas normal { // on regarde s'il faut augmenter le paramètre de charge if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence()) { // cas ou on augmente // modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation()); // réinitialisation pour la suite // nombre_de_bonnes_convergences = 0; // nombre_de_mauvaises_convergences = 0; } bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit // car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge } else { // cas ou l'incrément précédent n'a pas convergé // modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution()); // if (!modif_pas_de_temps) { // dans le cas où il n'y a pas de modification du pas de temps on le signale cout << "\n pas de pilotage ===> pas de modification possible du pas de temps"; arret = true; } bool etat_charge= charge->Avance();// à ne pas mettre dans l'expression qui suit // car si modif_pas_de_temps est true, il ne fera pas charge->avance(), à moins de le mettre en premier modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // increment de charge phase_de_convergence = 0; // initialisation pour repartir d'un bon pied } break; } case PILOTAGE_BASIQUE: case PILOT_GRADIENT : // cas du pilotage basique // et également pour le gradient pour l'instant {//cout << "\n phase de convergence " << phase_de_convergence << endl; if (phase_de_convergence >= 0) // cas normal {// on regarde s'il faut augmenter le paramètre de charge if (phase_de_convergence < 2) {if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence()) { // cas ou on augmente le pas de temps bool etat_charge= charge->Augmente_inc_charge(pa.Facteur_augmentation()); modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // réinitialisation pour la suite nombre_de_bonnes_convergences = 0;nombre_de_mauvaises_convergences=0; }; } else // cas la convergence n'a pas été bonne: phase_de_convergence >= 2 { // on va diminuer l'incrément bool etat_charge= charge->Diminue_inc_charge(pa.Fact_dim_en_mauvaiseConv()); modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); // réinitialisation pour la suite nombre_de_bonnes_convergences = 0; // on laisse le nombre de mauvaises convergence nombre_de_mauvaises_convergences = 0; // mais ça a convergé donc on met à 0 }; } else { // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps // on revient en arrière charge->Precedant(false); bool etat_charge= charge->Diminue_inc_charge(pa.Facteur_diminution()); modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); if (!modif_pas_de_temps) { // dans le cas où il n'y a pas de modification du pas de temps on le signale // l'arrêt sera traité par le programme appelant cout << "\n Pilotage ===> pas de modification possible du pas de temps"; arret = true; }; phase_de_convergence = 0; // initialisation pour repartir d'un bon pied } bool etat_charge= charge->Avance(); modif_pas_de_temps = (etat_charge || modif_pas_de_temps ); break; }; /* case PILOT_GRADIENT: // pour l'instant idem cas du pilotage basique {if (phase_de_convergence >= 0) // cas normal {// on regarde s'il faut augmenter le paramètre de charge if (nombre_de_bonnes_convergences > pa.Nb_bonne_convergence()) { // cas ou on augmente le pas de temps modif_pas_de_temps = charge->Augmente_inc_charge(pa.Facteur_augmentation()); // réinitialisation pour la suite nombre_de_bonnes_convergences = 0; } } else { // cas ou l'incrément précédent n'a pas convergé, diminution du pas de temps // on revient en arrière charge->Precedant(false); modif_pas_de_temps = charge->Diminue_inc_charge(pa.Facteur_diminution()); if (!modif_pas_de_temps) { // dans le cas où il n'y a pas de modification du pas de temps on le signale // l'arrêt sera traité par le programme appelant cout << "\n Pilotage ===> pas de modification possible du pas de temps"; arret = true; } phase_de_convergence = 0; // initialisation pour repartir d'un bon pied } charge->Avance(); // increment de charge break; } */ default: { cout << "\n erreur le cas de pilotage " << Nom_TypePilotage(pa.TypeDePilotage()) << " n'est pas implante !!! " << "\n Algori::Pilotage_du_temps(... "; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; }; // fin des différents cas de pilotage // retour de l'information sur la modification ou non du pas de temps //debug //cout << "\n Algori::Pilotage_du_temps: phase_de_convergence=" << phase_de_convergence // << " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences // << " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl ; //fin debug cout << flush; // pour que l'on puisse voir quelque chose ! en cours de calcul en particulier s'il y a pb return modif_pas_de_temps; }; // pilotage de la fin des itération en implicite : utilisation conjointe avec: Pilotage_du_temps() // ramène vraie si la convergence est correcte, sinon false bool Algori::Pilotage_fin_iteration_implicite(int compteur) { bool fin_iter = false; if (a_converge) { if (compteur < pa.Nb_iter_pour_bonne_convergence()) { // cas où le calcul a convergé en moins de pa.Nb_iter_pour_bonne_convergence nombre_de_bonnes_convergences++; // incrémentation de la bonne convergence nombre_de_mauvaises_convergences=0; phase_de_convergence = 1; //signalement pour Pilotage_du_temps } else if (compteur > (pa.Nb_iter_pour_mauvaise_convergence())) { // cas où on considère que la convergence n'a pas été bonne et qu'il vaut mieux diminuer l'incrément // pour la prochaine fois, on efface également le nombre de bonnes convergences nombre_de_bonnes_convergences = 0; nombre_de_mauvaises_convergences++; phase_de_convergence = 2; } else // cas où c'est ni très bon, ni très mauvais, on laisse en l'état { phase_de_convergence = 1; //signalement pour Pilotage_du_temps nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences=0; }; // nombre_de_mauvaises_convergences = 0; // dans tous les cas on a convergé fin_iter = true; // on signale qu'il y a eu convergence et que l'on a fini les itérations } else if (compteur > pa.Iterations()) { nombre_de_mauvaises_convergences++; nombre_de_bonnes_convergences = 0; if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n ******* NON convergence des iterations d'equilibre ********* " << "\n============================================================================"; } else { cout << "\n=============================================================================" << "\n *** NON convergence of the balance iteration ***** " << "\n============================================================================="; }; phase_de_convergence = -1; //signalement pour Pilotage_du_temps fin_iter = false; // on signale qu'il n'y a pas convergence } else if (phase_de_convergence == -2) // cas où c'est Convergence() qui est la cause de l'arret // pour cause d'évolution divergente des résidus { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n *** NON convergence equilibre: evolution divergente des residus ********* " << "\n============================================================================"; } else { cout << "\n=============================================================================" << "\n *** NON convergence of balance: divergente evolution of the residues ***** " << "\n============================================================================="; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -3) // cas où c'est Convergence() qui est la cause de l'arret // pour cause de variation de ddl minimal atteinte { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n *** NON convergence equilibre: variation de ddl minimal atteinte ********* " << "\n============================================================================"; } else { cout << "\n=============================================================================" << "\n *** NON convergence of balance: reaching of the minimum allowed of ddf ***** " << "\n============================================================================="; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -4) // cas où c'est Convergence() qui est la cause de l'arret // pour cause de variation de ddl maximal atteinte { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n *** NON convergence equilibre: variation de ddl maximum atteinte ********* " << "\n============================================================================"; } else { cout << "\n=============================================================================" << "\n *** NON convergence of balance: reaching of the maximum allowed of ddl ***** " << "\n============================================================================="; }; nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; fin_iter = false; // on signale qu'il n'y a pas convergence } else if (phase_de_convergence == -5) // cas d'un arrêt à cause d'un jacobien négatif, qui est géré { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n *** NON convergence due a la gestion de jacobien negatif ********* " << "\n============================================================================"; } else { cout << "\n============================================================================" << "\n *** NON convergence due to the management of negative jacobian ********* " << "\n============================================================================"; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -6) // cas d'un arrêt à cause d'une variation de jacobine trop grande { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n============================================================================" << "\n *** NON convergence due a une variation de jacobien trop grande ********* " << "\n============================================================================"; } else { cout << "\n============================================================================" << "\n *** NON convergence due to a too big variation of the jacobian ********* " << "\n============================================================================"; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -7) // cas d'un arrêt à cause d'une non convergence de la loi de comp { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) { cout << "\n============================================================================" << "\n *** NON convergence due a la loi de comportement ********* " << "\n============================================================================"; } else { cout << "\n============================================================================" << "\n *** NON convergence due to the material behaviour ********* " << "\n============================================================================"; }; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -8) // cas d'un arrêt à cause d'une non convergence de la loi de comp // mais pour un pb qui couve depuis plusieurs incréments { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) { cout << "\n============================================================================" << "\n *** NON convergence du a la loi de comportement ********* " << "\n *** probablement due a des erreurs sur plusieurs increments ********* " << "\n============================================================================"; } else { cout << "\n============================================================================" << "\n *** NON convergence due to the material behaviour ********* " << "\n *** probably due to errors along several increments ********* " << "\n============================================================================"; }; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -9) // cas d'un arrêt à cause d'un pb de la résolution du syteme linéaire { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) { cout << "\n==============================================================================" << "\n *** NON convergence due a un pb de resolution du systeme lineaire ********* " << "\n=============================================================================="; } else { cout << "\n=================================================================================" << "\n *** NON convergence due to the resolution of the global linear system ********* " << "\n================================================================================="; }; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -10) // cas d'un arrêt à cause d'un pb de calcul des efforts extérieurs { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) { cout << "\n==============================================================================" << "\n *** NON convergence due a un pb de calcul des efforts exterieurs ********* " << "\n=============================================================================="; } else { cout << "\n=================================================================================" << "\n *** NON convergence due to extern loading problem ********* " << "\n================================================================================="; }; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else if (phase_de_convergence == -11) // cas d'un arrêt à cause d'un nan ou infini sur forces ext, int { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) { cout << "\n==============================================================================" << "\n *** NON convergence due a un nan ou infini sur forces int, ext, totales ********* " << "\n=============================================================================="; } else { cout << "\n=================================================================================" << "\n *** NON convergence due to nan value ********* " << "\n================================================================================="; }; }; fin_iter = false; // on signale qu'il n'y a pas convergence nombre_de_bonnes_convergences=0; nombre_de_mauvaises_convergences++; } else // cas d'une erreur de pilotage: on ne sait pas pourquoi il s'est arrêté sans convergence { if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n cas de pilotage de fin d'iteration inconnues ? ou alors qui suit une erreur signalee precedemment "; if (ParaGlob::NiveauImpression() > 5) cout << "\n bool Pilotage_fin_iteration_implicite(int compteur) "; cout << endl; } else {cout << "\n unknown case of management for the end of iteration or, following an error "; if (ParaGlob::NiveauImpression() > 5) cout << "\n bool Pilotage_fin_iteration_implicite(int compteur) "; cout << endl; }; }; // si il ne s'agit pas d'une sortie voulue des itérations et incréments // on s'arrête if (!(pa.EtatSortieEquilibreGlobal())) { // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; // sinon on continue } return fin_iter; //debug if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n Algori::Pilotage_fin_iteration_implicite: phase_de_convergence=" << phase_de_convergence << " nombre_de_bonnes_convergences= " << nombre_de_bonnes_convergences << " nombre_de_mauvaises_convergences " << nombre_de_mauvaises_convergences << endl ; }; //fin debug }; // pilotage spécifique de la fin de la relaxation dynamique, en tenant compte des différents critères demandés // relax_vit_acce : // = 1 : il y a eu relaxation mais le calcul continue // = 0 : pas de relaxation // = -1 : on peut arrêter le calcul car le critère sur delta_ddl est satisfait // compteur: indique le nombre d'itération ou d'incrément en cours // iter_ou_incr : =1: il s'agit d'itération", =0 il s'agit d'incrément // lit arret, puis modifie arret en true ou false = il faut arrêter ou non // si true met à jour en interne certains paramètres de gestion de pilotage pour dire que l'on a bien convergé bool Algori::Pilotage_fin_relaxation_et_ou_residu(const int& relax_vit_acce,const int& iter_ou_incr, const int& compteur, const bool& arretResidu, bool& arret) { // pour mémoire: arret_a_equilibre_statique indique, si diff de 0, que l'on veut contrôler une convergence vers la solution // statique. Si = 1: le residu statique est utilise comme critere // si = 2: nécessite que les deux critères précédents soient satisfait // examen de la convergence éventuelle, utilisant le déplacement et/ou le résidu string nom="l'iteration"; if (!iter_ou_incr) nom = "l'increment"; switch (relax_vit_acce) { case -1: // cas où le critère en déplacement est ok {if (!arret_a_equilibre_statique) // cas ou on ne considère pas l'équilibre en résidu {arret=true;a_converge = true; cout << "\n critere en deplacement satisfait pour "<< nom << " : " << compteur << " max_deltaX= " < 3)) || (permet_affichage > 2)) if (sursousrelax != 1.) {if(ParaGlob::Francais()) {cout << "\n intervention d'une sur-sous relaxation: ";} else {cout << "\n intervention of an over or under relaxation: ";}; cout << sursousrelax; }; // --limitation de la norme de delta ddl // dans le cas où le maxi de variation de ddl est supérieur à la limite fixée on ramène la valeur if (pa.NormeMax_increment() > 0.) {// cas d'une limitation globale (tout le vecteur sol change if (maxDeltaDdl > pa.NormeMax_increment()) { double facteur=(pa.NormeMax_increment()/maxDeltaDdl); if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof ";}; cout << facteur; }; (*sol) *= facteur; // mise à jour du maxi de variation de ddl maxDeltaDdl = pa.NormeMax_increment(); }; } else // ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées {// cas d'une limitation globale (tout le vecteur sol change if (maxDeltaDdl > Abs(pa.NormeMax_increment())) { double maxa= Abs(pa.NormeMax_increment()); Vecteur & vect = *sol; // pour simplifier int taill=vect.Taille(); bool modif = false; for (int i=1;i<= taill;i++) { if (Abs(vect(i)) > maxa) { vect(i) = Signe(vect(i),maxa); modif = true;}; }; if (modif) {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur increment de ddl, limitation des maxis ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector increment of dof, limitation of the maxis ";}; }; }; // mise à jour du maxi de variation de ddl maxDeltaDdl = maxa; }; }; // -- indication de précision pour les éléments (utilisée pour certain type de gestion d'hourglass) // pour l'instant l'idée est la suivante: si le résidu augmente => on demande un calcul précis sur les éléments // pour le prochain calcul int nb_cycle_controle = MaX(2,pa.NbCycleControleResidu()); if (itera == 0) { lesMail->Drapeau_preparation_calcul_precis(10);} // par défaut à l'itération 0 on demande un calcul précis if (itera > 1) { bool change = false; // indicateur pour la demande d'un calcul précis if (itera <= nb_cycle_controle) { if (max_var_residu(itera) > max_var_residu(itera-1)) change = true;} else { if (max_var_residu(nb_cycle_controle) > max_var_residu(nb_cycle_controle-1)) change = true;}; if (change) // dans le cas où le résidu augmente => on demande un calcul précis sur les éléments { lesMail->Drapeau_preparation_calcul_precis(4);} else {lesMail->Drapeau_preparation_calcul_precis(4);}; // sinon pas de modif }; }; // pilotage pour l'initialisation de Xtdt à chaque début d'incrément, en implicite // avec la même direction qu'au pas précédent // ramène true, si c'est ok pour initialiser Xtdt bool Algori::Pilotage_init_Xtdt() { return (nombre_de_mauvaises_convergences <= 2); }; // pilotage en dynamique implicite, du maxi des déplacements et/ou vitesses // limitation spécifiquement des maxi en déplacements et/ou vitesses // il y a calcul éventuel de delta_X, mais c'est considéré comme une variable de travail void Algori::Pilotage_maxi_X_V(const Vecteur& X_t,Vecteur& X_tdt,const Vecteur& V_t,Vecteur& V_tdt) { // --limitation de la norme de delta X // dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur double normeMax_X_increment = pa.NormeMax_X_increment(); if ((normeMax_X_increment > 0.)&&( normeMax_X_increment!= ConstMath::tresgrand)) {// cas d'une limitation globale sur X if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille()); vec_trav = X_tdt; vec_trav -= X_t; double maxDeltaDdl=vec_trav.Max_val_abs(); if (maxDeltaDdl > normeMax_X_increment) { double facteur=(normeMax_X_increment/maxDeltaDdl); if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur delta X ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X ";}; cout << facteur << "( maxDeltaX= " << maxDeltaDdl<<")"; }; vec_trav *= facteur; X_tdt = X_t; X_tdt += vec_trav; }; } else if ( normeMax_X_increment!= ConstMath::tresgrand) // cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées {// cas d'une limitation globale (tout le vecteur sol change int taill=X_t.Taille(); if (vec_trav.Taille() != X_t.Taille()) vec_trav.Change_taille(X_t.Taille()); vec_trav = X_tdt; vec_trav -= X_t; double maxDeltaDdl=vec_trav.Max_val_abs(); if (maxDeltaDdl > -normeMax_X_increment) { double maxa= -normeMax_X_increment; bool modif = false; for (int i=1;i<= taill;i++) { if (Abs(vec_trav(i)) > maxa) { vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;}; }; if (modif) {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur delta X, limitation des maxis ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector delta X, limitation of the maxis ";}; }; X_tdt = X_t; X_tdt += vec_trav; }; }; }; // --limitation de la norme de delta V // dans le cas où le maxi de variation de delta est supérieur à la limite fixée on ramène la valeur double normeMax_V_increment = pa.NormeMax_V_increment(); if ((normeMax_V_increment > 0.)&&( normeMax_V_increment!= ConstMath::tresgrand)) {// cas d'une limitation globale sur V if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille()); vec_trav = V_tdt; vec_trav -= V_t; double maxDeltaDdl=vec_trav.Max_val_abs(); if (maxDeltaDdl > normeMax_V_increment) { double facteur=(normeMax_V_increment/maxDeltaDdl); if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 2)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur delta V ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V ";}; cout << facteur ; }; vec_trav *= facteur; V_tdt = V_t; V_tdt += vec_trav; }; } else if ( normeMax_V_increment!= ConstMath::tresgrand) // cas négatif ici il s'agit d'un écrétage, seule les composantes supérieures au maxi, sont écrètées {// cas d'une limitation globale (tout le vecteur sol change int taill=V_t.Taille(); if (vec_trav.Taille() != V_t.Taille()) vec_trav.Change_taille(V_t.Taille()); vec_trav = V_tdt; vec_trav -= V_t; double maxDeltaDdl=vec_trav.Max_val_abs(); if (maxDeltaDdl > -normeMax_V_increment) { double maxa= -normeMax_V_increment; bool modif = false; for (int i=1;i<= taill;i++) { if (Abs(vec_trav(i)) > maxa) { vec_trav(i) = Signe(vec_trav(i),maxa); modif = true;}; }; if (modif) {if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 4)) || (permet_affichage > 0)) {if(ParaGlob::Francais()) {cout << "\n ===>>>>> intervention de la reduction du vecteur delta V, limitation des maxis ";} else {cout << "\n ===>>>>> intervention of the reduction for the vector delta V, limitation of the maxis ";}; }; V_tdt = V_t; V_tdt += vec_trav; }; }; }; }; // passage des grandeurs gérées par l'algorithme de tdt à t // en particulier les énergies et les puissances void Algori::TdtversT() { // cas du calcul des énergies, passage des grandeurs de tdt à t // les énergies globales E_cin_t=E_cin_tdt; E_int_t = E_int_tdt; E_ext_t = E_ext_tdt; // la quantité de mouvement globale q_mov_t = q_mov_tdt; // les forces internes et externes généralisées F_int_t = F_int_tdt; F_ext_t = F_ext_tdt; // l'énergie visqueuse numérique E_visco_numerique_t=E_visco_numerique_tdt; // les puissances P_acc_t = P_acc_tdt; P_int_t = P_int_tdt; P_ext_t = P_ext_tdt; bilan_P_t = bilan_P_tdt; // cas particulier de l'amortissement cinétique à chaque noeud if (amortissement_cinetique_au_noeud) E_cinNoe_t = E_cinNoe_tdt; }; // vérification d'une singularité éventuelle de la matrice de raideur de dim: nbddl // pour un problème de mécanique, en comparant le nombre de point d'intégration total // et le nombre totale de degré de liberté void Algori::VerifSingulariteRaideurMeca(int nbddl,const LesMaillages& lesMail) const { #ifdef UTILISATION_MPI // cas d'un calcul //, seule la matrice du CPU 0 est concernée if (ParaGlob::Monde()->rank() != 0) return ; #endif if (ParaGlob::NiveauImpression() != 0) { // récup du nombre de grandeurs génératrices // Enum_ddl enu(SIG11); // init par défaut // on récupère la liste des problèmes physiques gérés par les éléments de tous les maillages const list & li = lesMail.Ddl_representatifs_des_physiques(); // on boucle sur la liste list ::const_iterator ili,iliend = li.end(); int nbpt=0; // init for (ili = li.begin();ili != iliend; ili++) nbpt += lesMail.NbTotalGrandeursGeneratrices(*ili); // affichage const double ratio = 1.2; // le pourcentage if (nbpt < ratio * nbddl) if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 0)) || (permet_affichage > 0)) { cout << "\n *** Attention, le nombre total de grandeurs generatrices aux point d'integrations dans " << " le probleme: " << nbpt << " est inferieur " << " a " << ratio << " * le nombre total de ddl du probleme !! c-a-d: "<< int(ratio * nbddl) << "\n en consequence il est possible que la matrice de raideur soit naturellement singuliere \n\n "; if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 7)) || (permet_affichage > 0)) cout << "\n void Algori::VerifSingulariteRaideurMeca(... "; }; }; }; // retouve le numéro de l'incrément sauvegardé trouvé dont le numéro est juste inf ou égale au // dernier incrément calculé - nb_incr_en_arriere. // ramène false si on n'a pas trouvé d'incrément a-doc // en retour icharge prend la valeur de l'incrément trouvé (si tout c'est bien passé) bool Algori::Controle_retour_sur_un_increment_enregistre(int nb_incr_en_arriere,int& icharge) { // tout d'abord on calcul le numéro d'incrément auquel il faut se placer List_io ::iterator inc_ok = list_incre_temps_calculer.begin(); List_io ::iterator inc_fin = list_incre_temps_calculer.end(); for (int i=1;i<=nb_incr_en_arriere;i++) if (inc_ok != inc_fin) {inc_ok++; } // les incréments sont rangés du dernier vers le premier else {return false;}; // sinon l'opération n'est pas possible // donc inc_ok représente maintenant le num maxi à partir duquel on va chercher un incrément enregistré List_io ::iterator in_sauve = list_incre_temps_sauvegarder.begin(); List_io ::iterator in_sauve_fin = list_incre_temps_sauvegarder.end(); // on recherche le premier incrément sauvegardé juste inf à celui que l'on s'est fixé while (((*in_sauve).n > (*inc_ok).n)&&(in_sauve != in_sauve_fin)) in_sauve++; // on vérifie que l'incrément est valide sinon on est obligé d'arrêter if (in_sauve == in_sauve_fin) {return false;}; // opération non possible // sinon c'est ok icharge = (*in_sauve).n; return true; }; // cohérence du type de convergence adopté en fonction de l'algorithme: par exemple on vérifie que l'on n'utilise // pas une convergence sur l'énergie cinétique avec un algo statique !! void Algori::Coherence_Algo_typeConvergence() { if ((Evolution_temporelle_du_calcul(typeCalcul) != DYNAMIQUE) && (strstr(pa.Norme().nom1.c_str(),"E_cinetique/E_statique")) && (Evolution_temporelle_du_calcul(typeCalcul) != AUCUNE_EVOLUTION)) { cout << "\n *** erreur: utilisation de la norme E_cinetique/E_statique avec un calcul non dynamique" << " arret ! "; if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5)) || (permet_affichage > 0)) cout << "\n Algori::Coherence_Algo_typeConvergence() "; // dans le cas où un comptage du calcul est en cours on l'arrête if (tempsCalEquilibre.Comptage_en_cours()) tempsCalEquilibre.Arret_du_comptage(); Sortie(1); }; };