// 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