1846 lines
71 KiB
C++
1846 lines
71 KiB
C++
|
|
|
|
// 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 "Debug.h"
|
|
#include "Tenseur3.h"
|
|
#include "ConstMath.h"
|
|
#include "MathUtil.h"
|
|
#include "Util.h"
|
|
#include "MathUtil2.h"
|
|
|
|
#ifndef Tenseur3_H_deja_inclus
|
|
|
|
// variables globales
|
|
// initialisation dans EnteteTenseur.h , utilisé dans le progr principal
|
|
//------------------------------------------------------------------
|
|
// cas des composantes mixtes BH
|
|
//------------------------------------------------------------------
|
|
|
|
// --- gestion de changement d'index ----
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::ChangementIndex::ChangementIndex() :
|
|
idx_i(9),idx_j(9),odVect(3)
|
|
{ idx_i(1)=1;idx_i(2)=1;idx_i(3)=1; idx_j(1)=1;idx_j(2)=2;idx_j(3)=3;
|
|
idx_i(4)=2;idx_i(5)=2;idx_i(6)=2; idx_j(4)=1;idx_j(5)=2;idx_j(6)=3;
|
|
idx_i(7)=3;idx_i(8)=3;idx_i(9)=3; idx_j(7)=1;idx_j(8)=2;idx_j(9)=3;
|
|
odVect(1,1)=1;odVect(1,2)=2;odVect(1,3)=3;
|
|
odVect(2,1)=4;odVect(2,2)=5;odVect(2,3)=6;
|
|
odVect(3,1)=7;odVect(3,2)=8;odVect(3,3)=9;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::Tenseur3BH() :
|
|
ipointe() // par defaut
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = 0.;
|
|
};
|
|
// initialisation de toutes les composantes a une meme valeur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::Tenseur3BH( const double val):
|
|
ipointe()
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = val;
|
|
};
|
|
// initialisation avec 9 valeurs différentes
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::Tenseur3BH
|
|
( const double val1, const double val2, const double val3, // 1ere ligne
|
|
const double val4, const double val5, const double val6, // 2ieme ligne
|
|
const double val7, const double val8, const double val9) // 3ieme ligne
|
|
:
|
|
ipointe()
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
t[0] = val1;t[1] = val2;t[2] = val3;
|
|
t[3] = val4;t[4] = val5;t[5] = val6;
|
|
t[6] = val7;t[7] = val8;t[8] = val9;
|
|
};
|
|
// constructeur a partir d'une instance non differenciee
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::Tenseur3BH ( const TenseurBH & B) :
|
|
ipointe()
|
|
{ this->dimension = B.dimension ;
|
|
#ifdef MISE_AU_POINT
|
|
if (dimension != 3)
|
|
{ cout << "\n erreur de dimension, elle devrait etre = 3 ";
|
|
cout << "\n Tenseur3BH::Tenseur3BH ( TenseurBH &) " << endl;
|
|
Sortie(1);
|
|
}
|
|
#endif
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = B.t[i];
|
|
};
|
|
// constructeur de copie
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::Tenseur3BH ( const Tenseur3BH & B):
|
|
ipointe()
|
|
{ this->dimension = B.dimension ;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = B.t[i];
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3BH::~Tenseur3BH()
|
|
{//if(listdouble9.end() != listdouble9.begin()) // si la liste n'est pas vide
|
|
listdouble9.erase(ipointe);} ; // suppression de l'élément de la liste
|
|
// initialise toutes les composantes à val
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::Inita(double val)
|
|
{ t[0] =val; t[1] =val; t[2] =val;
|
|
t[3] =val; t[4] =val; t[5] =val;
|
|
t[6] =val; t[7] =val; t[8] =val;
|
|
};
|
|
// operations
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator + ( const TenseurBH & B) const
|
|
{ TenseurBH * ptr;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator + ( etc..");
|
|
#endif
|
|
ptr = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = this->t[i] + B.t[i]; //somme des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::operator += ( const TenseurBH & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator + ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] += B.t[i];}; //somme des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator - () const
|
|
{ TenseurBH * ptr;
|
|
ptr = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = - this->t[i]; // soustraction des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator - ( const TenseurBH & B) const
|
|
{ TenseurBH * ptr;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator - ( etc..");
|
|
#endif
|
|
ptr = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = this->t[i] - B.t[i]; // soustraction des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::operator -= ( const TenseurBH & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator -= ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] -= B.t[i];}; //soustraction des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator = ( const TenseurBH & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator = ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] = B.t[i];
|
|
LesMaillonsBH::Libere(); // destruction des tenseurs intermediaires
|
|
return *this; }; //affectation des données;
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator * ( const double & b) const
|
|
{ TenseurBH * res;
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
res->t[i] = this->t[i] * b; //multiplication des données
|
|
return *res ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::operator *= ( const double & b)
|
|
{ for (int i = 0; i<=8; i++)
|
|
this->t[i] *= b;}; //multiplication des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator / ( const double & b) const
|
|
{ TenseurBH * res;
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
res->t[i] = this->t[i] / b; //division des données
|
|
return *res ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::operator /= ( const double & b)
|
|
{ for (int i = 0; i<=8; i++)
|
|
this->t[i] /= b;}; //division des données
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// affectation de B dans this, plusZero = false: les données manquantes sont inchangées,
|
|
// plusZero = true: les données manquantes sont mises à 0
|
|
void Tenseur3BH::Affectation_2D_a_3D(const Tenseur2BH & B,bool plusZero)
|
|
{ this->t[0] = B.t[0];this->t[4] = B.t[1];this->t[3] = B.t[2];this->t[1] = B.t[3];
|
|
if (plusZero)
|
|
{ this->t[2] = this->t[5] = this->t[8] = this->t[7] = this->t[6] = 0.;};
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// affectation de B dans this, plusZero = false: les données manquantes sont inchangées,
|
|
// plusZero = true: les données manquantes sont mises à 0
|
|
// si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
|
|
// des données possibles
|
|
void Tenseur3BH::Affectation_trans_dimension(const TenseurBH & B,bool plusZero)
|
|
{ switch (B.Dimension())
|
|
{case 3: *this = B; break; // affectation normale
|
|
case 2:
|
|
{ const Tenseur2BH & bn = *((Tenseur2BH *) &B);
|
|
this->Affectation_2D_a_3D(bn,plusZero);
|
|
break;
|
|
}
|
|
case 1:
|
|
{ if (plusZero)
|
|
this->Inita(0.);
|
|
this->t[0] = B.t[0]; //on affecte le seul terme
|
|
break;
|
|
}
|
|
default:
|
|
cout << "\n this= " << *this << " B= "; B.Ecriture(cout);
|
|
Message(3,
|
|
"erreur d\'affectation, Tenseur3BH::Affectation_trans_dimension( const TenseurBH & B, ..");
|
|
};
|
|
};
|
|
|
|
// produit contracte avec un vecteur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
CoordonneeB Tenseur3BH::operator * ( const CoordonneeB & B) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != dimension)
|
|
{ cout << "\nErreur : dimensions vecteur tenseur non egales !\n";
|
|
cout << " Tenseur3BH::operator *\n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
CoordonneeB v(dimension);
|
|
v(1) = this->t[0] * B(1) + this->t[1] * B(2) + this->t[2] * B(3);
|
|
v(2) = this->t[3] * B(1) + this->t[4] * B(2) + this->t[5] * B(3);
|
|
v(3) = this->t[6] * B(1) + this->t[7] * B(2) + this->t[8] * B(3);
|
|
return v;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBB & Tenseur3BH::operator * ( const TenseurBB & B) const // produit une fois contracte
|
|
{ TenseurBB * res;
|
|
#ifdef MISE_AU_POINT
|
|
if (Dabs(B.Dimension()) != 3) Message(3,"Tenseur3BH::operator * ( etc..");
|
|
#endif
|
|
res = new Tenseur_ns3BB;
|
|
LesMaillonsBB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
// on cree systematiquement un tenseur non symetrique
|
|
if (B.Dimension() == 3) // cas symetrique
|
|
{
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[5];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[5];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[5];
|
|
res->t[1] = this->t[0] * B.t[3] + this->t[1] * B.t[1] + this->t[2] * B.t[4];
|
|
res->t[4] = this->t[3] * B.t[3] + this->t[4] * B.t[1] + this->t[5] * B.t[4];
|
|
res->t[7] = this->t[6] * B.t[3] + this->t[7] * B.t[1] + this->t[8] * B.t[4];
|
|
res->t[2] = this->t[0] * B.t[5] + this->t[1] * B.t[4] + this->t[2] * B.t[2];
|
|
res->t[5] = this->t[3] * B.t[5] + this->t[4] * B.t[4] + this->t[5] * B.t[2];
|
|
res->t[8] = this->t[6] * B.t[5] + this->t[7] * B.t[4] + this->t[8] * B.t[2];
|
|
}
|
|
else // cas ou B n'est pas symetrique
|
|
{
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[6];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[6];
|
|
res->t[1] = this->t[0] * B.t[1] + this->t[1] * B.t[4] + this->t[2] * B.t[7];
|
|
res->t[4] = this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
res->t[7] = this->t[6] * B.t[1] + this->t[7] * B.t[4] + this->t[8] * B.t[7];
|
|
res->t[2] = this->t[0] * B.t[2] + this->t[1] * B.t[5] + this->t[2] * B.t[8];
|
|
res->t[5] = this->t[3] * B.t[2] + this->t[4] * B.t[5] + this->t[5] * B.t[8];
|
|
res->t[8] = this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
}
|
|
|
|
return (*res); };
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::operator * ( const TenseurBH & B) const // produit une fois contracte
|
|
{ TenseurBH * res;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator * ( etc..");
|
|
#endif
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[6];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[6];
|
|
res->t[1] = this->t[0] * B.t[1] + this->t[1] * B.t[4] + this->t[2] * B.t[7];
|
|
res->t[4] = this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
res->t[7] = this->t[6] * B.t[1] + this->t[7] * B.t[4] + this->t[8] * B.t[7];
|
|
res->t[2] = this->t[0] * B.t[2] + this->t[1] * B.t[5] + this->t[2] * B.t[8];
|
|
res->t[5] = this->t[3] * B.t[2] + this->t[4] * B.t[5] + this->t[5] * B.t[8];
|
|
res->t[8] = this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
return (*res); };
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// produit contracte contracté deux fois A(i,j)*B(j,i)=A..B c-c-d : A_i^{.k} * B_k^{.i}
|
|
// -> on contracte d'abord l'indice du milieu puis l'indice externe
|
|
// cela permet d'utiliser les mêmes variances pour les deux tenseurs
|
|
double Tenseur3BH::operator && ( const TenseurBH & B) const // produit deux fois contracte
|
|
{ double b = 0;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator && ( etc..");
|
|
#endif
|
|
b += this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
b += this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
b += this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
return b;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::Trace() const // trace du tenseur
|
|
{ double b;
|
|
b = this->t[0] + this->t[4] + this->t[8];
|
|
return b;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::II() const // second invariant
|
|
{ //return Dabs((*this && *this)); // on met Dabs car dans les petits nombres on peut avoir des nombres
|
|
double ret = (*this && *this);
|
|
// if (Dabs(ret) < 0.1*ConstMath::pasmalpetit)
|
|
// on part du principe qu'il s'agit du produit doublement contracté d'un tenseur symétrique
|
|
// donc normalement il devrait donner un nombre positif, donc s'il est très petit, on le met arbitrairement à 0
|
|
if (ret < 0.)
|
|
{ret = 0.;}
|
|
return ret;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::III() const // troisieme invariant
|
|
{ Tenseur3BH a; a = ((*this) * (*this));
|
|
return (a && (*this)) ;};
|
|
|
|
// valeurs propre dans le vecteur de retour, classée par ordres "décroissants"
|
|
// cas indique le cas de valeur propre:
|
|
// quelque soit la dimension: cas = -1, si l'extraction des valeurs propres n'a pas pu se faire
|
|
// dans ce cas les valeurs propres de retour sont nulles par défaut
|
|
// dim = 3 , 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 val(1)=val(2) ( val(1), et val(3) dans les 2 premières composantes du retour)
|
|
// , cas = 3 si val(2)=val(3) ( val(1), et val(2) dans les 2 premières composantes du retour)
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Coordonnee Tenseur3BH::ValPropre(int& cas) const
|
|
{ Coordonnee ret(3);
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{ cas = 0; ret(1)=ret(2)=ret(3)=b/3.; return ret;};
|
|
// sinon ..
|
|
b=-b; double c=0.5*(b*b-((*this)*(*this)).Trace()) ; double d=-this->Det();
|
|
// maintenant on va essayer de normaliser les termes de l'équation du troisième degré
|
|
// au début on a une équation x^3+B.x^2+C.x+D=0=(x-x1)(x-x2)(x-x3)
|
|
// on veut tenir compte de l'ordre de grandeur des xi avec une transformation: xp=a.x
|
|
// a étant un facteur de normalisation. L'équation en xpi devient:
|
|
// x^3+(a.B).x^2+(a^2.C).x+(a^3.D)=0=x^3+Bp.x^2+Cp.x+Dp, Bp Cp Dp étant les nouveaux coefficients
|
|
// on choisit pour a un coef fonction des valeurs des composantes du tenseur
|
|
double a_N = 1./ this->MaxiComposante(); // coeff de normalisation normalement non nulle
|
|
double bp = b * a_N; double cp = c * a_N*a_N; double dp = d * a_N*a_N*a_N;
|
|
// int caas;
|
|
// alg_zero.TroisiemeDegre dans certain ne fonctionne pas parfaitement, because , sans doute des arrondis
|
|
// j'essaie donc une résolution directe (voire après) qui a l'air de toujours fonctionner (a voir dans le temps)
|
|
// alg_zero.TroisiemeDegre(1.,b,c,d,ret(1),ret(2),ret(3),caas);
|
|
// #ifdef MISE_AU_POINT
|
|
// if (caas <= 0)
|
|
// { cout << "\n warning **** recherche de valeurs propre du tenseur: pas de racine correcte ! "
|
|
// << "\n tenseur= " << *this << "racines= " << ret
|
|
// << "\n on laisse le calcul se poursuivre cependant"
|
|
// << "\n Coordonnee Tenseur3BH::ValPropre()";
|
|
// };
|
|
// #endif
|
|
//
|
|
// ret /= a_N;
|
|
// cout << "\n \n " << ret(1) << " " << ret(2) << " " << ret(3);
|
|
//
|
|
// on va essayer d'utiliser les formules directes analytiques:
|
|
// 1) les invariants: Yavuz Basar and Dieter Weichert, "Nonlinear continuum Mechanis of solids"
|
|
// Sringer, p 33, ISBN 3-540-66601-X, 2000
|
|
double IA=-bp; double IIA=cp; double IIIA=-dp;
|
|
double tp1=IA*IA-3.*IIA; // grandeur intermédiaire qui doit-être positive
|
|
double t1 = 2.*sqrt(MaX(0.,tp1)); // on la met systématiquement à positif et on prend la racine
|
|
// si t1 est nul cela signifie qu'il y a trois valeurs propres égales
|
|
double untiers = 1./3.;
|
|
if (Abs(t1) <= ConstMath::trespetit)
|
|
{ret(1)=ret(2)=ret(3)=untiers*IA;}
|
|
else // sinon cas où l'on peut calculer t2
|
|
{// maintenant une seconde grandeur intermédiaire qui est un cosinus
|
|
double t2 = (2.*IA*IA*IA-9.*IA*IIA+27.*IIIA)/(t1*tp1);
|
|
if (Abs(t2) > 1.) t2 = Signe(t2); // limite à 1 au cas où
|
|
double theta = acos(t2);
|
|
// calcul des valeurs propres
|
|
ret(1)= untiers*(IA+t1*cos(untiers*(theta + 2.* ConstMath::Pi)));
|
|
ret(2)= untiers*(IA+t1*cos(untiers*(theta + 4.* ConstMath::Pi)));
|
|
ret(3)= untiers*(IA+t1*cos(untiers*(theta + 6.* ConstMath::Pi)));
|
|
};
|
|
ret /= a_N;
|
|
|
|
// caas = 5; // qui est le cas 3 valeurs propres, mais en fait elles peuvent être égales par exemple
|
|
/// cout << "\n " << ret(1) << " " << ret(2) << " " << ret(3);
|
|
|
|
// classement des valeurs propres
|
|
double vv1,vv2,vv3;
|
|
// if (caas == 5) // cas où il y a 3 racines réelles
|
|
// il n'y a plus qu'un seul cas
|
|
{// d'abord on regarde le plus grand que l'on met dans ret(1)
|
|
if (ret(1) >= ret(2))
|
|
{ if (ret(1) >= ret(3)) { vv1=ret(1); vv2=ret(2); vv3=ret(3);}
|
|
else { vv2=ret(1); ret(1)=vv1=ret(3); vv3=ret(2);};
|
|
}
|
|
else
|
|
{ if (ret(2) >= ret(3)) { vv2=ret(1);ret(1)=vv1=ret(2); vv3=ret(3);}
|
|
else { vv2=ret(1);ret(1)=vv1=ret(3); vv3=ret(2);};
|
|
};
|
|
// puis les deux derniers
|
|
if (vv2 < vv3) { ret(2) = vv3; ret(3) = vv2;vv2=vv3;vv3=ret(2);}
|
|
else { ret(2) = vv2; ret(3) = vv3;};
|
|
// définition du cas de valeurs propres
|
|
// dim = 3 , 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 val(1)=val(2) ( val(1), et val(3) dans les 2 premières composantes du retour)
|
|
// , cas = 3 si val(2)=val(3) ( val(1), et val(2) dans les 2 premières composantes du retour)
|
|
if ( difftrespetit(vv1,vv2) && difftrespetit(vv2,vv3)) {cas = 1;}
|
|
else if ( (EgaleApeuPres(vv1,vv2)) && EgaleApeuPres(vv2,vv3)) {cas = 0;}
|
|
else if ( (EgaleApeuPres(vv1,vv2)) && !EgaleApeuPres(vv2,vv3)) {cas = 2;}
|
|
else if ( !(EgaleApeuPres(vv1,vv2)) && EgaleApeuPres(vv2,vv3)) {cas = 3;}
|
|
else
|
|
{cout << "\n classement des valeurs propres : non realise !! "
|
|
<< "\n vv1= "<<vv1 <<", vv2= "<< vv2 <<", vv3= "<< vv3
|
|
<< "\n r(1)= "<<ret(1) << ", r(2)= "<<ret(2) << ", r(3)= "<<ret(3)
|
|
<< "\n Tenseur3BH::ValPropre(... "<<endl;
|
|
};
|
|
}
|
|
// else if ((caas == 4) || (caas == 1)) // cas où il y a 2 racines
|
|
// {//on regarde le plus grand
|
|
// if (ret(1) < ret(2))
|
|
// { vv2=ret(1); ret(1)=ret(2);ret(2)=vv2; cas=2;};
|
|
// // sinon l'ordre est déjà bon
|
|
// cas=3;
|
|
// }
|
|
// else if ((caas == 2) || (caas == 3))
|
|
// { // cas d'une seule racine
|
|
// cas=0;
|
|
// };
|
|
|
|
// // s'il y a eu erreur dans la recherche de valeurs propre on modifie le cas
|
|
// if (caas <= 0) cas=-1;
|
|
|
|
// if (cas <= 0)
|
|
// { cout << "\n warning **** recherche de valeurs propre du tenseur: pas de racine correcte ! "
|
|
// << "\n tenseur= " << *this << "racines= " << ret
|
|
// << "\n on laisse le calcul se poursuivre cependant"
|
|
// << "\n Coordonnee Tenseur3BH::ValPropre()";
|
|
// };
|
|
|
|
|
|
// retour
|
|
return ret;
|
|
};
|
|
|
|
// idem met en retour la matrice mat contiend par colonne les vecteurs propre
|
|
// elle doit avoir la dimension du tenseur
|
|
// les vecteurs propre sont exprime dans le repere dual (contrairement à HB)
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Coordonnee Tenseur3BH::ValPropre(int& cas, Mat_pleine& mat) const
|
|
{ Coordonnee ret(3);
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
// on ramène le tenseur identité en absolue comme base de vecteurs propres car toute base est ok
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{ mat.Initialise(0.); mat(1,1)=1.;mat(2,2)=1.;mat(3,3)=1.;
|
|
cas=0;ret(1)=ret(2)=ret(3)=b/3.;return ret;
|
|
};
|
|
// sinon on commence par calculer les valeurs propres
|
|
Coordonnee valPropre = Tenseur3BH::ValPropre(cas);
|
|
// --- gestion des erreurs éventuelles
|
|
if (cas == -1) // cas d'une erreur
|
|
{mat.Zero(); // mise à 0 de la matrice
|
|
ret.Zero(); // mise à 0 des valeurs propres
|
|
return ret;
|
|
};
|
|
// sinon ok on continue
|
|
// on crée une matrice pour utiliser une routine générale
|
|
#ifdef MISE_AU_POINT
|
|
if ((mat.Nb_ligne() != 3) || (mat.Nb_colonne() != 3))
|
|
{ cout << "\nErreur : la matrice en parametre doit etre de dimension 3x3 ";
|
|
cout << "\n Tenseur3BH::ValPropre(... \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(i,j) = (*this)(i,j);
|
|
// int cass;
|
|
Tableau <Coordonnee> V_P = MathUtil2::V_Propres3x3(mat,valPropre,cas);
|
|
// --- gestion des erreurs éventuelles
|
|
if (cas == -1) // cas d'une erreur
|
|
{mat.Zero(); // mise à 0 de la matrice
|
|
ret.Zero(); // mise à 0 des valeurs propres
|
|
return ret;
|
|
};
|
|
// sinon c'est ok, on continue
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(j,i) = V_P(i)(j); // le vecteur propre i, sa coordonnée j
|
|
//retour
|
|
return ret;
|
|
};
|
|
|
|
// ici il s'agit uniquement de calculer les vecteurs propres, les valeurs propres
|
|
// étant déjà connues
|
|
// en retour VP les vecteurs propre : doivent avoir la dimension du tenseur
|
|
// les vecteurs propre sont exprime dans le repere naturel (pour les tenseurs dim 3
|
|
// pour dim=2:le premier vecteur propre est exprime dans le repere naturel
|
|
// le second vecteur propre est exprimé dans le repère dual
|
|
// pour dim=1 le vecteur est dans la base naturelle (mais ça importe pas)
|
|
// en sortie cas = -1 s'il y a eu un problème, dans ce cas, V_P est quelconque
|
|
// sinon si tout est ok, cas est identique en sortie avec l'entrée
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3BH::VecteursPropres(const Coordonnee& valPropre,int& cas, Tableau <Coordonnee>& V_P) const
|
|
{ // on dimensionne en conséquence
|
|
Coordonnee toto(3); // un vecteur nul
|
|
V_P.Change_taille(3,toto); // tableau initialisé à 0
|
|
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
// on ramène le tenseur identité en absolue comme base de vecteurs propres car toute base est ok
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (cas != 0)
|
|
{ cout << "\nErreur : les valeurs propres devraient etre identiques alors qu'en entree: cas= " << cas ;
|
|
cout << "\n Tenseur3BH::VecteursPropres(... \n";
|
|
cas=-1;
|
|
return;
|
|
};
|
|
#endif
|
|
V_P(1).Zero(); V_P(1)(1)=1.;
|
|
V_P(2).Zero(); V_P(2)(2)=1.;
|
|
V_P(3).Zero(); V_P(3)(3)=1.;
|
|
cas=0;return;
|
|
};
|
|
// sinon ok on continue
|
|
// on crée une matrice pour utiliser une routine générale
|
|
Mat_pleine mat(3,3,0.);
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(i,j) = (*this)(i,j);
|
|
// int cass;
|
|
V_P = MathUtil2::V_Propres3x3(mat,valPropre,cas);
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::Det() const // determinant de la matrice des coordonnees
|
|
{ double b = 0;
|
|
b += this->t[0] *(this->t[4] * this->t[8] - this->t[5] * this->t[7]);
|
|
b -= this->t[3] *(this->t[1] * this->t[8] - this->t[2] * this->t[7]);
|
|
b += this->t[6] *(this->t[1] * this->t[5] - this->t[2] * this->t[4]);
|
|
return b;};
|
|
// test
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
int Tenseur3BH::operator == ( const TenseurBH & B) const
|
|
{ int res = 1;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator == ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
if (this->t[i] != B.t[i]) res = 0 ;
|
|
return res; };
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
int Tenseur3BH::operator != ( const TenseurBH & B) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3BH::operator != ( etc..");
|
|
#endif
|
|
if ((*this) == B)
|
|
return 0;
|
|
else
|
|
return 1; };
|
|
// calcul du tenseur inverse par rapport au produit contracte
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::Inverse() const
|
|
{TenseurBH * res;
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
// choix sur la méthode d'inversion
|
|
switch (ParaGlob::param->ParaAlgoControleActifs().Type_calnum_inversion_metrique())
|
|
{ case LU_EQUILIBRE:
|
|
{ // on recopie this dans le nouveau tenseur
|
|
for (int i = 0; i< 9; i++)
|
|
res->t[i] = t[i];
|
|
|
|
// pour le débug
|
|
//res->t[0]=3.; res->t[1]=2.;res->t[2]=1.;
|
|
|
|
// appel de l'inversion
|
|
Util::Inverse_mat3x3(((Tenseur3BH *) res)->ipointe);
|
|
}
|
|
break;
|
|
//cout << "\n comp \n ";
|
|
// res->Ecriture(cout); cout << "\n";
|
|
case CRAMER : // méthode historique
|
|
{ // calcul du determinant
|
|
double det = Det();
|
|
#ifdef MISE_AU_POINT
|
|
if (Dabs(det) <= ConstMath::trespetit)
|
|
{ cout << "\nErreur : le determinant du tenseur est nul !\n";
|
|
cout << "Tenseur3BH::Inverse() \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
det =1./det;
|
|
res->t[0] = (this->t[4]*this->t[8] - this->t[5]*this->t[7])*det;
|
|
res->t[3] = (this->t[5]*this->t[6] - this->t[3]*this->t[8])*det;
|
|
res->t[6] = (this->t[3]*this->t[7] - this->t[4]*this->t[6])*det;
|
|
res->t[1] = (this->t[2]*this->t[7] - this->t[1]*this->t[8])*det;
|
|
res->t[4] = (this->t[0]*this->t[8] - this->t[2]*this->t[6])*det;
|
|
res->t[7] = (this->t[1]*this->t[6] - this->t[0]*this->t[7])*det;
|
|
res->t[2] = (this->t[1]*this->t[5] - this->t[2]*this->t[4])*det;
|
|
res->t[5] = (this->t[2]*this->t[3] - this->t[0]*this->t[5])*det;
|
|
res->t[8] = (this->t[0]*this->t[4] - this->t[1]*this->t[3])*det;
|
|
}
|
|
break;
|
|
default:
|
|
{ cout << "\nErreur **** : la methode de resolution de l'inversion de tenseur "
|
|
<< ParaGlob::param->ParaAlgoControleActifs().Type_calnum_inversion_metrique() << " n'est pas implante \n";
|
|
cout << "Tenseur3BH::Inverse() \n";
|
|
Sortie(1);
|
|
};
|
|
break;
|
|
};
|
|
// res->Ecriture(cout); // pour le debug
|
|
return *res;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3BH::Transpose() const
|
|
{ TenseurHB * res;
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon(res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = this->t[0];
|
|
res->t[1] = this->t[3];
|
|
res->t[2] = this->t[6];
|
|
res->t[3] = this->t[1];
|
|
res->t[4] = this->t[4];
|
|
res->t[5] = this->t[7];
|
|
res->t[6] = this->t[2];
|
|
res->t[7] = this->t[5];
|
|
res->t[8] = this->t[8];
|
|
return *res;};
|
|
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// permute Bas Haut, mais reste dans le même tenseur
|
|
void Tenseur3BH::PermuteHautBas()
|
|
{ // t[0] = t[0];
|
|
double t1=t[1]; t[1] = t[3];
|
|
double t2=t[2]; t[2] = t[6];
|
|
t[3] = t1;
|
|
//[4] = [4];
|
|
double t5=t[5]; t[5] = t[7];
|
|
t[6] = t2;
|
|
t[7] = t5;
|
|
//t[8] = t[8];
|
|
};
|
|
|
|
// calcul du maximum en valeur absolu des composantes du tenseur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::MaxiComposante() const
|
|
{ return DabsMaxiTab(t, 9) ;
|
|
};
|
|
|
|
// retourne la composante i,j en lecture et écriture
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double& Tenseur3BH::Coor( const int i, const int j)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ( ((i!=1)&&(i!=2)&&(i!=3)) || ((j!=1)&&(j!=2)&&(j!=3)) )
|
|
{ cout << "\nErreur : composante inexistante !\n";
|
|
cout << " i = " << i << "j = " << j << '\n';
|
|
cout << "Tenseur3BH::OPERATOR() (int,int ) \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
switch (i)
|
|
{ case 1 : { switch (j)
|
|
{ case 1 : return t[0]; break;
|
|
case 2 : return t[1]; break;
|
|
case 3 : return t[2]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 2 : { switch (j)
|
|
{ case 1 : return t[3]; break;
|
|
case 2 : return t[4]; break;
|
|
case 3 : return t[5]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 3 : { switch (j)
|
|
{ case 1 : return t[6]; break;
|
|
case 2 : return t[7]; break;
|
|
case 3 : return t[8]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
default : return t[0];
|
|
}
|
|
};
|
|
// retourne la composante i,j en lecture seulement
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3BH::operator () ( const int i, const int j) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ( ((i!=1)&&(i!=2)&&(i!=3)) || ((j!=1)&&(j!=2)&&(j!=3)) )
|
|
{ cout << "\nErreur : composante inexistante !\n";
|
|
cout << " i = " << i << "j = " << j << '\n';
|
|
cout << "Tenseur3BH::OPERATOR() (int,int ) \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
switch (i)
|
|
{ case 1 : { switch (j)
|
|
{ case 1 : return t[0]; break;
|
|
case 2 : return t[1]; break;
|
|
case 3 : return t[2]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 2 : { switch (j)
|
|
{ case 1 : return t[3]; break;
|
|
case 2 : return t[4]; break;
|
|
case 3 : return t[5]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 3 : { switch (j)
|
|
{ case 1 : return t[6]; break;
|
|
case 2 : return t[7]; break;
|
|
case 3 : return t[8]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
default : return t[0];
|
|
}
|
|
};
|
|
|
|
//fonctions static définissant le produit tensoriel de deux vecteurs
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3BH::Prod_tensoriel(const CoordonneeB & aB, const CoordonneeH & bH)
|
|
{ TenseurBH * res;
|
|
#ifdef MISE_AU_POINT
|
|
if ((aB.Dimension() != 3) || (bH.Dimension() != 3))
|
|
{ cout << "\n erreur de dimension dans les coordonnées d'entrée, dim1 et dim2 ="
|
|
<< aB.Dimension() << " " << bH.Dimension()
|
|
<< "\n Tenseur3BH::Prod_tensoriel( etc.." << endl;
|
|
Sortie(1);
|
|
}
|
|
#endif
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = aB(1) * bH(1); res->t[1] = aB(1) * bH(2); res->t[2] = aB(1) * bH(3);
|
|
res->t[3] = aB(2) * bH(1); res->t[4] = aB(2) * bH(2); res->t[5] = aB(2) * bH(3);
|
|
res->t[6] = aB(3) * bH(1); res->t[7] = aB(3) * bH(2); res->t[8] = aB(3) * bH(3);
|
|
return *res ;};
|
|
|
|
// lecture et écriture de données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
istream & Tenseur3BH::Lecture(istream & entree)
|
|
{ // lecture et vérification du type
|
|
string nom_type;
|
|
entree >> nom_type;
|
|
if (nom_type != "Tenseur3BH")
|
|
{ Sortie(1);
|
|
return entree;
|
|
}
|
|
// lecture des coordonnées
|
|
for (int i = 0; i< 9; i++)
|
|
entree >> this->t[i];
|
|
return entree;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
ostream & Tenseur3BH::Ecriture(ostream & sort) const
|
|
{ // écriture du type
|
|
sort << "Tenseur3BH ";
|
|
// puis les datas
|
|
for (int i = 0; i< 9; i++)
|
|
sort << setprecision(ParaGlob::NbdigdoCA()) << this->t[i] << " ";
|
|
return sort;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// surcharge de l'operator de lecture
|
|
istream & operator >> (istream & entree, Tenseur3BH & A)
|
|
{ int dim = A.Dimension();
|
|
#ifdef MISE_AU_POINT
|
|
if (dim != 3) A.Message(3,"operator >> (istream & entree, Tenseur3BH & A)");
|
|
#endif
|
|
// lecture et vérification du type
|
|
string nom_type;
|
|
entree >> nom_type;
|
|
if (nom_type != "Tenseur3BH")
|
|
{ Sortie(1);
|
|
return entree;
|
|
}
|
|
// lecture des coordonnées
|
|
for (int i = 0; i< 9 ; i++)
|
|
entree >> A.t[i];
|
|
return entree;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// surcharge de l'operator d'ecriture
|
|
ostream & operator << (ostream & sort , const Tenseur3BH & A)
|
|
{ //int dim = A.Dimension();
|
|
// écriture du type
|
|
sort << "Tenseur3BH ";
|
|
// puis les datas
|
|
for (int i = 0; i< 9; i++)
|
|
sort << setprecision(ParaGlob::NbdigdoCA()) << A.t[i] << " ";
|
|
return sort;
|
|
};
|
|
|
|
//------------------------------------------------------------------
|
|
// cas des composantes mixtes HB
|
|
//------------------------------------------------------------------
|
|
|
|
// --- gestion de changement d'index ----
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::ChangementIndex::ChangementIndex() :
|
|
idx_i(9),idx_j(9),odVect(3)
|
|
{ idx_i(1)=1;idx_i(2)=1;idx_i(3)=1; idx_j(1)=1;idx_j(2)=2;idx_j(3)=3;
|
|
idx_i(4)=2;idx_i(5)=2;idx_i(6)=2; idx_j(4)=1;idx_j(5)=2;idx_j(6)=3;
|
|
idx_i(7)=3;idx_i(8)=3;idx_i(9)=3; idx_j(7)=1;idx_j(8)=2;idx_j(9)=3;
|
|
odVect(1,1)=1;odVect(1,2)=2;odVect(1,3)=3;
|
|
odVect(2,1)=4;odVect(2,2)=5;odVect(2,3)=6;
|
|
odVect(3,1)=7;odVect(3,2)=8;odVect(3,3)=9;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::Tenseur3HB() :
|
|
ipointe() // par defaut
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = 0.;
|
|
};
|
|
// initialisation de toutes les composantes a une meme valeur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::Tenseur3HB( const double val) :
|
|
ipointe()
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = val;
|
|
};
|
|
// initialisation avec 9 valeurs différentes
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::Tenseur3HB
|
|
( const double val1, const double val2, const double val3, // 1ere ligne
|
|
const double val4, const double val5, const double val6, // 2ieme ligne
|
|
const double val7, const double val8, const double val9) // 3ieme ligne
|
|
:
|
|
ipointe()
|
|
{ dimension = 3;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
t[0] = val1;t[1] = val2;t[2] = val3;
|
|
t[3] = val4;t[4] = val5;t[5] = val6;
|
|
t[6] = val7;t[7] = val8;t[8] = val9;
|
|
};
|
|
// constructeur a partir d'une instance non differenciee
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::Tenseur3HB ( const TenseurHB & B):
|
|
ipointe()
|
|
{ this->dimension = B.dimension ;
|
|
#ifdef MISE_AU_POINT
|
|
if (dimension != 3)
|
|
{ cout << "\n erreur de dimension, elle devrait etre = 3 ";
|
|
cout << "\n Tenseur3HB::Tenseur3HB ( TenseurHB &) " << endl;
|
|
Sortie(1);
|
|
}
|
|
#endif
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = B.t[i];
|
|
};
|
|
// constructeur de copie
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::Tenseur3HB ( const Tenseur3HB & B):
|
|
ipointe()
|
|
{ this->dimension = B.dimension ;
|
|
listdouble9.push_front(Reels9()); // allocation
|
|
ipointe = listdouble9.begin(); // recup de la position de la maille dans la liste
|
|
t = (ipointe)->donnees; // recup de la position des datas dans la maille
|
|
for ( int i=0; i< 9; i++)
|
|
t[i] = B.t[i];
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Tenseur3HB::~Tenseur3HB()
|
|
{//if(listdouble9.end() != listdouble9.begin()) // si la liste n'est pas vide
|
|
listdouble9.erase(ipointe);} ; // suppression de l'élément de la liste
|
|
// initialise toutes les composantes à val
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::Inita(double val)
|
|
{ t[0] =val; t[1] =val; t[2] =val;
|
|
t[3] =val; t[4] =val; t[5] =val;
|
|
t[6] =val; t[7] =val; t[8] =val;
|
|
};
|
|
// operations
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator + (const TenseurHB & B) const
|
|
{ TenseurHB * ptr;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator + ( etc..");
|
|
#endif
|
|
ptr = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = this->t[i] + B.t[i]; //somme des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::operator += ( const TenseurHB & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator += ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] += B.t[i];}; //somme des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator - () const
|
|
{ TenseurHB * ptr;
|
|
ptr = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = - this->t[i]; // soustraction des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator - ( const TenseurHB & B) const
|
|
{ TenseurHB * ptr;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator - ( etc..");
|
|
#endif
|
|
ptr = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( ptr); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
(*ptr).t[i] = this->t[i] - B.t[i]; // soustraction des données
|
|
return (*ptr) ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::operator -= ( const TenseurHB & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator -= ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] -= B.t[i];}; //soustraction des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator = ( const TenseurHB & B)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator = ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
this->t[i] = B.t[i];
|
|
LesMaillonsHB::Libere(); // destruction des tenseurs intermediaires
|
|
return *this; }; //affectation des données;
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator * ( const double & b) const
|
|
{ TenseurHB * res;
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
res->t[i] = this->t[i] * b; //multiplication des données
|
|
return *res ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::operator *= ( const double & b)
|
|
{ for (int i = 0; i<=8; i++)
|
|
this->t[i] *= b;}; //multiplication des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator / ( const double & b) const
|
|
{ TenseurHB * res;
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
for (int i = 0; i<=8; i++)
|
|
res->t[i] = this->t[i] / b; //division des données
|
|
return *res ;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::operator /= ( const double & b)
|
|
{ for (int i = 0; i<=8; i++)
|
|
this->t[i] /= b;}; //division des données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// affectation de B dans this, plusZero = false: les données manquantes sont inchangées,
|
|
// plusZero = true: les données manquantes sont mises à 0
|
|
void Tenseur3HB::Affectation_2D_a_3D(const Tenseur2HB & B,bool plusZero)
|
|
{ this->t[0] = B.t[0];this->t[4] = B.t[1];this->t[3] = B.t[2];this->t[1] = B.t[3];
|
|
if (plusZero)
|
|
{ this->t[2] = this->t[5] = this->t[8] = this->t[7] = this->t[6] = 0.;};
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// affectation de B dans this, plusZero = false: les données manquantes sont inchangées,
|
|
// plusZero = true: les données manquantes sont mises à 0
|
|
// si au contraire la dimension de B est plus grande que *this, il y a uniquement affectation
|
|
// des données possibles
|
|
void Tenseur3HB::Affectation_trans_dimension(const TenseurHB & B,bool plusZero)
|
|
{ switch (B.Dimension())
|
|
{case 3: *this = B; break; // affectation normale
|
|
case 2:
|
|
{ const Tenseur2HB & bn = *((Tenseur2HB *) &B);
|
|
this->Affectation_2D_a_3D(bn,plusZero);
|
|
break;
|
|
}
|
|
case 1:
|
|
{ if (plusZero)
|
|
this->Inita(0.);
|
|
this->t[0] = B.t[0]; //on affecte le seul terme
|
|
break;
|
|
}
|
|
default:
|
|
cout << "\n this= " << *this << " B= "; B.Ecriture(cout);
|
|
Message(3,
|
|
"erreur d\'affectation, Tenseur3HB::Affectation_trans_dimension( const TenseurHB & B, ..");
|
|
};
|
|
};
|
|
|
|
// produit contracte avec un vecteur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
CoordonneeH Tenseur3HB::operator * ( const CoordonneeH & B) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != dimension)
|
|
{ cout << "\nErreur : dimensions vecteur tenseur non egales !\n";
|
|
cout << " Tenseur3HB::operator *\n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
CoordonneeH v(dimension);
|
|
v(1) = this->t[0] * B(1) + this->t[1] * B(2) + this->t[2] * B(3);
|
|
v(2) = this->t[3] * B(1) + this->t[4] * B(2) + this->t[5] * B(3);
|
|
v(3) = this->t[6] * B(1) + this->t[7] * B(2) + this->t[8] * B(3);
|
|
return v;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHH & Tenseur3HB::operator * ( const TenseurHH & B) const // produit une fois contracte
|
|
{ TenseurHH * res;
|
|
#ifdef MISE_AU_POINT
|
|
if (Dabs(B.Dimension()) != 3) Message(3,"Tenseur3HB::operator * ( etc..");
|
|
#endif
|
|
res = new Tenseur_ns3HH;
|
|
LesMaillonsHH::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
// on cree systematiquement un tenseur non symetrique
|
|
if (B.Dimension() == 3) // cas symetrique
|
|
{
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[5];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[5];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[5];
|
|
res->t[1] = this->t[0] * B.t[3] + this->t[1] * B.t[1] + this->t[2] * B.t[4];
|
|
res->t[4] = this->t[3] * B.t[3] + this->t[4] * B.t[1] + this->t[5] * B.t[4];
|
|
res->t[7] = this->t[6] * B.t[3] + this->t[7] * B.t[1] + this->t[8] * B.t[4];
|
|
res->t[2] = this->t[0] * B.t[5] + this->t[1] * B.t[4] + this->t[2] * B.t[2];
|
|
res->t[5] = this->t[3] * B.t[5] + this->t[4] * B.t[4] + this->t[5] * B.t[2];
|
|
res->t[8] = this->t[6] * B.t[5] + this->t[7] * B.t[4] + this->t[8] * B.t[2];
|
|
}
|
|
else // cas ou B n'est pas symetrique
|
|
{
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[6];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[6];
|
|
res->t[1] = this->t[0] * B.t[1] + this->t[1] * B.t[4] + this->t[2] * B.t[7];
|
|
res->t[4] = this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
res->t[7] = this->t[6] * B.t[1] + this->t[7] * B.t[4] + this->t[8] * B.t[7];
|
|
res->t[2] = this->t[0] * B.t[2] + this->t[1] * B.t[5] + this->t[2] * B.t[8];
|
|
res->t[5] = this->t[3] * B.t[2] + this->t[4] * B.t[5] + this->t[5] * B.t[8];
|
|
res->t[8] = this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
}
|
|
return (*res); };
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::operator * ( const TenseurHB & B) const // produit une fois contracte
|
|
{ TenseurHB * res;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator * ( etc..");
|
|
#endif
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
res->t[3] = this->t[3] * B.t[0] + this->t[4] * B.t[3] + this->t[5] * B.t[6];
|
|
res->t[6] = this->t[6] * B.t[0] + this->t[7] * B.t[3] + this->t[8] * B.t[6];
|
|
res->t[1] = this->t[0] * B.t[1] + this->t[1] * B.t[4] + this->t[2] * B.t[7];
|
|
res->t[4] = this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
res->t[7] = this->t[6] * B.t[1] + this->t[7] * B.t[4] + this->t[8] * B.t[7];
|
|
res->t[2] = this->t[0] * B.t[2] + this->t[1] * B.t[5] + this->t[2] * B.t[8];
|
|
res->t[5] = this->t[3] * B.t[2] + this->t[4] * B.t[5] + this->t[5] * B.t[8];
|
|
res->t[8] = this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
return (*res); };
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// produit contracte contracté deux fois A(i,j)*B(j,i)=A..B c-c-d : A^i_{.k} * B^k_{.i}
|
|
// -> on contracte d'abord l'indice du milieu puis l'indice externe
|
|
// cela permet d'utiliser les mêmes variances pour les deux tenseurs
|
|
double Tenseur3HB::operator && ( const TenseurHB & B) const // produit deux fois contracte
|
|
{ double b = 0;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator && ( etc..");
|
|
#endif
|
|
b += this->t[0] * B.t[0] + this->t[1] * B.t[3] + this->t[2] * B.t[6];
|
|
b += this->t[3] * B.t[1] + this->t[4] * B.t[4] + this->t[5] * B.t[7];
|
|
b += this->t[6] * B.t[2] + this->t[7] * B.t[5] + this->t[8] * B.t[8];
|
|
return b;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::Trace() const // trace du tenseur
|
|
{ double b;
|
|
b = this->t[0] + this->t[4] + this->t[8];
|
|
return b;};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::II() const // second invariant
|
|
{ //return Dabs((*this && *this)); // on met Dabs car dans les petits nombres on peut avoir des nombres
|
|
double ret = (*this && *this);
|
|
// if (Dabs(ret) < 0.1*ConstMath::pasmalpetit)
|
|
// on part du principe qu'il s'agit du produit doublement contracté d'un tenseur symétrique
|
|
// donc normalement il devrait donner un nombre positif, donc s'il est très petit, on le met arbitrairement à 0
|
|
if (ret < 0.)
|
|
{ret = 0.;}
|
|
return ret;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::III() const // troisieme invariant
|
|
{ Tenseur3HB a; a = ((*this) * (*this));
|
|
return (a && (*this)) ;};
|
|
|
|
// valeurs propre dans le vecteur de retour, classée par ordres "décroissants"
|
|
// cas indique le cas de valeur propre:
|
|
// cas = -1, si l'extraction des valeurs propres n'a pas pu se faire
|
|
// dans ce cas les valeurs propres de retour sont nulles par défaut
|
|
// dim = 3 , 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 val(1)=val(2) ( val(1), et val(3) dans les 2 premières composantes du retour)
|
|
// , cas = 3 si val(2)=val(3) ( val(1), et val(2) dans les 2 premières composantes du retour)
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Coordonnee Tenseur3HB::ValPropre(int& cas) const
|
|
{ Coordonnee ret(3);
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{ cas = 0; ret(1)=ret(2)=ret(3)=b/3.; return ret;};
|
|
// sinon ..
|
|
b=-b; double c=0.5*(b*b-((*this)*(*this)).Trace()) ; double d=-this->Det();
|
|
// maintenant on va essayer de normaliser les termes de l'équation du troisième degré
|
|
// au début on a une équation x^3+B.x^2+C.x+D=0=(x-x1)(x-x2)(x-x3)
|
|
// on veut tenir compte de l'ordre de grandeur des xi avec une transformation: xp=a.x
|
|
// a étant un facteur de normalisation. L'équation en xpi devient:
|
|
// x^3+(a.B).x^2+(a^2.C).x+(a^3.D)=0=x^3+Bp.x^2+Cp.x+Dp, Bp Cp Dp étant les nouveaux coefficients
|
|
// on choisit pour a un coef fonction des valeurs des composantes du tenseur
|
|
double a_N = 1./ this->MaxiComposante(); // coeff de normalisation normalement non nulle
|
|
double bp = b * a_N; double cp = c * a_N*a_N; double dp = d * a_N*a_N*a_N;
|
|
// int caas; // pour la gestion des différents cas de retour de alg_zero.TroisiemeDegre
|
|
// alg_zero.TroisiemeDegre dans certain ne fonctionne pas parfaitement, because , sans doute des arrondis
|
|
// j'essaie donc une résolution directe (voire après) qui a l'air de toujours fonctionner (a voir dans le temps)
|
|
// alg_zero.TroisiemeDegre(1.,bp,cp,dp,ret(1),ret(2),ret(3),caas);
|
|
// #ifdef MISE_AU_POINT
|
|
// if (caas <= 0)
|
|
// { cout << "\n warning **** recherche de valeurs propre du tenseur: pas de racine correcte ! "
|
|
// << "\n tenseur= " << *this << "racines= " << ret
|
|
// << "\n on laisse le calcul se poursuivre cependant"
|
|
// << "\n Coordonnee Tenseur3HB::ValPropre()";
|
|
// cas=-1;
|
|
// ret.Zero();
|
|
// // retour
|
|
// return ret;
|
|
// };
|
|
// #endif
|
|
// ret /= a_N;
|
|
// cout << "\n \n " << ret(1) << " " << ret(2) << " " << ret(3);
|
|
//
|
|
// on va essayer d'utiliser les formules directes analytiques:
|
|
// 1) les invariants: Yavuz Basar and Dieter Weichert, "Nonlinear continuum Mechanis of solids"
|
|
// Sringer, p 33, ISBN 3-540-66601-X, 2000
|
|
double IA=-bp; double IIA=cp; double IIIA=-dp;
|
|
double tp1=IA*IA-3.*IIA; // grandeur intermédiaire qui doit-être positive
|
|
double t1 = 2.*sqrt(MaX(0.,tp1)); // on la met systématiquement à positif et on prend la racine
|
|
// si t1 est nul cela signifie qu'il y a trois valeurs propres égales
|
|
double untiers = 1./3.;
|
|
if (Abs(t1) <= ConstMath::trespetit)
|
|
{ret(1)=ret(2)=ret(3)=untiers*IA;}
|
|
else // sinon cas où l'on peut calculer t2
|
|
{// maintenant une seconde grandeur intermédiaire qui est un cosinus
|
|
double t2 = (2.*IA*IA*IA-9.*IA*IIA+27.*IIIA)/(t1*tp1);
|
|
if (Abs(t2) > 1.) t2 = Signe(t2); // limite à 1 au cas où
|
|
double theta = acos(t2);
|
|
// calcul des valeurs propres
|
|
ret(1)= untiers*(IA+t1*cos(untiers*(theta + 2.* ConstMath::Pi)));
|
|
ret(2)= untiers*(IA+t1*cos(untiers*(theta + 4.* ConstMath::Pi)));
|
|
ret(3)= untiers*(IA+t1*cos(untiers*(theta + 6.* ConstMath::Pi)));
|
|
};
|
|
ret /= a_N;
|
|
|
|
/// caas = 5; // qui est le cas 3 valeurs propres, mais en fait elles peuvent être égales par exemple
|
|
/// cout << "\n " << ret(1) << " " << ret(2) << " " << ret(3);
|
|
|
|
// // dans certains cas meme avec caas ok, il y a des pb ??
|
|
// // dans ce cas on utilise lapack
|
|
// bool pb=false;
|
|
// switch(caas)
|
|
// {
|
|
//// !!!!!!!!! a revoir car ne fonctionne pas en fait !!!!!!!!!
|
|
// case 5: if(ret(3)== ConstMath::tresgrand) pb=true;
|
|
// case 4 : case 1 : if(ret(2)== ConstMath::tresgrand) pb=true;
|
|
// case 2 : case 3 : if(ret(1)== ConstMath::tresgrand) pb=true;
|
|
// default: break;
|
|
// };
|
|
// if (pb)
|
|
// { // pour l'instant on brame !!
|
|
// #ifdef MISE_AU_POINT
|
|
// if (caas <= 0)
|
|
// { cout << "\n warning **** recherche de valeurs propre du tenseur: pas de racine correcte ! "
|
|
// << "\n tenseur= " << *this << "racines= " << ret
|
|
// << "\n on laisse le calcul se poursuivre cependant"
|
|
// << "\n Coordonnee Tenseur3HB::ValPropre()";
|
|
// };
|
|
// #endif
|
|
//
|
|
// }
|
|
|
|
|
|
// classement des valeurs propres
|
|
double vv1,vv2,vv3;
|
|
// if (caas == 5) // cas où il y a 3 racines réelles
|
|
// il n'y a plus qu'un seul cas
|
|
{// d'abord on regarde le plus grand que l'on met dans ret(1)
|
|
if (ret(1) >= ret(2))
|
|
{ if (ret(1) >= ret(3)) { vv1=ret(1); vv2=ret(2); vv3=ret(3);}
|
|
else { vv2=ret(1); ret(1)=vv1=ret(3); vv3=ret(2);};
|
|
}
|
|
else
|
|
{ if (ret(2) >= ret(3)) { vv2=ret(1);ret(1)=vv1=ret(2); vv3=ret(3);}
|
|
else { vv2=ret(1);ret(1)=vv1=ret(3); vv3=ret(2);};
|
|
};
|
|
// puis les deux derniers
|
|
if (vv2 < vv3) { ret(2) = vv3; ret(3) = vv2;vv2=vv3;vv3=ret(2);}
|
|
else { ret(2) = vv2; ret(3) = vv3;};
|
|
// définition du cas de valeurs propres
|
|
// dim = 3 , 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 val(1)=val(2) ( val(1), et val(3) dans les 2 premières composantes du retour)
|
|
// , cas = 3 si val(2)=val(3) ( val(1), et val(2) dans les 2 premières composantes du retour)
|
|
if ( difftrespetit(vv1,vv2) && difftrespetit(vv2,vv3)) {cas = 1;}
|
|
else if ( (EgaleApeuPres(vv1,vv2)) && EgaleApeuPres(vv2,vv3)) {cas = 0;}
|
|
else if ( (EgaleApeuPres(vv1,vv2)) && !EgaleApeuPres(vv2,vv3)) {cas = 2;}
|
|
else if ( !(EgaleApeuPres(vv1,vv2)) && EgaleApeuPres(vv2,vv3)) {cas = 3;}
|
|
else
|
|
{cout << "\n classement des valeurs propres : non realise !! "
|
|
<< "\n vv1= "<<vv1 <<", vv2= "<< vv2 <<", vv3= "<< vv3
|
|
<< "\n r(1)= "<<ret(1) << ", r(2)= "<<ret(2) << ", r(3)= "<<ret(3)
|
|
<< "\n Tenseur3HB::ValPropre(... "<<endl;
|
|
};
|
|
}
|
|
// else if ((caas == 4) || (caas == 1)) // cas où il y a 2 racines
|
|
// {//on regarde le plus grand
|
|
// if (ret(1) < ret(2))
|
|
// { vv2=ret(1); ret(1)=ret(2);ret(2)=vv2; cas=2;};
|
|
// // sinon l'ordre est déjà bon
|
|
// cas=3;
|
|
// }
|
|
// else if ((caas == 2) || (caas == 3))
|
|
// {// cas d'une seule racine
|
|
// cas=0;
|
|
// };
|
|
|
|
// s'il y a eu erreur dans la recherche de valeurs propre on modifie le cas
|
|
// if (caas <= 0) {cas=-1;ret.Zero();};
|
|
|
|
// if (cas <= 0)
|
|
// { cout << "\n warning **** recherche de valeurs propre du tenseur: pas de racine correcte ! "
|
|
// << "\n tenseur= " << *this << "racines= " << ret
|
|
// << "\n on laisse le calcul se poursuivre cependant"
|
|
// << "\n Coordonnee Tenseur3HB::ValPropre()";
|
|
// };
|
|
// retour
|
|
return ret;
|
|
};
|
|
|
|
// idem met en retour la matrice mat contiend par colonne les vecteurs propre
|
|
// elle doit avoir la dimension du tenseur
|
|
// les vecteurs propre sont exprime dans le repere naturel
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
Coordonnee Tenseur3HB::ValPropre(int& cas, Mat_pleine& mat) const
|
|
{ Coordonnee ret(3);
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
// on ramène le tenseur identité en absolue comme base de vecteurs propres car toute base est ok
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{ mat.Initialise(0.); mat(1,1)=1.;mat(2,2)=1.;mat(3,3)=1.;
|
|
cas=0;ret(1)=ret(2)=ret(3)=b/3.;return ret;
|
|
};
|
|
// sinon on commence par rechercher les valeurs propres
|
|
// sinon on commence par calculer les valeurs propres
|
|
Coordonnee valPropre = Tenseur3HB::ValPropre(cas);
|
|
// --- gestion des erreurs éventuelles
|
|
if (cas == -1) // cas d'une erreur
|
|
{mat.Zero(); // mise à 0 de la matrice
|
|
ret.Zero(); // mise à 0 des valeurs propres
|
|
return ret;
|
|
};
|
|
// sinon ok on continue
|
|
// on crée une matrice pour utiliser une routine générale
|
|
#ifdef MISE_AU_POINT
|
|
if ((mat.Nb_ligne() != 3) || (mat.Nb_colonne() != 3))
|
|
{ cout << "\nErreur : la matrice en parametre doit etre de dimension 3x3 ";
|
|
cout << "\n Tenseur3BH::ValPropre(... \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(i,j) = (*this)(i,j);
|
|
int cass;
|
|
Tableau <Coordonnee> V_P = MathUtil2::V_Propres3x3(mat,valPropre,cas);
|
|
// --- gestion des erreurs éventuelles
|
|
if (cas == -1) // cas d'une erreur
|
|
{mat.Zero(); // mise à 0 de la matrice
|
|
ret.Zero(); // mise à 0 des valeurs propres
|
|
return ret;
|
|
};
|
|
// sinon c'est ok, on continue
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(j,i) = V_P(i)(j); // le vecteur propre i, sa coordonnée j
|
|
//retour
|
|
return ret;
|
|
};
|
|
|
|
// ici il s'agit uniquement de calculer les vecteurs propres, les valeurs propres
|
|
// étant déjà connues
|
|
// en retour VP les vecteurs propre: doivent avoir la dimension du tenseur
|
|
// les vecteurs propre sont exprime dans le repere naturel (pour les tenseurs dim 3
|
|
// pour dim=2:le premier vecteur propre est exprime dans le repere naturel
|
|
// le second vecteur propre est exprimé dans le repère dual
|
|
// pour dim=1 le vecteur est dans la base naturelle (mais ça importe pas)
|
|
// en sortie cas = -1 s'il y a eu un problème, dans ce cas, V_P est quelconque
|
|
// sinon si tout est ok, cas est identique en sortie avec l'entrée
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
void Tenseur3HB::VecteursPropres(const Coordonnee& valPropre,int& cas, Tableau <Coordonnee>& V_P) const
|
|
{ // on dimensionne en conséquence
|
|
Coordonnee toto(3); // un vecteur nul
|
|
V_P.Change_taille(3,toto); // tableau initialisé à 0
|
|
|
|
// si le tenseur est sphérique, les trois valeurs propres sont identique au 1/3 de la trace
|
|
// on ramène le tenseur identité en absolue comme base de vecteurs propres car toute base est ok
|
|
double b = this->Trace(); // la trace
|
|
double sqrt_II_b = sqrt(Dabs(this->II() - Sqr(b) / 3.)) ; // l'intensité du déviateur
|
|
if (sqrt_II_b <= ConstMath::unpeupetit * Dabs(b) )
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (cas != 0)
|
|
{ cout << "\nErreur : les valeurs propres devraient etre identiques alors qu'en entree: cas= " << cas ;
|
|
cout << "\n Tenseur3HB::VecteursPropres(... \n";
|
|
cas=-1;
|
|
return;
|
|
};
|
|
#endif
|
|
V_P(1).Zero(); V_P(1)(1)=1.;
|
|
V_P(2).Zero(); V_P(2)(2)=1.;
|
|
V_P(3).Zero(); V_P(3)(3)=1.;
|
|
cas=0;return;
|
|
};
|
|
// sinon ok on continue
|
|
// on crée une matrice pour utiliser une routine générale
|
|
Mat_pleine mat(3,3,0.);
|
|
for (int i=1;i<=3;i++)
|
|
for (int j=1;j<=3;j++)
|
|
mat(i,j) = (*this)(i,j);
|
|
int cass;
|
|
V_P = MathUtil2::V_Propres3x3(mat,valPropre,cas);
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::Det() const // determinant de la matrice des coordonnees
|
|
{ double b = 0;
|
|
b += this->t[0] *(this->t[4] * this->t[8] - this->t[5] * this->t[7]);
|
|
b -= this->t[3] *(this->t[1] * this->t[8] - this->t[2] * this->t[7]);
|
|
b += this->t[6] *(this->t[1] * this->t[5] - this->t[2] * this->t[4]);
|
|
return b;};
|
|
// test
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
int Tenseur3HB::operator == ( const TenseurHB & B) const
|
|
{ int res = 1;
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator == ( etc..");
|
|
#endif
|
|
for (int i = 0; i<=8; i++)
|
|
if (this->t[i] != B.t[i]) res = 0 ;
|
|
return res; };
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
int Tenseur3HB::operator != ( const TenseurHB & B) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if (B.Dimension() != 3) Message(3,"Tenseur3HB::operator != ( etc..");
|
|
#endif
|
|
if ((*this) == B)
|
|
return 0;
|
|
else
|
|
return 1; };
|
|
// calcul du tenseur inverse par rapport au produit contracte
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::Inverse() const
|
|
{TenseurHB * res;
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
// choix sur la méthode d'inversion
|
|
switch (ParaGlob::param->ParaAlgoControleActifs().Type_calnum_inversion_metrique())
|
|
{ case LU_EQUILIBRE:
|
|
{ // on recopie this dans le nouveau tenseur
|
|
for (int i = 0; i< 9; i++)
|
|
res->t[i] = t[i];
|
|
|
|
// pour le débug
|
|
//res->t[0]=3.; res->t[1]=2.;res->t[2]=1.;
|
|
|
|
// appel de l'inversion
|
|
Util::Inverse_mat3x3(((Tenseur3HB *) res)->ipointe);
|
|
}
|
|
break;
|
|
//cout << "\n comp \n ";
|
|
// res->Ecriture(cout); cout << "\n";
|
|
case CRAMER : // méthode historique
|
|
{ // calcul du determinant
|
|
double det = Det();
|
|
#ifdef MISE_AU_POINT
|
|
if (Dabs(det) <= ConstMath::trespetit)
|
|
{ cout << "\nErreur : le determinant du tenseur est nul !\n";
|
|
cout << "Tenseur3HB::Inverse() \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
det =1./det;
|
|
res->t[0] = (this->t[4]*this->t[8] - this->t[5]*this->t[7])*det;
|
|
res->t[3] = (this->t[5]*this->t[6] - this->t[3]*this->t[8])*det;
|
|
res->t[6] = (this->t[3]*this->t[7] - this->t[4]*this->t[6])*det;
|
|
res->t[1] = (this->t[2]*this->t[7] - this->t[1]*this->t[8])*det;
|
|
res->t[4] = (this->t[0]*this->t[8] - this->t[2]*this->t[6])*det;
|
|
res->t[7] = (this->t[1]*this->t[6] - this->t[0]*this->t[7])*det;
|
|
res->t[2] = (this->t[1]*this->t[5] - this->t[2]*this->t[4])*det;
|
|
res->t[5] = (this->t[2]*this->t[3] - this->t[0]*this->t[5])*det;
|
|
res->t[8] = (this->t[0]*this->t[4] - this->t[1]*this->t[3])*det;
|
|
}
|
|
break;
|
|
default:
|
|
{ cout << "\nErreur **** : la methode de resolution de l'inversion de tenseur "
|
|
<< ParaGlob::param->ParaAlgoControleActifs().Type_calnum_inversion_metrique() << " n'est pas implante \n";
|
|
cout << "Tenseur3BH::Inverse() \n";
|
|
Sortie(1);
|
|
};
|
|
break;
|
|
};
|
|
// res->Ecriture(cout); // pour le debug
|
|
return *res;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurBH & Tenseur3HB::Transpose() const
|
|
{ TenseurBH * res;
|
|
res = new Tenseur3BH;
|
|
LesMaillonsBH::NouveauMaillon(res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = this->t[0];
|
|
res->t[1] = this->t[3];
|
|
res->t[2] = this->t[6];
|
|
res->t[3] = this->t[1];
|
|
res->t[4] = this->t[4];
|
|
res->t[5] = this->t[7];
|
|
res->t[6] = this->t[2];
|
|
res->t[7] = this->t[5];
|
|
res->t[8] = this->t[8];
|
|
return *res;};
|
|
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// permute Bas Haut, mais reste dans le même tenseur
|
|
void Tenseur3HB::PermuteHautBas()
|
|
{ // t[0] = t[0];
|
|
double t1=t[1]; t[1] = t[3];
|
|
double t2=t[2]; t[2] = t[6];
|
|
t[3] = t1;
|
|
//[4] = [4];
|
|
double t5=t[5]; t[5] = t[7];
|
|
t[6] = t2;
|
|
t[7] = t5;
|
|
//t[8] = t[8];
|
|
};
|
|
|
|
// calcul du maximum en valeur absolu des composantes du tenseur
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::MaxiComposante() const
|
|
{ return DabsMaxiTab(t, 9) ;
|
|
};
|
|
|
|
// retourne la composante i,j en lecture et écriture
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double& Tenseur3HB::Coor( const int i, const int j)
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ( ((i!=1)&&(i!=2)&&(i!=3)) || ((j!=1)&&(j!=2)&&(j!=3)) )
|
|
{ cout << "\nErreur : composante inexistante !\n";
|
|
cout << " i = " << i << "j = " << j << '\n';
|
|
cout << "TenseurHH::Coor(int,int ) \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
switch (i)
|
|
{ case 1 : { switch (j)
|
|
{ case 1 : return t[0]; break;
|
|
case 2 : return t[1]; break;
|
|
case 3 : return t[2]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 2 : { switch (j)
|
|
{ case 1 : return t[3]; break;
|
|
case 2 : return t[4]; break;
|
|
case 3 : return t[5]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 3 : { switch (j)
|
|
{ case 1 : return t[6]; break;
|
|
case 2 : return t[7]; break;
|
|
case 3 : return t[8]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
default : return t[0];
|
|
}
|
|
};
|
|
// retourne la composante i,j en lecture seulement
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
double Tenseur3HB::operator () ( const int i, const int j) const
|
|
{
|
|
#ifdef MISE_AU_POINT
|
|
if ( ((i!=1)&&(i!=2)&&(i!=3)) || ((j!=1)&&(j!=2)&&(j!=3)) )
|
|
{ cout << "\nErreur : composante inexistante !\n";
|
|
cout << " i = " << i << "j = " << j << '\n';
|
|
cout << "TenseurHH::OPERATOR() (int,int ) \n";
|
|
Sortie(1);
|
|
};
|
|
#endif
|
|
switch (i)
|
|
{ case 1 : { switch (j)
|
|
{ case 1 : return t[0]; break;
|
|
case 2 : return t[1]; break;
|
|
case 3 : return t[2]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 2 : { switch (j)
|
|
{ case 1 : return t[3]; break;
|
|
case 2 : return t[4]; break;
|
|
case 3 : return t[5]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
case 3 : { switch (j)
|
|
{ case 1 : return t[6]; break;
|
|
case 2 : return t[7]; break;
|
|
case 3 : return t[8]; break;
|
|
default : return t[0]; }
|
|
break;}
|
|
default : return t[0];
|
|
}
|
|
};
|
|
|
|
//fonctions static définissant le produit tensoriel de deux vecteurs
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
TenseurHB & Tenseur3HB::Prod_tensoriel(const CoordonneeH & aH, const CoordonneeB & bB)
|
|
{ TenseurHB * res;
|
|
#ifdef MISE_AU_POINT
|
|
if ((aH.Dimension() != 3) || (bB.Dimension() != 3))
|
|
{ cout << "\n erreur de dimension dans les coordonnées d'entrée, dim1 et dim2 ="
|
|
<< aH.Dimension() << " " << bB.Dimension()
|
|
<< "\n Tenseur2HB::Prod_tensoriel( etc.." << endl;
|
|
Sortie(1);
|
|
}
|
|
#endif
|
|
res = new Tenseur3HB;
|
|
LesMaillonsHB::NouveauMaillon( res); // ajout d'un tenseur intermediaire
|
|
res->t[0] = aH(1) * bB(1); res->t[1] = aH(1) * bB(2); res->t[2] = aH(1) * bB(3);
|
|
res->t[3] = aH(2) * bB(1); res->t[4] = aH(2) * bB(2); res->t[5] = aH(2) * bB(3);
|
|
res->t[6] = aH(3) * bB(1); res->t[7] = aH(3) * bB(2); res->t[8] = aH(3) * bB(3);
|
|
return *res ;};
|
|
|
|
// lecture et écriture de données
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
istream & Tenseur3HB::Lecture(istream & entree)
|
|
{ // lecture et vérification du type
|
|
string nom_type;
|
|
entree >> nom_type;
|
|
if (nom_type != "Tenseur3HB")
|
|
{ Sortie(1);
|
|
return entree;
|
|
}
|
|
// lecture des coordonnées
|
|
for (int i = 0; i< 9; i++)
|
|
entree >> this->t[i];
|
|
return entree;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
ostream & Tenseur3HB::Ecriture(ostream & sort) const
|
|
{ // écriture du type
|
|
sort << "Tenseur3HB ";
|
|
// puis les datas
|
|
for (int i = 0; i< 9; i++)
|
|
sort << setprecision(ParaGlob::NbdigdoCA()) << this->t[i] << " ";
|
|
return sort;
|
|
};
|
|
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// surcharge de l'operator de lecture
|
|
istream & operator >> (istream & entree, Tenseur3HB & A)
|
|
{ int dim = A.Dimension();
|
|
#ifdef MISE_AU_POINT
|
|
if (dim != 3) A.Message(3,"operator >> (istream & entree, Tenseur3HB & A)");
|
|
#endif
|
|
// lecture et vérification du type
|
|
string nom_type;
|
|
entree >> nom_type;
|
|
if (nom_type != "Tenseur3HB")
|
|
{ Sortie(1);
|
|
return entree;
|
|
}
|
|
// lecture des coordonnées
|
|
for (int i = 0; i< 9; i++)
|
|
entree >> A.t[i];
|
|
return entree;
|
|
};
|
|
#ifndef MISE_AU_POINT
|
|
inline
|
|
#endif
|
|
// surcharge de l'operator d'ecriture
|
|
ostream & operator << (ostream & sort , const Tenseur3HB & A)
|
|
{ //int dim = A.Dimension();
|
|
// écriture du type
|
|
sort << "Tenseur3HB ";
|
|
// puis les datas
|
|
for (int i = 0; i< 9; i++)
|
|
sort << setprecision(ParaGlob::NbdigdoCA()) << A.t[i] << " ";
|
|
return sort;
|
|
};
|
|
|
|
|
|
#endif
|