431 lines
19 KiB
C++
Executable file
431 lines
19 KiB
C++
Executable file
// 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) <https://www.irdl.fr/>.
|
|
//
|
|
// Herezh++ is distributed under GPL 3 license ou ultérieure.
|
|
//
|
|
// Copyright (C) 1997-2021 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 <https://www.gnu.org/licenses/>.
|
|
//
|
|
// For more information, please consult: <https://herezh.irdl.fr/>.
|
|
|
|
#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
|
|
};
|
|
};
|
|
}
|
|
*/
|