// 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 "Algo_zero.h" // contiend que les méthodes qui ne sont pas des templates #include "MathUtil.h" #include "ConstMath.h" // CONSTRUCTEURS : // constructeur par défaut Algo_zero::Algo_zero() : prec_res_abs(1.e-3) // précision absolue par défaut sur le résidu ,prec_res_rel(1.e-3) // précision relative par défaut sur le résidu ,iter_max(20) // nombre d'itération maxi pour un incrément ,coef_mini_delta_x(ConstMath::pasmalpetit) // précision relative sur le mini de l'incrément de x ,mini_delta_x( ConstMath::trespetit) // minimum de delta x permis ,maxi_delta_x(ConstMath::pasmalgrand) // maximum de delta x permis ,nbMaxiIncre(20) // nombre maxi d'incrément permis ,maxi_test_moins1(2) ,permet_affichage(0) {} // constructeur de copie Algo_zero::Algo_zero(const Algo_zero& a) : prec_res_abs(a.prec_res_abs),prec_res_rel(a.prec_res_rel) ,iter_max(a.iter_max),coef_mini_delta_x(a.coef_mini_delta_x) ,mini_delta_x(a.mini_delta_x),maxi_delta_x(a.maxi_delta_x),nbMaxiIncre(a.nbMaxiIncre) ,maxi_test_moins1(a.maxi_test_moins1) ,permet_affichage(a.permet_affichage) {} // DESTRUCTEUR : Algo_zero::~Algo_zero() {} // METHODES PUBLIQUES : // initialisation de tous les paramètres à leurs valeurs par défaut void Algo_zero::Init_param_val_defaut() { prec_res_abs = 1.e-3 ; // précision absolue par défaut sur le résidu prec_res_rel = 1.e-3 ; // précision relative par défaut sur le résidu iter_max = 20; // nombre d'itération maxi pour un incrément coef_mini_delta_x = ConstMath::pasmalpetit; // précision relative sur le mini de l'incrément de x mini_delta_x = ConstMath::trespetit; // minimum de delta x permis maxi_delta_x = ConstMath::pasmalgrand ; // maximum de delta x permis nbMaxiIncre = 20; // nombre maxi d'incrément permis maxi_test_moins1 = 2; permet_affichage = 0; // niveau par défaut d'affichage } // affichage à l'écran des infos void Algo_zero::Affiche() const { cout << "\n Algo_zero:_parametres: " << " prec_res_abs= " << prec_res_abs << " prec_res_rel= " << prec_res_rel << " iter_max= " << iter_max << " coef_mini_delta_x= " << coef_mini_delta_x << " mini_delta_x= " << mini_delta_x << " maxi_delta_x= " << maxi_delta_x << " nbMaxiIncre= " << nbMaxiIncre << " maxi_test_moins1= "<< maxi_test_moins1 << " permet_affichage " << permet_affichage << endl; }; //----- lecture écriture de restart ----- // cas donne le niveau de la récupération // = 1 : on récupère tout // = 2 : on récupère uniquement les données variables (supposées comme telles) void Algo_zero::Lecture_base_info (ifstream& ent,const int cas) { if (cas == 1) {string nom; ent >> nom; if (nom != "Algo_zero:_para:") { cout << "\n erreur en lecture des parametres d'Algo_zero, on devait lire le mot clef " << "Algo_zero:_para: et on a lu "<< nom << endl; Sortie(1); }; ent >> nom >> prec_res_abs >> nom >> prec_res_rel >> nom >> iter_max >> nom >> coef_mini_delta_x >> nom >> mini_delta_x >> nom >> maxi_delta_x >> nom >> nbMaxiIncre >> nom >> maxi_test_moins1; ent >> nom >> permet_affichage; }; }; // cas donne le niveau de sauvegarde // = 1 : on sauvegarde tout // = 2 : on sauvegarde uniquement les données variables (supposées comme telles) void Algo_zero::Ecriture_base_info(ofstream& sort,const int cas) { if (cas==1) {sort << "\n Algo_zero:_para:" << " prec_res_abs= " << prec_res_abs << " prec_res_rel= " << prec_res_rel << " iter_max= " << iter_max << " coef_mini_delta_x= " << coef_mini_delta_x << " mini_delta_x= " << mini_delta_x << " maxi_delta_x= " << maxi_delta_x << " nbMaxiIncre= " << nbMaxiIncre << " maxi_test_moins1= "<< maxi_test_moins1 << " permet_affichage= " << permet_affichage << endl; }; }; // recherche du zéro d'une équation du second degré dans l'espace des réels: ax^2+bx+c=0. // cas indique les différents cas: // = 1 : il y a deux racines, racine2 > racine1 // = 2 : il y a une racine double: racine1=racine2 // = 0 : pas de racine // = -1 : pas de racine car a,b,c sont tous inférieur à la précision de traitement // = -2 : pas de racine car a,b sont inférieur à la précision de traitement tandis que c est non nul // = -3 : une racine simple car a est inférieur à la précision de traitement, donc considéré comme nul // b et c sont non nul -> equa du premier degré, solution: racine1 void Algo_zero::SecondDegre(double a, double b, double c1, double& racine1, double& racine2, int& cas) const { // 1== on regarde tout d'abord si ce n'est pas une équation du premier degré if (Dabs(a) <= ConstMath::trespetit) { // on regarde si le coeff restant de x n'est pas nul if ( Dabs(b) <= ConstMath::trespetit) { // on regarde si le terme constant est nul if (Dabs(c1) <= ConstMath::trespetit) // pas de solution possible mais l'équation est valide à ConstMath::trespetit près { cas = -1;} else // pas de solution possible et l'équation n'est pas possible { cas = -2;} } else // b est non nul et l'équation est du premier degré { cas = -3; racine1= -c1/b; racine2=racine1; return;}; }; // 2== maintenant on est sur d'avoir une équa du second degré // calcul du discriminant double delta = b*b - 4. * a * c1; // choix en fonction de la valeur du discriminant if (delta < 0.) { // on regarde si l'on est près de la précision de la machine if (Dabs(delta/a) <= 1000*ConstMath::trespetit) { // dans ce cas on met delta à 0 cas = 2; racine1 = (-b)/(2.*a); racine2=racine1; } else // pas de solution {cas = 0;} } else if (delta == 0.) { // une solution double cas = 2; racine1 = (-b)/(2.*a); racine2=racine1; } else { // deux racines séparées cas = 1; double r = sqrt(delta); racine1 = (-b-r)/(2.*a);racine2 = (-b+r)/(2.*a); }; }; // recherche du zéro d'une équation du troisième degré dans l'espace des réels: ax^3+bx^2+cx+d=0. // cas indique les différents cas: // = 1 : il y a deux racines , racine2 > racine1 // = 2 : il y a une racine double // = 3 : il y a une seule racine réelle racine1 (et deux complexes non calculées) // = 4 : il y a une racine simple: racine1, et une racine double: racine 2 // = 5 : il y a 3 racines réelles: racine1, racine2, racine3 // = 0 : pas de racine // = -1 : pas de racine car a,b,c sont tous inférieur à la précision de traitement // = -2 : pas de racine car a,b sont inférieur à la précision de traitement tandis que c est non nul // = -3 : une racine simple car a est inférieur à la précision de traitement, donc considéré comme nul // b et c sont non nul -> equa du premier degré, solution: racine1 void Algo_zero::TroisiemeDegre(double a, double b, double c1, double d, double& racine1, double& racine2, double& racine3, int& cas) { // 1== on regarde tout d'abord si ce n'est pas une équation du second degré if (Dabs(a) <= ConstMath::trespetit) { // appel de la résolution d'une équation du second degré SecondDegre(b,c1,d,racine1,racine2,cas); #ifdef MISE_AU_POINT if (cas==1) {if ((Dabs(racine1) > ConstMath::pasmalgrand) || (Dabs(racine2) > ConstMath::pasmalgrand) ) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1 << " " << racine2; } } else {if (Dabs(racine1) > ConstMath::pasmalgrand) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1; } }; #endif } else { // cas d'une réelle équation du 3ième degré // on normalise l'équation par a; double bb = b/a; double cc1 = c1/a;double dd = d/a; // on appelle la routine de quartic double v3[4];// les racines int nb_root= algo_quartic.cubic(bb,cc1,dd,v3); // on recopie les racines cas = nb_root+2; switch (nb_root) { case 3: racine3=v3[2]; /* #ifdef MISE_AU_POINT double x=racine3; if (Dabs(x*x*x + bb*x*x +cc1*x+dd) > ConstMath::petit) { cout << "\n erreur la troisieme racine de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + bb*x*x +cc1*x+dd) << "\n Algo_zero::TroisiemeDegre(.."; } #endif*/ case 2: racine2=v3[1]; /* #ifdef MISE_AU_POINT x=racine2; if (Dabs(x*x*x + bb*x*x +cc1*x+dd) > ConstMath::petit) { cout << "\n erreur la seconde racine de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + bb*x*x +cc1*x+dd) << "\n Algo_zero::TroisiemeDegre(.."; } #endif*/ case 1: racine1=v3[0]; /* #ifdef MISE_AU_POINT x=racine1; if (Dabs(x*x*x + bb*x*x +cc1*x+dd) > ConstMath::petit) { cout << "\n erreur la premiere racine de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + bb*x*x +cc1*x+dd) << "\n Algo_zero::TroisiemeDegre(.."; } #endif*/ break; default: cout << "\n erreur pas de racine pour l'equation cubique !" << "\n Algo_zero::TroisiemeDegre(.."; Sortie(1); } }; // cout << "\n résolution 3 degré cas= " << cas << " racine1= " << racine1 // << " racine2= " << racine2 << " racine3= " << racine3; }; /* void Algo_zero::TroisiemeDegre(double a, double b, double c1, double d, double& racine1, double& racine2, double& racine3, int& cas) const { // 1== on regarde tout d'abord si ce n'est pas une équation du second degré if (Dabs(a) <= ConstMath::trespetit) { // appel de la résolution d'une équation du second degré SecondDegre(b,c1,d,racine1,racine2,cas); #ifdef MISE_AU_POINT if (cas==1) {if ((Dabs(racine1) > ConstMath::pasmalgrand) || (Dabs(racine2) > ConstMath::pasmalgrand) ) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1 << " " << racine2; } } else {if (Dabs(racine1) > ConstMath::pasmalgrand) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1; } }; #endif } else { // cas d'une réelle équation du 3ième degré // on normalise l'équation par a; a=1.; b/=a; c1/=a;d/=a; // on commence par regarder si ce n'est pas une racine triple // si p est nulle il n'y a qu'une seule racine double lambda = -b/3.; if (( Dabs(c1- 3.*lambda*lambda) <= 100.*ConstMath::trespetit) && ( Dabs(d + lambda*lambda*lambda) <= 100.*ConstMath::trespetit)) { // cas d'une racine tripe cas = 3; racine1=racine2=racine3=lambda; #ifdef MISE_AU_POINT double x=racine1; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la racine triple de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } #endif return; } // cas où on n'a pas de racine triple double r1=-b/(3.*a); //double x= r1 + y double b2=b*b; double a2=a*a;double b3=b2*b; double a3=a*a2; double p = (3*a*c1-b2)/(3.*a2); double q = (2.*b3+27.*a2*d-9.*a*b*c1)/(27.*a3); double p3 = p*p*p; double q2=q*q; double s=4.*p3 + 27.*q2; if (s>0.) { // cas d'une seule racine réelle: racine1 double dd=sqrt(s/27.); double untier=1./3.; // résolution des pb de petits nombres ou de nombres négatifs double ddmoinsq=(-q+dd); double signeddmoinsq=1.; if (ddmoinsq < 0.) signeddmoinsq=-1.; ddmoinsq = Dabs(ddmoinsq); double qPlusDd =(q+dd); double signeqPlusDd=1.; if (qPlusDd < 0.) signeqPlusDd=-1.; qPlusDd = Dabs(qPlusDd); // si le nombre est trop petit le log tend vers -l'infini if (ddmoinsq <= 100.*ConstMath::trespetit) {ddmoinsq=1.;signeddmoinsq=0.;}; if (qPlusDd <= 100.*ConstMath::trespetit) {qPlusDd=1.;signeqPlusDd=0.;}; double y = signeddmoinsq * pow(ddmoinsq*0.5,untier) -signeqPlusDd*pow(qPlusDd*0.5,untier); // tout ça à la place de l'expression qui suit !! // double y = pow((-q+dd)*0.5,untier)+pow(-(q+dd)*0.5,untier); racine1=racine2=racine3=r1+y; #ifdef MISE_AU_POINT if (Dabs(racine1) > ConstMath::pasmalgrand) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1; } #endif #ifdef MISE_AU_POINT double x=racine1; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la racine simple de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } #endif cas= 3; } else if (s == 0.) { // cas où il y a une racine simple: racine 1, et une racine double: racine2 double y1= 3.*q/p; double y2=-y1/2.; racine1=r1+y1; racine2=r1+y2; cas = 4; #ifdef MISE_AU_POINT if ((Dabs(racine1) > ConstMath::pasmalgrand) || (Dabs(racine2) > ConstMath::pasmalgrand) ) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1 << " " << racine2; } #endif #ifdef MISE_AU_POINT double x=racine1; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la racine simple premiere de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } x=racine2; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la racine double de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } #endif } else // cas où s < 0. { // cas où il y a trois racines réelles double dd=sqrt((-4.*p3+27.*q2)/27.); double r=2.*sqrt(-p/3.); double teta1=ConstMath::Pi/2.; if (Dabs(q) > 10*ConstMath::trespetit)teta1 = atan(-dd/q); if (cos(teta1)*(-q) < 0) teta1 +=ConstMath::Pi/2; // if (q<0.) {teta1 = atan(-dd/q);} // else if (q>0.) {teta1 = atan(-dd/q) + ConstMath::Pi;}; // // sinon teta1=pi/2 ce qui est déjà le cas double y1=r*cos(teta1/3.); double y2=r*cos(teta1/3.+2.*ConstMath::Pi/3.); double y3=r*cos(teta1/3.+4.*ConstMath::Pi/3.); racine1=r1+y1; racine2=r1+y2; racine3=r1+y3; cas = 5; #ifdef MISE_AU_POINT if ((Dabs(racine1) > ConstMath::pasmalgrand) || (Dabs(racine2) > ConstMath::pasmalgrand) || (racine3 > ConstMath::pasmalgrand)) { cout << "\n sans doute erreur dans le calcul des racines de l'equation du 3ieme degre" << "\n resultat trop grand " << racine1 << " " << racine2 << " " << racine2; } #endif #ifdef MISE_AU_POINT double x=racine1; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la premiere racine (des 3) de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } x=racine2; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la seconde racine (des 3) de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } x=racine3; if (Dabs(x*x*x + b*x*x +c1*x+d) > ConstMath::petit) { cout << "\n erreur la troisieme racine (des 3) de l'equation du 3ieme degre est fausse equa= " << Dabs(x*x*x + b*x*x +c1*x+d); } #endif }; }; } */