// 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 "MathUtil2.h"
//#include "nrutil.h"
//#include "jacobi.h"
#include "Util.h"
#include "ConstMath.h"
#include "MathUtil.h"
#ifndef MATHUTIL2_H_deja_inclus
//// vecteurs propre et valeurs propres d'une matrice nxn c-a-d : en particulier 3 3 ou 2 2 ou 1 1
//// avec une limitation sur n (< 50)
//// *** dans le cas où les matrices sont symétriques !! ***
//// la méthode est itérative, --> méthode de Jacobi
//// la matrice A est ecrasee, a la sortie chaque colonne represente un vecteur propre
//// le vecteur de retour contiend les valeurs propres
//// s'il y a une erreur dans le calcul : cas = -1
//#ifndef MISE_AU_POINT
// inline
//#endif
//Vecteur MathUtil2::VectValPropre(Mat_pleine& A,int& cas)
// { // appel d'une routine jacobi
// int nbcol = A.Nb_colonne();
// #ifndef MISE_AU_POINT
// int nblign = A.Nb_ligne();
// if (nbcol != nblign)
// { cout << "\n erreur dans VectValPropre(Mat_pleine& A), la matrice n'est pas carré"
// << endl;
// Sortie(1);
// }
// #endif
//
// // 1) def de la matrice et du vecteur contenant les vecteurs propre et les valeurs propres
// Vecteur d(nbcol);
// Mat_pleine V(nbcol,nbcol);
// int nrot =0; // nombre de rotation dans jacobi
//
// // 3) appel du programme de la bibliothèque (fortement modifié)
// Jacobi jaco; // une instance par défaut
//
// jaco.jacobi(A,d,V,nrot);
// // traitement erreur
// if (nrot == -1) {cas = -1;} else {cas = 1;};
//
// // 4) mise en ordre des valeurs et vecteurs propres
// jaco.eigsrt(d,V);
// // 5) sauvegarde et retour
// A = V;
// return d;
// };
//
//calcul des vecteurs propres pour une matrice 3x3 réel uniquement, pas forcément symétrique
// dans le cas où on connait déjà les valeurs propres
// --> Utilisable que pour des matrices carrées
// en entrée : VP, de dimension 3, Vp contient les valeurs propres
// les 3 valeurs propres sont considérées classées: VP(1) >= VP(2) >= VP(3)
// cas : qui indique le type de valeurs propres
// , cas = 1 si 3 val propres différentes (= 3 composantes du vecteur de retour)
// , cas = 0 si les 3 sont identiques (= la première composantes du vecteur de retour),
// , cas = 2 si Vp(1)=Vp(2) ( Vp(1), et Vp(3) dans les 2 premières composantes du retour)
// , cas = 3 si Vp(2)=Vp(3) ( Vp(1), et Vp(2) dans les 2 premières composantes du retour)
// en sortie : le tableau des vecteurs propres, rangés selon l'ordre d'entrée
// cas = le cas de l'entrée, sauf s'il y a eu un pb, dans ce cas: cas = -1, et les vecteurs propres sont
// dans ce cas quelconques
//
#ifndef MISE_AU_POINT
inline
#endif
Tableau MathUtil2::V_Propres3x3(const Mat_pleine& A,const Coordonnee & VP, int & cas )
{
#ifdef MISE_AU_POINT
if ((A.Nb_colonne() != 3)|| (A.Nb_ligne() != 3))
{cout << "\n erreur de dimension: Nb_colonne()= " << A.Nb_colonne() << ", Nb_ligne()= ";
cout << A.Nb_ligne() << " alors que cette methode ne s'applique qu'aux matrices 3x3 ! "
<< "\n V_Propres3x3(..." << endl;
Sortie(1);
};
if (VP.Dimension() != 3)
{cout << "\n erreur il n'y a pas 3 valeurs propres ! " << endl;
Sortie(1);
};
if ( (VP(1) < VP(2)) || (VP(2) < VP(3)) || (VP(1) < VP(3)) )
{cout << "\n erreur les trois valeurs propres ne sont pas dans le bon ordre (VP(1) >= VP(2) >= VP(3)) "
<< "\n VP(1)= " << VP(1) << ", VP(2)= " << VP(2) << ", VP(3)= " << VP(3)
<< "\n V_Propres3x3(..." << endl;
Sortie(1);
};
#endif
// initialisation
Coordonnee3 zero(3);
Tableau Vpropre(3,zero); // les vecteurs propres
// on utilise une copie de la matrice d'entrée
Mat_pleine B(A);
// dans tous les cas il y a au moins une valeur propre, on démarre avec celle là
// on calcul la matrice B-lambda*Id qui normalement doit-être singulière
////---debug
//cout << "\n debug V_Propres3x3 ";
//cout <<"\n B: ";
//B.Affiche();
//// --- fin debug
for (int i=1;i<=3;i++)
B(i,i) -= VP(1);
////---debug
//cout << "\n debug V_Propres3x3 apres B(i,i) -= VP(1)";
//cout <<"\n B: ";
//B.Affiche();
//// --- fin debug
// on calcul le rang de la matrice
int rang_B = CalculRangMatrice3x3Singuliere(B);
//---debug
//cout << "\n debug V_Propres3x3 ";
//cout <<"\n rangB: "< 7) "
<< "\n VP: ";
if (ParaGlob::NiveauImpression() > 7)
{ VP.Affiche();
cout <<"\n A: ";
A.Affiche();
cout <<"\n B: ";
B.Affiche();
cout <<"\n rangB: "< 7) "
<< "\n VP: ";
if (ParaGlob::NiveauImpression() > 7)
{ VP.Affiche();
cout <<"\n A: ";
A.Affiche();
cout <<"\n B: ";
B.Affiche();
cout <<"\n rangB: "< 7) "
<< "\n VP: ";
if (ParaGlob::NiveauImpression() > 7)
{ VP.Affiche();
cout <<"\n A: ";
A.Affiche();
cout <<"\n B: ";
B.Affiche();
cout <<"\n rangB: "< 7) "
<< "\n VP: ";
if (ParaGlob::NiveauImpression() > 7)
{ VP.Affiche();
cout <<"\n A: ";
A.Affiche();
cout <<"\n B: ";
B.Affiche();
cout <<"\n rangB: "< 7)
{cout << "\n matrice initiale: ";
A.Affiche();
cout << "\n B: ";
B.Affiche();
cout << "\n B2: ";
B2.Affiche();
cout <<"\n rangB: "< ConstMath::unpeupetit)
{cout << "\n erreur le vecteur (i= " << i <<") propre ";
Vpropre(i).Affiche();
cout << "\n n'est pas un vecteur propre pour la valeur propre: "
<< Vp(i) << " concernant la matrice: ";
A.Affiche();
cout << "\n A*V = "< veut dire que c'est la matrice nulle (à ConstMath::pasmalpetit près)
// rang = 1 ==> la première ligne de la matrice contient la direction libre, génératrice
// rang = 2 ==> les deux premières ligne de la matrice contiennent les deux directions libres
#ifndef MISE_AU_POINT
inline
#endif
int MathUtil2::CalculRangMatrice3x3Singuliere( Mat_pleine& A)
{
#ifdef MISE_AU_POINT
if ((A.Nb_colonne() != 3)|| (A.Nb_ligne() != 3))
{cout << "erreur de dimension: Nb_colonne()= " << A.Nb_colonne() << ", Nb_ligne()= ";
cout << A.Nb_ligne() << " alors que cette methode ne s'applique qu'aux matrices 3x3 ! "
<< "\n CalculRangMatrice(..." << endl;
Sortie(1);
}
#endif
int rang = 0; // init par défaut
// on récupère la norme maxi de la matrice
int imax,jmax;
double maxMat = A.MaxiValAbs(imax,jmax);
// si maxMat == 0, la matrice est nulle -> rang = 0
if (maxMat <= ConstMath::pasmalpetit)
{ rang = 0; }
else
{// sinon le rang sera au moins égal à 1 et maxMat n'est pas trop petit
double unSurmaxMat = 1./maxMat;
// on permute la première ligne, pour qu'elle contienne le maxi
if (imax != 1)
{// sauvegarde de la ligne du maxi, avec normalisation à 1
Vecteur ligne_du_maxi = unSurmaxMat * A(imax);
A.Ligne_set(imax) = A(1); // permutation
A.Ligne_set(1) = ligne_du_maxi; // """"
};
// maintenant on fait une réduction, c-a-d on transforme la matrice pour qu'il n'y ait que (1,0,0) dans la colonne du maxi
Vecteur col_du_maxi = A(jmax); // récup de la colonne du maxi
A.Ligne_set(2) = A(2) - col_du_maxi(2)*A(1);
A.Ligne_set(3) = A(3) - col_du_maxi(3)*A(1);
// arrivé ici normalement on a A(imax,2) = A(imax,3) = 0.
// on calcul le maxi des composantes de la deuxième et troisième ligne de la matrice
// -- tout d'abord la deuxième ligne
int imax2=2; // init
int jmax2; double maxMat2 = A(2).Max_val_abs(jmax2);
// -- idem troisième ligne
int imax3=3; // init
int jmax3; double maxMat3 = A(3).Max_val_abs(jmax3);
// les maxi finaux sont avec les indices 2 (imax2, jmax2, maxMat2)
if (maxMat3 > maxMat2)
{imax2=imax3;jmax2=jmax3;maxMat2 = maxMat3;
};
// si le maxi est très petit, on n'a qu'une seule direction de libre
if (maxMat2 <= ConstMath::pasmalpetit)
{ rang = 1; }
else
{ // sinon on refait la même manip entre les lignes 2 et 3
double unSurmaxMat2 = 1./maxMat2;
// on permute la dernière ligne, si besoin, pour que la deuxième contienne le maxi
if (imax2 != 2)
{// sauvegarde de la ligne du maxi, avec normalisation à 1
Vecteur ligne_du_maxi = unSurmaxMat2 * A(imax2);
A.Ligne_set(imax2) = A(2); // permutation
A.Ligne_set(2) = ligne_du_maxi; // """"
};
// le rang est 2 et les 2 premières lignes contiennent deux vecteurs indépendants
rang = 2;
}
};
// retour
return rang;
};
// --- cas d'une dimension d'espace == 3
// calcul deux vecteurs perpendiculaires à un troisième, générateurs d'un plan, et orthonormée
// Les deux vecteurs résultats sont quelconques a priori
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const Coordonnee& V1, Coordonnee& V2, Coordonnee& V3)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 3)|| (V2.Dimension() != 3) || (V3.Dimension() != 3))
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 3: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension() << ", V3.Dimension()= " << V3.Dimension()
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
}
#endif
Coordonnee V(V1/norme_V1); // on normalise
// on va chercher l'ordre des composantes de V
int un,deux,trois;
if (Dabs(V(2)) > Dabs(V(1)))
{ if (Dabs(V(2)) > Dabs(V(3)))
{un = 2;
if (Dabs(V(1)) > Dabs(V(3)))
{deux = 1; trois = 3;}
else
{deux = 3; trois = 1;}
}
else
{un = 3; deux= 2; trois = 1;}
}
else
{ if ((Dabs(V(3)) > Dabs(V(1))))
{un = 3; deux = 1; trois = 2; }
else
{if ((Dabs(V(3)) > Dabs(V(2))))
{un = 1; deux = 3; trois = 2;}
else
{un = 1; deux = 2; trois = 3;};
}
};
// on calcule les vecteurs en fonction
double unsurlongue = 1./sqrt(V(un)*V(un) + V(trois)*V(trois));
V2(un) = -V(trois) * unsurlongue;
V2(deux) = 0.;
V2(trois) = V(un) * unsurlongue;
V3(un) = V(deux) * V2(trois);
V3(deux) = V(trois) * V2(un) - V(un) * V2(trois);
V3(trois) = -V(deux) * V2(un);
#ifdef MISE_AU_POINT
if (ParaGlob::NiveauImpression() > 8)
{// on vérifie l'algo de tri
bool erreur = false;
if ((Dabs(V(deux)) > Dabs(V(un))) || (Dabs(V(trois)) > Dabs(V(un)))
|| (Dabs(V(trois)) > Dabs(V(deux)))
)
{cout << "\n *** erreur dans le tri des composantes de V: "
<< "un= "<< un << "deux= "<< deux <<" trois= "<< trois
<< " V= "<< V ;
erreur = true;
};
// on vérifie les normes et les produits scalaires
if ((V.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V a une norme " << V.Norme() << " diff de 1 ";
erreur = true;
}
if ((V2.Norme()-1) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 a une norme " << V2.Norme() << " diff de 1 ";
erreur = true;
}
if ((V3.Norme()-1) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 a une norme " << V3.Norme() << " diff de 1 ";
erreur = true;
}
if (Dabs(V * V2) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 n'est pas normal a V1 "
<< "\n V1= " << V1 << " V2= " << V2 ;
erreur = true;
}
if (Dabs(V * V3) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V1 "
<< "\n V1= " << V << " V3= " << V3 ;
erreur = true;
}
if (Dabs(V2 * V3) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V2 "
<< "\n V3= " << V3 << " V2= " << V2 ;
erreur = true;
}
if (erreur)
{ cout << "\n Def_vecteurs_plan(const Coordonnee& V1,..." << flush;
Sortie(1);
};
};
#endif
/* // calcul original, qui ne fonctionne pas pour le cas V(1) et V(3) nulle ensemble !!
//
if (Dabs(V(1)) >= Dabs(V(3)))
{ double unsurlongue = 1./sqrt(V(1)*V(1) + V(3)*V(3));
// si V(3) est nulle, alors V(1) est forcément non nulle ==>longue est non nul
// si (V(3) est non nulle, alors ==>longue est non nul
V2(1) = -V(3) * unsurlongue;
V2(2) = 0.;
V2(3) = V(1) * unsurlongue;
V3(1) = V(2) * V2(3);
V3(2) = V(3) * V2(1) - V(1) * V2(3);
V3(3) = -V(2) * V2(1);
}
else
{ double unsurlongue = 1./sqrt(V(2)*V(2) + V(3)*V(3));
// ici V(2) prend le rôle de V(1)
V2(1) = 0.;
V2(2) = V(3) * unsurlongue;
V2(3) = -V(2) * unsurlongue;
V3(1) = V(2) * V2(3) - V(3) * V2(2);
V3(2) = -V(1) * V2(3);
V3(3) = V(1) * V2(2);
};
*/
};
// calcul deux vecteurs perpendiculaires à un troisième, générateurs d'un plan, et orthonormée
// Les deux vecteurs résultats sont quelconques a priori
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const CoordonneeB& V1, CoordonneeB& V2, CoordonneeB& V3)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const CoordonneeB& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 3)|| (V2.Dimension() != 3) || (V3.Dimension() != 3))
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 3: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension() << ", V3.Dimension()= " << V3.Dimension()
<< "\n Def_vecteurs_plan(const CoordonneeB& V1,..." << endl;
Sortie(1);
}
#endif
CoordonneeB V(V1/norme_V1); // on normalise
// on va chercher l'ordre des composantes de V
int un,deux,trois;
if (Dabs(V(2)) > Dabs(V(1)))
{ if (Dabs(V(2)) > Dabs(V(3)))
{un = 2;
if (Dabs(V(1)) > Dabs(V(3)))
{deux = 1; trois = 3;}
else
{deux = 3; trois = 1;}
}
else
{un = 3; deux= 2; trois = 1;}
}
else
{ if ((Dabs(V(3)) > Dabs(V(1))))
{un = 3; deux = 1; trois = 2; }
else
{if ((Dabs(V(3)) > Dabs(V(2))))
{un = 1; deux = 3; trois = 2;}
else
{un = 1; deux = 2; trois = 3;};
}
};
// on calcule les vecteurs en fonction
double unsurlongue = 1./sqrt(V(un)*V(un) + V(trois)*V(trois));
V2(un) = -V(trois) * unsurlongue;
V2(deux) = 0.;
V2(trois) = V(un) * unsurlongue;
V3(un) = V(deux) * V2(trois);
V3(deux) = V(trois) * V2(un) - V(un) * V2(trois);
V3(trois) = -V(deux) * V2(un);
#ifdef MISE_AU_POINT
if (ParaGlob::NiveauImpression() > 8)
{// on vérifie l'algo de tri
bool erreur = false;
if ((Dabs(V(deux)) > Dabs(V(un))) || (Dabs(V(trois)) > Dabs(V(un)))
|| (Dabs(V(trois)) > Dabs(V(deux)))
)
{cout << "\n *** erreur dans le tri des composantes de V: "
<< "un= "<< un << "deux= "<< deux <<" trois= "<< trois
<< " V= "<< V ;
erreur = true;
};
// on vérifie les normes et les produits scalaires
if ((V.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V a une norme " << V.Norme() << " diff de 1 ";
erreur = true;
}
if ((V2.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 a une norme " << V2.Norme() << " diff de 1 ";
erreur = true;
}
if ((V3.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 a une norme " << V3.Norme() << " diff de 1 ";
erreur = true;
}
if (Dabs(V.Coor() * V2.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 n'est pas normal a V1 "
<< "\n V1= " << V1 << " V2= " << V2 ;
erreur = true;
}
if (Dabs(V.Coor() * V3.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V1 "
<< "\n V1= " << V << " V3= " << V3 ;
erreur = true;
}
if (Dabs(V2.Coor() * V3.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V2 "
<< "\n V3= " << V3 << " V2= " << V2 ;
erreur = true;
}
if (erreur)
{ cout << "\n Def_vecteurs_plan(const CoordonneeB& V1,..." << flush;
Sortie(1);
};
}
#endif
/* // calcul original, qui ne fonctionne pas pour le cas V(1) et V(3) nulle ensemble !!
if (Dabs(V(1)) >= Dabs(V(3)))
{ double unsurlongue = 1./sqrt(V(1)*V(1) + V(3)*V(3));
// si V(3) est nulle, alors V(1) est forcément non nulle ==>longue est non nul
// si (V(3) est non nulle, alors ==>longue est non nul
V2(1) = -V(3) * unsurlongue;
V2(2) = 0.;
V2(3) = V(1) * unsurlongue;
V3(1) = V(2) * V2(3);
V3(2) = V(3) * V2(1) - V(1) * V2(3);
V3(3) = -V(2) * V2(1);
}
else
{ double unsurlongue = 1./sqrt(V(2)*V(2) + V(3)*V(3));
// ici V(2) prend le rôle de V(1)
V2(1) = 0.;
V2(2) = V(3) * unsurlongue;
V2(3) = -V(2) * unsurlongue;
V3(1) = V(2) * V2(3) - V(3) * V2(2);
V3(2) = -V(1) * V2(3);
V3(3) = V(1) * V2(2);
};
*/
};
// calcul deux vecteurs perpendiculaires à un troisième, générateurs d'un plan, et orthonormée
// Les deux vecteurs résultats sont quelconques a priori
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const CoordonneeH& V1, CoordonneeH& V2, CoordonneeH& V3)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const CoordonneeH& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 3)|| (V2.Dimension() != 3) || (V3.Dimension() != 3))
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 3: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension() << ", V3.Dimension()= " << V3.Dimension()
<< "\n Def_vecteurs_plan(const CoordonneeH& V1,..." << endl;
Sortie(1);
}
#endif
CoordonneeH V(V1/norme_V1); // on normalise
// on va chercher l'ordre des composantes de V
int un,deux,trois;
if (Dabs(V(2)) > Dabs(V(1)))
{ if (Dabs(V(2)) > Dabs(V(3)))
{un = 2;
if (Dabs(V(1)) > Dabs(V(3)))
{deux = 1; trois = 3;}
else
{deux = 3; trois = 1;}
}
else
{un = 3; deux= 2; trois = 1;}
}
else
{ if ((Dabs(V(3)) > Dabs(V(1))))
{un = 3; deux = 1; trois = 2; }
else
{if ((Dabs(V(3)) > Dabs(V(2))))
{un = 1; deux = 3; trois = 2;}
else
{un = 1; deux = 2; trois = 3;};
}
};
// on calcule les vecteurs en fonction
double unsurlongue = 1./sqrt(V(un)*V(un) + V(trois)*V(trois));
V2(un) = -V(trois) * unsurlongue;
V2(deux) = 0.;
V2(trois) = V(un) * unsurlongue;
V3(un) = V(deux) * V2(trois);
V3(deux) = V(trois) * V2(un) - V(un) * V2(trois);
V3(trois) = -V(deux) * V2(un);
#ifdef MISE_AU_POINT
if (ParaGlob::NiveauImpression() > 8)
{// on vérifie l'algo de tri
bool erreur = false;
if ((Dabs(V(deux)) > Dabs(V(un))) || (Dabs(V(trois)) > Dabs(V(un)))
|| (Dabs(V(trois)) > Dabs(V(deux)))
)
{cout << "\n *** erreur dans le tri des composantes de V: "
<< "un= "<< un << "deux= "<< deux <<" trois= "<< trois
<< " V= "<< V ;
erreur = true;
};
// on vérifie les normes et les produits scalaires
if ((V.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V a une norme " << V.Norme() << " diff de 1 ";
erreur = true;
}
if ((V2.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 a une norme " << V2.Norme() << " diff de 1 ";
erreur = true;
}
if ((V3.Norme()-1.) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 a une norme " << V3.Norme() << " diff de 1 ";
erreur = true;
}
if (Dabs(V.Coor() * V2.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V2 n'est pas normal a V1 "
<< "\n V1= " << V1 << " V2= " << V2 ;
erreur = true;
}
if (Dabs(V.Coor() * V3.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V1 "
<< "\n V1= " << V << " V3= " << V3 ;
erreur = true;
}
if (Dabs(V2.Coor() * V3.Coor()) > ConstMath::petit)
{cout << "erreur le nouveau vecteur V3 n'est pas normal a V2 "
<< "\n V3= " << V3 << " V2= " << V2 ;
erreur = true;
}
if (erreur)
{ cout << "\n Def_vecteurs_plan(const CoordonneeH& V1,..." << flush;
Sortie(1);
};
}
#endif
/* // calcul original, qui ne fonctionne pas pour le cas V(1) et V(3) nulle ensemble !!
if (Dabs(V(1)) >= Dabs(V(3)))
{ double unsurlongue = 1./sqrt(V(1)*V(1) + V(3)*V(3));
// si V(3) est nulle, alors V(1) est forcément non nulle ==>longue est non nul
// si (V(3) est non nulle, alors ==>longue est non nul
V2(1) = -V(3) * unsurlongue;
V2(2) = 0.;
V2(3) = V(1) * unsurlongue;
V3(1) = V(2) * V2(3);
V3(2) = V(3) * V2(1) - V(1) * V2(3);
V3(3) = -V(2) * V2(1);
}
else
{ double unsurlongue = 1./sqrt(V(2)*V(2) + V(3)*V(3));
// ici V(2) prend le rôle de V(1)
V2(1) = 0.;
V2(2) = V(3) * unsurlongue;
V2(3) = -V(2) * unsurlongue;
V3(1) = V(2) * V2(3) - V(3) * V2(2);
V3(2) = -V(1) * V2(3);
V3(3) = V(1) * V2(2);
};
*/
};
// --- cas d'une dimension d'espace == 2
// calcul d'un vecteur perpendiculaire à un premier, et orthonormée
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const Coordonnee& V1, Coordonnee& V2)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 2)|| (V2.Dimension() != 2) )
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 2: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension()
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
}
#endif
Coordonnee V(V1/norme_V1); // on normalise
// le vecteur V2 est normale à V
// et V,V2 -> sens direct (inverse de l'horloge)
V2(1) = - V1(2);
V2(2) = V1(1);
};
// calcul d'un vecteur perpendiculaire à un premier, et orthonormée
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const CoordonneeB& V1, CoordonneeB& V2)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 2)|| (V2.Dimension() != 2) )
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 2: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension()
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
}
#endif
CoordonneeB V(V1/norme_V1); // on normalise
// le vecteur V2 est normale à V
// et V,V2 -> sens direct (inverse de l'horloge)
V2(1) = - V1(2);
V2(2) = V1(1);
};
// calcul d'un vecteur perpendiculaire à un premier, et orthonormée
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::Def_vecteurs_plan(const CoordonneeH& V1, CoordonneeH& V2)
{ double norme_V1= V1.Norme();
#ifdef MISE_AU_POINT
if (norme_V1 < ConstMath::trespetit)
{cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
cout << " le calcul du plan normal est impossible ! "
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
};
if ((V1.Dimension() != 2)|| (V2.Dimension() != 2) )
{cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 2: V1.Taille()= " << V1.Dimension()
<< ", V2.Dimension()= " << V2.Dimension()
<< "\n Def_vecteurs_plan(const Coordonnee& V1,..." << endl;
Sortie(1);
}
#endif
CoordonneeH V(V1/norme_V1); // on normalise
// le vecteur V2 est normale à V
// et V,V2 -> sens direct (inverse de l'horloge)
V2(1) = - V1(2);
V2(2) = V1(1);
};
//// calcul deux vecteurs perpendiculaires à un troisième, générateurs d'un plan, et orthonormées
//// Les deux vecteurs résultats sont quelconques a priori
//// calcul également la variation des vecteurs résultats
//// en entrée: V1 et d_Vi(1)(ddl) : vecteur donné et sa variation
//// en sortie: V2 et V3, d_Vi(2)(ddl) et d_Vi(3)(ddl) : vecteurs résultats et leurs variations
//#ifndef MISE_AU_POINT
// inline
//#endif
//void Def_vecteurs_plan_et_variation(const CoordonneeB& V1, CoordonneeB& V2, CoordonneeB& V3
// ,Tableau & d_Vi)
// { double norme_V1= V1.Norme();
// #ifdef MISE_AU_POINT
// if (norme_V1 < ConstMath::trespetit)
// {cout << "erreur le vecteur V1 a une norme nulle (= " << norme_V1 << ") ";
// cout << " le calcul du plan normal est impossible ! "
// << "\n Def_vecteurs_plan_et_variation(const CoordonneeB& V1,..." << endl;
// Sortie(1);
// };
// if ((V1.Dimension() != 3)|| (V2.Dimension() != 3) || (V3.Dimension() != 3))
// {cout << "erreur de dimension dans les vecteurs, qui devraient etre de dimension 3: V1.Taille()= " << V1.Dimension()
// << ", V2.Dimension()= " << V2.Dimension() << ", V3.Dimension()= " << V3.Dimension()
// << "\n Def_vecteurs_plan_et_variation(const CoordonneeB& V1,..." << endl;
// Sortie(1);
// }
// #endif
// CoordonneeB V(V1/norme_V1); // on normalise
// //
// if (Dabs(V(1)) >= Dabs(V(3)))
// { double unsurlongue = 1./sqrt(V(1)*V(1) + V(3)*V(3));
// // si V(3) est nulle, alors V(1) est forcément non nulle ==>longue est non nul
// // si (V(3) est non nulle, alors ==>longue est non nul
// V2(1) = -V(3) * unsurlongue;
// V2(2) = 0.;
// V2(3) = V(1) * unsurlongue;
//
// V3(1) = V(2) * V2(3);
// V3(2) = V(3) * V2(1) - V(1) * V2(3);
// V3(3) = -V(2) * V2(1);
//
// // et les variations
// int taille = d_Vi.Taille();
// for (int i=1; i<= taille; i++)
// { BaseB & d_Vi_i = d_Vi(i); // pour simplifier
// CoordonneeB & d_V1 = d_Vi_i(1); // "
// double d_denom = 2. * (d_V1(1) * V(1) + d_V1(3) * V(3));
// double d_unsurlongue =
// 1./sqrt(V(1)*V(1) + V(3)*V(3));
//
// CoordonneeB & d_V2 = d_Vi_i(2); // "
//
//
// };
// }
// else
// { double unsurlongue = 1./sqrt(V(2)*V(2) + V(3)*V(3));
// // ici V(2) prend le rôle de V(1)
// V2(1) = 0.;
// V2(2) = V(3) * unsurlongue;
// V2(3) = -V(2) * unsurlongue;
//
// V3(1) = V(2) * V2(3) - V(3) * V2(2);
// V3(2) = -V(1) * V2(3);
// V3(3) = V(1) * V2(2);
// };
// };
//
// calcul d'un changement de base: ceci n'est pas fait dans la classe Coordonnee car il faut y adjoindre
// la classe Mat_pleine qui intègre beaucoup de chose, du coup la classe Coordonnee deviendrait une usine
// changement de base (cf. théorie) : la matrice beta est telle que:
// gpB(i) = beta(i,j) * gB(j) <==> gp_i = beta_i^j * g_j
// et la matrice gamma telle que:
// gamma(i,j) represente les coordonnees de la nouvelle base duale gpH dans l'ancienne gH
// gpH(i) = gamma(i,j) * gH(j), i indice de ligne, j indice de colonne
// c-a-d= gp^i = gamma^i_j * g^j
// rappel des différentes relations entre beta et gamma
// [beta]^{-1} = [gamma]^T ; [beta]^{-1T} = [gamma]
// [beta] = [gamma]^{-1T} ; [beta]^{T} = [gamma]^{-1}
// changement de base pour de une fois covariant:
// [Ap_k] = [beta] * [A_i]
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::ChBase(const CoordonneeB& A_B,const Mat_pleine& beta,CoordonneeB& Ap_B)
{ int dim = A_B.Dimension();
#ifdef MISE_AU_POINT
if ((beta.Nb_ligne() != dim) || (beta.Nb_colonne() != dim))
{ cout << "\nErreur : matrice beta n'a pas les memes dimensions beta.Nb_ligne(): "
<< beta.Nb_ligne() <<" et beta.Nb_colonne(): " << beta.Nb_colonne()
<< " que le vecteur de dim: "
<< dim << " ! le changement de base n'est pas possible ! \n";
cout << "ChBase(const CoordonneeB& A_B,const Mat_pleine& beta,CoordonneeB& Ap_B) \n";
Sortie(1);
};
#endif
Vecteur inter = beta.Prod_mat_vec(A_B.Vect());
for (int i=1; i<= dim;i++)
Ap_B(i) = inter(i);
};
// changement de base pour de une fois contravariant:
// [Ap^k] = [gamma] * [A^i]
#ifndef MISE_AU_POINT
inline
#endif
void MathUtil2::ChBase(const CoordonneeH& A_H,const Mat_pleine& gamma,CoordonneeH& Ap_H)
{ int dim = A_H.Dimension();
#ifdef MISE_AU_POINT
if ((gamma.Nb_ligne() != dim) || (gamma.Nb_colonne() != dim))
{ cout << "\nErreur : matrice gamma n'a pas les memes dimensions gamma.Nb_ligne(): "
<< gamma.Nb_ligne() <<" et gamma.Nb_colonne(): " << gamma.Nb_colonne()
<< " que le vecteur de dim: "
<< dim << " ! le changement de base n'est pas possible ! \n";
cout << "ChBase(const CoordonneeH& A_H,const Mat_pleine& gamma,CoordonneeH& Ap_H) \n";
Sortie(1);
};
#endif
Vecteur inter = gamma.Prod_mat_vec(A_H.Vect());
////-------- debug -------
//cout << "\n debug MathUtil2::ChBase( ...";
//cout << "\n A_H initiale: "<< A_H;
//cout << "\n gamma: "; gamma.Affiche();
//cout << "\n gamma * A_H " << inter << flush;
////-------- fin debug ---------
for (int i=1; i<= dim;i++)
Ap_H(i) = inter(i);
};
#endif