Herezh_dev/herezh_pp/comportement/hysteresis/Hysteresis3D_2.cc

2818 lines
161 KiB
C++
Executable file

// FICHIER : Hysteresis3D.cc
// CLASSE : Hysteresis3D
// 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 <iostream>
using namespace std; //introduces namespace std
#include <math.h>
#include <stdlib.h>
#include "Sortie.h"
#include "ConstMath.h"
#include "MatLapack.h"
#include "ExceptionsLoiComp.h"
#include "TenseurQ3gene.h"
#include "Hysteresis3D.h"
// ========== codage des METHODES VIRTUELLES protegees:================
// calcul des contraintes
void Hysteresis3D::Calcul_SigmaHH (TenseurHH & sigHH_t,TenseurBB& ,DdlElement & tab_ddl,
TenseurBB & ,TenseurHH & ,BaseB& ,BaseH& ,TenseurBB& epsBB_,
TenseurBB& delta_epsBB_,TenseurBB & gijBB_,
TenseurHH & gijHH_,Tableau <TenseurBB *>& d_gijBB_,double& ,double& ,
TenseurHH & sigHH_
,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double& module_cisaillement
,const Met_abstraite::Expli_t_tdt& )
{
#ifdef MISE_AU_POINT
if (epsBB_.Dimension() != 3)
{ cout << "\nErreur : la dimension devrait etre 3 !\n";
cout << " Hysteresis3D::Calcul_SigmaHH\n";
Sortie(1);
};
if (tab_ddl.NbDdl() != d_gijBB_.Taille())
{ cout << "\nErreur : le nb de ddl est != de la taille de d_gijBB_ !\n";
cout << " Hysteresis3D::Calcul_SigmaHH\n";
Sortie(1);
};
#endif
const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_); // passage en dim 3
const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_); // " " " "
const Tenseur3BB & gijBB = *((Tenseur3BB*) &gijBB_); // " " " "
Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_); // " " " "
// Tenseur3HH & sigHH_i = *((Tenseur3HH*) &sigHH_t); // " " " "
SaveResulHysteresis3D & save_resul = *((SaveResulHysteresis3D*) saveResul);
// initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
// cas d'une dépendance à la phase de la déformation totale
if (avec_phase_paradefEqui || avec_phaseEps)
{ xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
ParaMateriauxAvecPhaseEpsilon(gijHH,epsBB,xnp,xmu,Qzero);
};
// === 1 == calcul de l'avancement temporel sur 1 pas,
int cas = 1; // cas normal avec dérivée de Jauman
// try { // débug
Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
// débug---------
/* }
catch (ErrNonConvergence_loiDeComportement excep)
{ // initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
Avancement_temporel(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ);
}
catch ( ... )
{ // initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
Avancement_temporel(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ);
}
*/
// Verif_coincidence(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ,true);
// fin débug -------------
// on libère les tenseurs intermédiaires
LibereTenseur();LibereTenseurQ();
};
// calcul des contraintes a t+dt et de ses variations
void Hysteresis3D::Calcul_DsigmaHH_tdt (TenseurHH & sigHH_t,TenseurBB& ,DdlElement & tab_ddl
,BaseB& ,TenseurBB & ,TenseurHH &
,BaseB& ,Tableau <BaseB> & ,BaseH& ,Tableau <BaseH> &
,TenseurBB & epsBB_tdt,Tableau <TenseurBB *>& d_epsBB,TenseurBB & delta_epsBB_
,TenseurBB & gijBB_tdt ,TenseurHH & gijHH_tdt
,Tableau <TenseurBB *>& d_gijBB_tdt
,Tableau <TenseurHH *>& d_gijHH_tdt,double& ,double&
,Vecteur& ,TenseurHH& sigHH_tdt,Tableau <TenseurHH *>& d_sigHH
,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite
,double& module_cisaillement,const Met_abstraite::Impli& )
{
#ifdef MISE_AU_POINT
if (epsBB_tdt.Dimension() != 3)
{ cout << "\nErreur : la dimension devrait etre 3 !\n";
cout << " Hysteresis3D::Calcul_DsigmaHH_tdt\n";
Sortie(1);
};
if (tab_ddl.NbDdl() != d_gijBB_tdt.Taille())
{ cout << "\nErreur : le nb de ddl est != de la taille de d_gijBB_tdt !\n";
cout << " Hysteresis3D::Calcul_DsigmaHH_tdt\n";
Sortie(1);
};
#endif
const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_tdt); // " " " "
const Tenseur3BB & gijBB = *((Tenseur3BB*) &gijBB_tdt); // " " " "
Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_tdt); // " " " "
// Tenseur3HH & sigHH_i = *((Tenseur3HH*) &sigHH_t); // " " " "
SaveResulHysteresis3D & save_resul = *((SaveResulHysteresis3D*) saveResul);
// initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
// cas d'une dépendance à la phase de la déformation totale
if (avec_phase_paradefEqui || avec_phaseEps)
{ xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
ParaMateriauxAvecPhaseEpsilon(gijHH,epsBB,xnp,xmu,Qzero);
};
// === 1 == calcul de l'avancement temporel sur 1 pas,
int cas = 1; // cas normal avec dérivée de Jauman
Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
// ==== 2 === calcul de l'opérateur tangent =============
Hysteresis3D::Dsig_d_ddl(d_sigHH,epsBB_tdt,gijHH_tdt,d_gijBB_tdt,d_gijHH_tdt,d_epsBB );
// débug---------
// Verif_coincidence(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ,true);
// fin débug -------------
// on libère les tenseurs intermédiaires
LibereTenseur();LibereTenseurQ();
};
// calcul des contraintes et ses variations par rapport aux déformations a t+dt
// en_base_orthonormee: le tenseur de contrainte en entrée est en orthonormee
// le tenseur de déformation et son incrémentsont également en orthonormees
// si = false: les bases transmises sont utilisées
// ex: contient les éléments de métrique relativement au paramétrage matériel = X_(0)^a
void Hysteresis3D::Calcul_dsigma_deps (bool en_base_orthonormee, TenseurHH & sigHH_t,TenseurBB&
,TenseurBB & epsBB_tdt,TenseurBB & delta_epsBB_,double& ,double&
,TenseurHH& sigHH_tdt,TenseurHHHH& d_sigma_deps
,EnergieMeca & energ,const EnergieMeca & energ_t,double& module_compressibilite,double& module_cisaillement
,const Met_abstraite::Umat_cont& ex)
{
#ifdef MISE_AU_POINT
if (epsBB_tdt.Dimension() != 3)
{ cout << "\nErreur : la dimension devrait etre 3 !\n";
cout << " Hysteresis3D::Calcul_dsigma_deps\n";
Sortie(1);
};
#endif
const Tenseur3HH & gijHH = *((Tenseur3HH*) ex.gijHH_tdt); // " " " "
const Tenseur3BB & gijBB = *((Tenseur3BB*) ex.gijBB_tdt); // " " " "
const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
const Tenseur3BB & delta_epsBB = *((Tenseur3BB*) &delta_epsBB_); // passage en dim 3
Tenseur3HH & sigHH = *((Tenseur3HH*) &sigHH_tdt); // " " " "
// Tenseur3HH & sigHH_i = *((Tenseur3HH*) &sigHH_t); // " " " "
SaveResulHysteresis3D & save_resul = *((SaveResulHysteresis3D*) saveResul);
// initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
// cas d'une dépendance à la phase de la déformation totale
if (avec_phase_paradefEqui || avec_phaseEps)
{ xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
if (en_base_orthonormee)
ParaMateriauxAvecPhaseEpsilon(IdHH3,epsBB,xnp,xmu,Qzero);
else
ParaMateriauxAvecPhaseEpsilon(gijHH,epsBB,xnp,xmu,Qzero);
};
// === 1 == calcul de l'avancement temporel sur 1 pas,
// ici il n'y a pas de différence entre orthonormeee ou pas au niveau du type de calcul
int cas = 1; // donc cas avec dérivée de Jauman en mixte
if (en_base_orthonormee)
Avancement_temporel(delta_epsBB,IdHH3,IdBB3,cas,save_resul,sigHH,energ_t,energ);
else
Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
// ==== 2 === calcul de l'opérateur tangent =============
// Hysteresis3D::Dsig_depsilon(en_base_orthonormee,gijHH,d_sigma_deps);
// try { // débug
Hysteresis3D::Dsig_depsilon(en_base_orthonormee,gijHH,d_sigma_deps,sigHH);
// débug---------
// }
// catch (ErrNonConvergence_loiDeComportement excep)
// { // initialisation des variables de travail
// save_resul.Init_debut_calcul();
// // initialisation éventuelle des variables thermo-dépendantes
// Init_thermo_dependance();
// if (en_base_orthonormee)
// Avancement_temporel(delta_epsBB,IdHH3,IdBB3,cas,save_resul,sigHH,energ_t,energ);
// else
// Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
// Hysteresis3D::Dsig_depsilon(en_base_orthonormee,gijHH,d_sigma_deps);
// }
// catch ( ... )
// { // initialisation des variables de travail
// racine.Change_taille(9);
// save_resul.Init_debut_calcul();
// // initialisation éventuelle des variables thermo-dépendantes
// Init_thermo_dependance();
// if (en_base_orthonormee)
// Avancement_temporel(delta_epsBB,IdHH3,IdBB3,cas,save_resul,sigHH,energ_t,energ);
// else
// Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
// Hysteresis3D::Dsig_depsilon(en_base_orthonormee,gijHH,d_sigma_deps);
// };
// Verif_coincidence(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ,true);
// fin débug -------------
// on libère les tenseurs intermédiaires
LibereTenseur();LibereTenseurQ();
};
// =============== fonction protegee ============
// calcul de la fonction résidu de la résolution de l'équation constitutive
// l'argument test ramène
// . 1 si le calcul a été ok, -1 s'il y a eu un pb, mais on peut continuer, 0 s'il y a eu un pb
// fatal, qui invalide le calcul du résidu
Vecteur& Hysteresis3D::Residu_constitutif (const double & alpha,const Vecteur & x, int& test)
{ // récupération du vecteur delta_sigma
for (int i=1;i<=9;i++) // accroissement de t à tdt
rdelta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i)) = x(i);
test = 1; // init par défaut
// variation de sigma de R à tdt
rdelta_sigma_barre_BH_Ratdt = sigma_i_barre_BH + rdelta_sigma_barre_tdt_BH - sigma_barre_BH_R;
delta_barre_alpha_epsBH = alpha * delta_barre_epsBH; // limitation de la charge
// -- calcul de QdeltaSigma
QdeltaSigmaRatdt = sqrt(rdelta_sigma_barre_BH_Ratdt.II());
// -- calculs relatifs aux angles de phases
Cal_wprime(QdeltaSigmaRatdt,rdelta_sigma_barre_BH_Ratdt,Q_OiaR,delta_sigma_barre_BH_OiaR
,wBase,rdelta_sigma_barre_tdt_BH,wprime,wprime_point,trajet_neutre);
// --- si dépendance de la phase de sigma0i_tdt (et non delta sigma) mise à jour des para matériaux
if (avec_phaseDeltaSig)
{xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
ParaMateriauxAvecPhaseDeltaSig(xnp,delta_sigma_barre_BH_OiaR,rdelta_sigma_barre_BH_Ratdt,xmu,Qzero);
};
// -- modif 7 mai 2012 ---
// dans le cas où le phidt est négatif, l'équation constitutive n'est plus valide, dans ce cas on considère
// que phi est nulle, c-a-d que l'on évolue suivant un trajet neutre ce qui n'est sans doute pas l'idéal, mais permet d'éviter l'explosion
// -- calcul de phidt
double phidt = (rdelta_sigma_barre_BH_Ratdt && delta_barre_alpha_epsBH) ; // init partie radial // -- modif 16 juin 2012 --
if (!trajet_neutre) // -- modif 16 juin 2012 --
phidt -= QdeltaSigmaRatdt * QdeltaSigmaRatdt * wprime_point / (2. * xmu * wprime); // -- modif 16 juin 2012 --
// if ((phidt < 0) && force_phi_zero_si_negatif) // -- modif 16 juin 2012 --
if (phidt < 0) // -- modif 9 fev 2015 --
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 8)) || (Permet_affichage() > 8) )
cout << "\n phidt= " << phidt << "\n Hysteresis3D::Residu_constitutif(..." << endl;
if ( Dabs(phidt) < force_phi_zero_si_negatif) // -- modif 9 fev 2015 --
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5) )
{ cout << "\n attention on utilise une valeur de phi negative dans pour le calcul de l'equation constitutive "
<< " phidt= " << phidt;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::Residu_constitutif(..." << endl;
};
phidt = 0.;trajet_neutre = true;
test = -1; // c'est un pb mais pas fatal
};
};
// fin modif modif 7 mai 2012 ---
if (trajet_neutre)
{ // si c'est un trajet neutre, l'équation constitutive est beaucoup plus simple: sigma_point = 2 mu D_barre
// -- calcul du résidu
residuBH = rdelta_sigma_barre_tdt_BH - 2. * xmu * delta_barre_alpha_epsBH;
// --- si dépendance à la déformation équivalente on calcul le xnp correspondant à un phi = 0
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
double phitau = 0.;
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigmaRatdt,phitau,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
}
else
{ // cas d'un trajet non neutre
// modif 7 mai 2012 --- on ne recalcule plus le phi qui a été calculé plus haut pour savoir s'il était négatif
// // -- calcul de phidt
// double phidt = (rdelta_sigma_barre_BH_Ratdt && delta_barre_alpha_epsBH)
// - QdeltaSigmaRatdt * QdeltaSigmaRatdt * wprime_point / (2. * xmu * wprime);
// --- si dépendance à la déformation équivalente
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigmaRatdt,phidt,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
// -- calcul de Beta
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
double beta=0.; // init dans le cas où ne le calcul pas après
if (QdeltaSigmaRatdt >= ConstMath::petit)
// on ne calcul beta que si la norme de deltaSigmaRatdt est significative
{if (xnp == 2.) { beta = - 2. * xmu * unsurwprimeQ0_puiss_np;}
else {beta = - 2. * xmu * unsurwprimeQ0_puiss_np * pow(QdeltaSigmaRatdt,xnp-2.);};
};
// -- calcul du résidu
residuBH = rdelta_sigma_barre_tdt_BH
- 2. * xmu * delta_barre_alpha_epsBH - beta * phidt * rdelta_sigma_barre_BH_Ratdt;
};
// -- retour du résidu
for (int i=1;i<=9;i++)
residu(i) = residuBH(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i));
return residu;
};
// calcul de la matrice tangente de la résolution de l'équation constitutive
// l'argument test ramène
// . 1 si le calcul a été ok, -1 s'il y a eu un pb, mais on peut continuer, 0 s'il y a eu un pb
// fatal, qui invalide le calcul du résidu et de la dérivée
Mat_abstraite& Hysteresis3D::Mat_tangente_constitutif
(const double & alphap,const Vecteur & x, Vecteur& residu, int& test)
{ // récupération du vecteur delta_sigma
for (int i=1;i<=9;i++) // accroissement de t à tdt
rdelta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i)) = x(i);
test = 1; // init par défaut
rdelta_sigma_barre_BH_Ratdt = sigma_i_barre_BH + rdelta_sigma_barre_tdt_BH - sigma_barre_BH_R;
delta_barre_alpha_epsBH = alphap * delta_barre_epsBH; // limitation de la charge
// -- calcul de QdeltaSigmaRatdt
QdeltaSigmaRatdt = sqrt(rdelta_sigma_barre_BH_Ratdt.II());
// -- calculs relatifs aux angles de phases
if (avecVarWprimeS)
{Cal_wprime_et_der(QdeltaSigmaRatdt,rdelta_sigma_barre_BH_Ratdt,Q_OiaR,delta_sigma_barre_BH_OiaR
,wBase,rdelta_sigma_barre_tdt_BH,wprime,d_wprime,wprime_point,d_wprime_point,trajet_neutre);
}
else
{Cal_wprime(QdeltaSigmaRatdt,rdelta_sigma_barre_BH_Ratdt,Q_OiaR,delta_sigma_barre_BH_OiaR
,wBase,rdelta_sigma_barre_tdt_BH,wprime,wprime_point,trajet_neutre);
d_wprime.Inita(0.);
d_wprime_point.Inita(0.);
};
// --- si dépendance de la phase de sigma0i_tdt (et non delta sigma) mise à jour des para matériaux
if (avec_phaseDeltaSig)
{xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
ParaMateriauxAvecPhaseDeltaSig(xnp,delta_sigma_barre_BH_OiaR,rdelta_sigma_barre_BH_Ratdt,xmu,Qzero);
};
//---- débug
// wprime = 1.;wprime_point=0.;trajet_neutre = false;
// --- fin débug
// -- modif 7 mai 2012 ---
// dans le cas où le phidt est négatif, l'équation constitutive n'est plus valide, dans ce cas on considère
// que phi est nulle, c-a-d que l'on évolue suivant un trajet neutre ce qui n'est sans doute pas l'idéal, mais permet d'éviter l'explosion
// calcul de phidt
double phidt = (rdelta_sigma_barre_BH_Ratdt && delta_barre_alpha_epsBH) ; // init partie radial // -- modif 16 juin 2012 --
if (!trajet_neutre) // -- modif 16 juin 2012 --
phidt -= QdeltaSigmaRatdt * QdeltaSigmaRatdt * wprime_point / (2. * xmu * wprime); // -- modif 16 juin 2012 --
// if ((phidt < 0) && force_phi_zero_si_negatif) // -- modif 16 juin 2012 --
if (phidt < 0) // -- modif 9 fev 2015 --
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 8)) || (Permet_affichage() > 8) )
cout << "\n phidt= " << phidt << "\n Hysteresis3D::Mat_tangente_constitutif(..." << endl;
if ( Dabs(phidt) < force_phi_zero_si_negatif) // -- modif 9 fev 2015 --
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
{ cout << "\n attention on utilise une valeur de phi negative dans pour le calcul de l'equation constitutive "
<< " phidt= " << phidt;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::Mat_tangente_constitutif(..." << endl;
};
phidt = 0.; trajet_neutre=true;
test = -1; // c'est un pb mais pas fatal
};
};
// fin modif modif 7 mai 2012 ---
if (trajet_neutre)
{ // si c'est un trajet neutre, l'équation constitutive est beaucoup plus simple: sigma_point = 2 mu D_barre
// -- calcul du résidu
residuBH = rdelta_sigma_barre_tdt_BH - 2. * xmu * delta_barre_alpha_epsBH;
// variation du résidu et retour du résidu
for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
residu(ig) = residuBH(i,j);
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
derResidu(ig,jg) = IdBH3(i,k)*IdBH3(l,j);
};
};
// --- si dépendance à la déformation équivalente on calcul le xnp correspondant à un phi = 0
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
double phitau = 0.;
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigmaRatdt,phitau,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
}
else
{ // cas d'un trajet non neutre
// modif 7 mai 2012 --- on ne recalcule plus le phi qui a été calculé plus haut pour savoir s'il était négatif
// // calcul de phidt
// double phidt = (rdelta_sigma_barre_BH_Ratdt && delta_barre_alpha_epsBH)
// - QdeltaSigmaRatdt * QdeltaSigmaRatdt * wprime_point / (2. * xmu * wprime);
// --- si dépendance à la déformation équivalente
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigmaRatdt,phidt,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
// -- calcul de Beta
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
double beta=0.; // init dans le cas où ne le calcul pas après
double unsurQdeltaSigma= ConstMath::grand; // on limite la valeur par exemple pour le démarrage
double puiss = 1.; // variable intermédiaire qui resert par la suite
if (QdeltaSigmaRatdt >= ConstMath::petit)
// on ne calcul beta que si la norme de deltaSigmaRatdt est significative
// idem pour unsurQdeltaSigma
{unsurQdeltaSigma=1./QdeltaSigmaRatdt;
if (xnp == 2.) { beta = - 2. * xmu * unsurwprimeQ0_puiss_np;}
else {puiss = pow(QdeltaSigmaRatdt,xnp-2.);
beta = - 2. * xmu * unsurwprimeQ0_puiss_np * pow(QdeltaSigmaRatdt,xnp-2.);
};
};
// calcul du résidu
residuBH = rdelta_sigma_barre_tdt_BH
- 2. * xmu * delta_barre_alpha_epsBH - beta * phidt * rdelta_sigma_barre_BH_Ratdt;
// -- calcul de la variation du résidu
// 1 # variation de QdeltaSigmaRatdt ;
// -- calcul de la variation de QdeltaSigmaRatdt par rapport à sigma_barre
Tenseur3BH d_QdeltaSigmaRatdt(unsurQdeltaSigma * rdelta_sigma_barre_BH_Ratdt);
d_QdeltaSigmaRatdt.PermuteHautBas();
// 2 # variation de beta
Tenseur3BH d_beta; // initialisé par défaut à 0
if (QdeltaSigmaRatdt >= ConstMath::petit)
// dans le cas ou la norme de deltaSigmaRatdt n'est pas significative, beta est mis à zero
// il en est de même pour le cas où xnp = 2, pour lequel beta est constant ainsi que sa variation.
// A part ces deux cas on peut calculer d_beta
{if (xnp != 2.)
{double a = 2. * xmu * unsurwprimeQ0_puiss_np * puiss;
d_beta = (a * (2.-xnp) * unsurQdeltaSigma) * d_QdeltaSigmaRatdt
+ ( a *xnp / wprime) * d_wprime;
}; // si xnp==2: cas où d_beta est nul, déjà fait dans l'initialisation de d_beta
};
// 3 # variation de phidt
Tenseur3BH d_phidt(delta_barre_alpha_epsBH);
d_phidt.PermuteHautBas();
d_phidt -= (wprime_point*QdeltaSigmaRatdt/(xmu*wprime))*d_QdeltaSigmaRatdt;
d_phidt -= (QdeltaSigmaRatdt*QdeltaSigmaRatdt/2. * xmu)*
(d_wprime_point/wprime - (wprime_point/(wprime*wprime))*d_wprime);
// 4 # variation du résidu et retour du résidu
for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
residu(ig) = residuBH(i,j);
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
derResidu(ig,jg) = (1.-beta * phidt)*IdBH3(i,k)*IdBH3(l,j)
- (d_beta(k,l) * phidt + beta * d_phidt(k,l))
* rdelta_sigma_barre_BH_Ratdt(i,j);
};
};
};// fin du cas non neutre
calcul_dResi_dsig = true; // on indique que la matrice est calculée
return derResidu;
};
// calcul de l'opérateur tangent : dsigma/depsilon
TenseurHHHH& Hysteresis3D::Dsig_depsilon
(bool en_base_orthonormee,const Tenseur3HH & gijHH_tdt, TenseurHHHH& dsig_deps_
,TenseurHH & sigHH)
{ // -- calcul de la matrice MPC
Dsig_d_(MPC);
// -- calcul de dsigma / d_eps
// comme le tenseur des contraintes est symétrique, idem pour le tenseur de déformation
// on doit avoir un tenseur d'ordre 4 symétrique par rapport aux deux premiers indices
// et symétrique par rapport aux deux derniers indices
// donc modif à faire -> on devrait itérer de 1 à 6 et non de 1 à 9 <<<<< !!!!!
// ===> non ! car en fait il y a de la non symétrie qui traîne... voir modif plus bas
Tenseur3HHHH & dsig_deps = *((Tenseur3HHHH*) &dsig_deps_);
// TenseurQ3geneHHHH & dsig_deps = *((TenseurQ3geneHHHH*) &dsig_deps_);
// dans le cas d'une base orthonormeee, la position des indices importe peu, donc l'opérateur
// déjà calculé est ok
if (en_base_orthonormee)
{for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
dsig_deps.Change(i,j,k,l,-MPC(ig,jg));
};
};
}
else // dans le cas d'une base quelconque il faut intervenir sur le premier et dernier indice
{
// for (int i=1;i<4;i++)
// for (int j=1;j<4;j++)
// for (int k=1;k<4;k++)
// for (int l=1;l<4;l++)
// {double inter=0.;
// for (int e=1;e<4;e++)
// for (int f=1;f<4;f++)
// {int ej = Tenseur3BH::OdVect(e,j);
// int kf = Tenseur3HB::OdVect(k,f); // en fait idem mixte dans un sens ou l'autre
//// inter += gijHH_tdt(i,e) * MPC(ej,kf) * gijHH_tdt(f,l);
//// essai (a virer si pas concluant ) 1 oct 2020
//// a priori c'est concluant, cela fct nettement mieux, en particulier quand on l'utilise
//// en implicit : LoiAdditiveEnSigma::Calcul_DsigmaHH_via_eps_tdt
//// Je ne comprends pas pourquoi la matrice ne conduit pas à une symétrie, mais ...
//// forcé de constater qu'il faut intégrer tous les termes... et donc on force une symétrie !!
// int je = Tenseur3BH::OdVect(j,e);
// int fk = Tenseur3HB::OdVect(f,k); // en fait idem mixte dans un sens ou l'autre
// inter += gijHH_tdt(i,e) *
// 0.25* (MPC(ej,kf)+MPC(je,kf)+MPC(ej,fk)+MPC(je,fk))
// * gijHH_tdt(f,l);
////$$$$$ il manque les variation de gijHH_tdt par rapport à epsilon !!
//
//// fin essai: on garde car a priori concluant
// }
// dsig_deps.Change(i,j,k,l,-inter);
// };
////$$$$ à voir la prise en compte de la partie der de Jauman
//// essai en suivant exactement la même procédure que dsigma/d_ddl
// nouveau calcul car il manquait des termes
for (int oj=1;oj<=9;oj++)
{int o=Tenseur3BH::idx_i(oj); int j=Tenseur3BH::idx_j(oj);
for (int ef=1;ef<=9;ef++)
{int e=Tenseur3BH::idx_i(ef); int f=Tenseur3BH::idx_j(ef);
double inter=0.;
for (int i=1;i<4;i++)
for (int k=1;k<4;k++)
for (int l=1;l<4;l++)
{ int ij = Tenseur3BH::OdVect(i,j);
int kl = Tenseur3BH::OdVect(k,l);
// ici un - car MPC(ij,kl) est = - d sig_i^j / d eps_k^l
inter -= gijHH_tdt(o,i) * MPC(ij,kl) * IdBH3(k,e) * gijHH_tdt(f,l);
};
// ici - car c'est un - dans la formule
inter -= 2.* gijHH_tdt(o,e) * sigHH(f,j);
dsig_ojef_HHHH.Change(o,j,e,f,inter);
};
};
// on symétrise
dsig_deps.TransfertDunTenseurGeneral(dsig_ojef_HHHH.Symetrise1et2_3et4());
};
// retour
return dsig_deps;
};
// calcul de l'opérateur tangent : dsigma/d_ddl
void Hysteresis3D::Dsig_d_ddl(Tableau <TenseurHH *>& d_sigHH,TenseurBB & epsBB_tdt
,TenseurHH & gijHH_tdt,Tableau <TenseurBB *>& d_gijBB_tdt
,Tableau <TenseurHH *>& d_gijHH_tdt,Tableau <TenseurBB *>& d_epsBB )
{ // -- calcul de la matrice MPC
Dsig_d_(MPC);
////----- debug
//cout << "\n debug Hysteresis3D::Dsig_d_ddl( ";
//MPC.Affiche();
//cout << endl;
////--- fin debug
// -- calcul de dsigma / d_ddl
// nombre de ddl pour la variation du tenseur des contraintes
int nbddl = d_gijBB_tdt.Taille();
Tenseur3BH depsBH_dll;Tenseur3BH dsig3BH; Tenseur_ns3HH dsig1_HH;
const Tenseur3HH & gijHH = *((Tenseur3HH*) &gijHH_tdt); // " " " "
const Tenseur3BB & epsBB = *((Tenseur3BB*) &epsBB_tdt); // passage en dim 3
for (int i = 1; i<= nbddl; i++)
{ // on fait uniquement une égalité d'adresse de manière à ne pas utiliser
// le constructeur d'ou la profusion d'* et de ()
Tenseur3HH & dsigHH = *((Tenseur3HH*) (d_sigHH(i))); // passage en dim 1
const Tenseur3BB & d_gijBB = *((Tenseur3BB*)(d_gijBB_tdt(i))); // passage en dim 1
const Tenseur3HH & dgijHH = *((Tenseur3HH*)(d_gijHH_tdt(i))) ; // pour simplifier l'ecriture
const Tenseur3BB & depsBB = *((Tenseur3BB *) (d_epsBB(i))); // "
depsBH_dll = (depsBB * gijHH + epsBB * dgijHH );
for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
dsig3BH.Coor(i,j) = 0.;
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
// dsig3BH(i,j) += -(dRdeps(ig,jg) * depsBH_dll(k,l));
dsig3BH.Coor(i,j) += -(MPC(ig,jg) * depsBH_dll(k,l));
};
};
// et en deux fois contra
dsig1_HH = gijHH * dsig3BH + dgijHH * sigma_t_barre_tdt ;
// et on symétrise
dsigHH = 0.5*(dsig1_HH + dsig1_HH.Transpose());
}
};
// calcul de la première phase de l'opérateur tangent, est utilisé par Dsig_d_ddl et
// Dsig_depsilon
// calcul de la matrice MPC
void Hysteresis3D::Dsig_d_(MatLapack& MPC)
{ // dans le cas où la résolution est faite avec du Runge on appelle une routine spécifique
if (type_calcul_comportement_tangent==2)
{ Dsig_d_Runge(MPC);
return;
};
// ---- sinon il s'agit de l'algo avec linéarisation
double const untiers=1./3.;
double beta=0.; // init dans le cas où ne le calcul pas après
if (!trajet_neutre)
{ // si c'est un trajet non neutre, on utilise l'ensemble de la loi constitutive
// -- calcul de Beta
// remarque: le xnp que l'on utilise ici est le dernier calculé dans l'algo
// d'avancement temporel (on ne le met pas à jour)
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
if (QdeltaSigmaRatdt >= ConstMath::petit)
// on ne calcul beta que si la norme de deltaSigmaRatdt est significative
{if (xnp == 2.)
{ beta = - 2. * xmu * unsurwprimeQ0_puiss_np ;}
else
{ beta = - 2. * xmu * unsurwprimeQ0_puiss_np * pow(QdeltaSigmaRatdt,xnp-2.);};
};
}; // fin du calcul de beta pour le cas d'un trajet non neutre
// normalement la matrice der_at_racine (qui vient d'être calculée
// pour résoudre l'équation constitutive, contient d_R_i^j / d_sigbarre_k^l)
// mais ce serait peut-être mieux de systématiquement la recalculer pour alpha = 1
// on aurait ainsi une matrice sécante ???
if (!calcul_dResi_dsig)
{// cas où la matrice tangente n'a pas été calculée
// calcul de la matrice tangente de la résolution de l'équation constitutive
// essai d'une nouvelle méthode
/* a prioiri ne fonctionne pas
// on utilise une petite portion de tàtdt
MatLapack der_at_racine_inter(9,9);
int nb_decoup = 10;
double alphap = 1./nb_decoup; //00; // pour voir 1/100
// sigma_i_barre_BH représente le point de ref sur la même courbe d'évolution
// delta_sigma_barre_tdt_BH représente le delta sigma depuis le point de ref
Tenseur3BH sigma_courant_BH(sigma_i_barre_BH);
Tenseur3BH sigma_i_barre_sauve_BH(sigma_i_barre_BH); // sauvegarde
Tenseur3BH incr_sig_BH(delta_sigma_barre_tdt_BH);incr_sig_BH /= nb_decoup;
for (int ig=1;ig<=9;ig++)
racine(ig) = incr_sig_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
for (int i=1;i<=nb_decoup;i++)
{ // on prend une nouvelle référence ad Hoc
sigma_i_barre_BH = sigma_courant_BH;
sigma_courant_BH += incr_sig_BH;
// on calcul l'opérateur tangent pour le sigma_courant_BH
der_at_racine_inter = Mat_tangente_constitutif(alphap,racine,residu);
// on cumule l'opérateur tangent
der_at_racine += der_at_racine_inter;
};
// calcul de l'opérateur tangent finale
der_at_racine *= alphap;
*/
// ici une solution qui fonctionne bien pour alpha = 10 !! incompréhensible !!
/* double alphap = 10;
// récup de la solution
for (int ig=1;ig<=9;ig++)
// racine(ig) = alphap * delta_sigma_barre_tdt_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
racine(ig) = delta_sigma_barre_tdt_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
// on prend une nouvelle référence, proche de l'arrivée
// sigma_i_barre_BH = sigma_t_barre_tdt-alphap * delta_sigma_barre_tdt_BH;
sigma_i_barre_BH = sigma_t_barre_tdt-delta_sigma_barre_tdt_BH;
der_at_racine = Mat_tangente_constitutif(alphap,racine,residu); */
// fin essai de la nouvelle méthode
// la méthode normale !
double alphap = 1.;
// récup de la solution
for (int ig=1;ig<=9;ig++)
racine(ig) = delta_sigma_barre_tdt_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
int test; // ne sert pas pour l'instant
der_at_racine = Mat_tangente_constitutif(alphap,racine,residu,test);
// !!!!!!!! pour le débug
//cout << " norme residu= " << residu.Max_val_abs()/delta_sigma_barre_tdt_BH.MaxiComposante() ;
//if (residu.Max_val_abs() <= ConstMath::petit)
// cout << " la norme est nulle !";
// !!!!!!!! pour le débug
};
// 1-- on calcul son inverse
der_at_racine.Inverse(dRdsigMoinsun);
// ------ pour le débug
// MatLapack produit(9,9);
// produit = dRdsigMoinsun * der_at_racine;
// for (int i=1;i<=9;i++)
// { if (Dabs(produit(i,i)-1. ) > ConstMath::unpeupetit)
// cout << "\n diag("<<i<<","<<i<<") n'est pas unitaire =" << produit(i,i);
// for (int j=1;j<= 9; j++)
// { if (i!=j)
// if (Dabs(produit(i,j)) > ConstMath::unpeupetit)
// cout << "\n terme ("<<i<<","<<j<<") non nul =" << produit(i,j);
// if ((produit(i,j) != produit(j,i)) && (Dabs(produit(i,j)) > ConstMath::unpeupetit))
// cout << "\n non symetrique ("<<i<<","<<j<<") =" << produit(i,j) << " et " << produit(j,i);
//
// }
// }
//
//------ fin pour le débug
// 2-- maintenant il faut calculer la variation du résidu constitutif / aux déformations
dRdeps.Initialise(0.);
// ************ important ********************
// en fait dans la suite on calcul - dSigma/ dEps et non +
// ensuite dans l'utilisation on met un moins (ce serait peut-être plus judicieux de mettre moins ici
// et pas après !!!
if (trajet_neutre)
{ // si c'est un trajet neutre, l'équation constitutive est beaucoup plus simple: sigma_point = 2 mu D_barre
for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
dRdeps(ig,jg) = -2. * xmu * (IdBH3(i,k)*IdBH3(l,j)-untiers*IdBH3(l,k)*IdBH3(i,j));
};
};
}
else
{ // cas non neutre
for (int ig=1;ig<=9;ig++)
{int i=Tenseur3BH::idx_i(ig); int j=Tenseur3BH::idx_j(ig);
for (int jg=1;jg<=9;jg++)
{int k=Tenseur3BH::idx_i(jg); int l=Tenseur3BH::idx_j(jg);
dRdeps(ig,jg) = -2. * xmu * (IdBH3(i,k)*IdBH3(l,j)-untiers*IdBH3(l,k)*IdBH3(i,j)) // originale
// dRdeps(ig,jg) = 2. * xmu * (IdBH3(i,k)*IdBH3(l,j)-untiers*IdBH3(l,k)*IdBH3(i,j)) // essai
// // + beta * rdelta_sigma_barre_BH_Ratdt(i,j)
// // * rdelta_sigma_barre_BH_Ratdt(l,k);
// + beta * delta_sigma_barre_BH_Ratdt(i,j) // originale
// normalement suivant les formules, on devrait avoir un - ???? incompréhensible
// car avec un + ça marche mieux ??
- beta * delta_sigma_barre_BH_Ratdt(i,j) // essai
* delta_sigma_barre_BH_Ratdt(l,k);
};
};
};
// 3-- puis on calcul le produit des deux matrices
MPC = dRdsigMoinsun * dRdeps; // originale
// MPC = -dRdeps * dRdsigMoinsun; // essai
};
// calcul de l'avancement temporel sur 1 pas,
// utilisé par les 3 programmes principaux:
// Calcul_SigmaHH, Calcul_DsigmaHH_tdt, Calcul_dsigma_deps,
void Hysteresis3D::Avancement_temporel(const Tenseur3BB & delta_epsBB,const Tenseur3HH & gijHH
,const Tenseur3BB & gijBB,int cas,SaveResulHysteresis3D & save_resul
,Tenseur3HH & sigHH,const EnergieMeca & energ_t,EnergieMeca & energ)
{
// . le tenseur des contraintes initiale en mixte, qui sera considéré comme la contrainte de début
// de calcul, pour toute la suite,
// . s'il y a plusieurs passage dans la boucle while qui suit, sigma_i_barre_BH variera, à chaque passage
// . on utilise le sigmaBH sauvegardé plutôt que le sigmaHH ce qui signifie que l'on effectue un transport
// en mixte plutôt qu'en 2 fois contravariants !!
// mise en place d'un transport éventuelle sur toutes les grandeurs
Transport_grandeur(gijBB,gijHH,save_resul);
sigma_i_barre_BH = save_resul.sigma_barre_BH_t; // récup des info
// même procédé pour la def équivalente de début de calcul, initié à t qui sert pour calculer la def équi de R à tdt
def_i_equi = save_resul.def_equi_at;
// init énergie
energ = energ_t;
double W_a = save_resul.fonction_aide_t; // valeur courante de la fonction d'aide
double delta_W_a = 0.; // valeur courante du delta W
// -- récup et initialisation des variables de travail
// iatens_princ: pointeur sur la liste déjà enregistrée, iatens: pointeur courant
List_io <Tenseur3BH>::iterator iatens_princ = save_resul.sigma_barre_BH_R.begin();
List_io <Tenseur3BH>::iterator iatens = iatens_princ;
// idem pour la fonction d'aide
List_io <double>::iterator iafct_princ = save_resul.fct_aide.begin();
List_io <double>::iterator iafct = iafct_princ;
aucun_pt_inversion = true; // pour gérer le fait qu'au début il n'y a pas de pt d'inversion !
if (iatens_princ != save_resul.sigma_barre_BH_R.end())
aucun_pt_inversion = false; // cas où on a déjà des inversions enregistrées
// idem pour les déformations équivalentes, fonctionnent avec l'indicateur "aucun_pt_inversion"
List_io <double>::iterator iadef_equi_princ = save_resul.def_equi.begin();
List_io <double>::iterator iadef_equi = iadef_equi_princ;
// idem pour les centres de surfaces de coïncidence
List_io <Tenseur3BH>::iterator iaOi_princ = save_resul.oc_BH_R.begin();
List_io <Tenseur3BH>::iterator iaOi = iaOi_princ;
// on récupère la def maxi de première charge, c'est celle qui correspond au premier point d'inversion
// si on est sur la première charge on prend la dernière valeur enregistrée sinon on récupère
// la valeur du premier point d'inversion
if (aucun_pt_inversion) { defEqui_maxi = def_i_equi;}
else { List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();
iil++;defEqui_maxi = *iil; // la dernière valeur est nulle, c'est l'avant dernière qui est la bonne
};
centre_initial = true; // pour gérer le fait qu'au début le centre initial = tenseur nul
if (iaOi_princ != save_resul.oc_BH_R.end())
centre_initial = false; // cas où on a déjà de nouveaux centres enregistrés
// un pointeur qui indique si les pointeurs courants sont sur les listes principales ou
// sur les nouvelles listes
bool pt_sur_principal = true; bool oi_sur_principal = true;
wBase = save_resul.wBase_t; // initialisation du paramètre de masing
double unSur_wBaseCarre= 1./(wBase*wBase);
// -- la déformation
delta_epsBH = delta_epsBB * gijHH; // incrément de def en mixte
double trace = delta_epsBH.Trace();
delta_barre_epsBH = delta_epsBH - (trace/3.)*IdBH3;
//-- partie spécifique gestion via fct aide
Tenseur3BH delta_epsBH_totale(delta_epsBH); // sauvegarde delta epsilon totale
Tenseur3BH delta_barre_epsBH_totale(delta_barre_epsBH); // sauvegarde delta_barre epsilon totale
// a priori, on fait un pas de calcul correspondant à la totalité de la déformation
// sauf cas inversion ou coïncidence
double ratio_deformation_en_cours = 0.; // utilisée pour l'instant uniquement avec l'algo fct aide
double ratio_multiplicatif_coincidence = 1.; // ""
int phase_coincidence = 0; // pour la gestion de la coincidence
//-- fin partie spécifique gestion via fct aide
// on définit un indicateur pour le type de gestion de la mémorisation discrète
bool bascule_fct_aide=false; // init
bool premier_passage = true; // init
// indicateur pour gérer la fin du traitement
bool fin_traitement= false; bool force_fin_traitement = false;
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\n$$$ === Hysteresis3D::Avancement_temporel: debut de l'algo " << endl ;
};
#endif
//----- fin débug
// ==== 1 === calcul de la contrainte à tdt =============
// faire tant que fin_traitement n'est pas bon
int nb_coin_inver=0; // compteur pour éviter une boucle infinie
while (!fin_traitement)
{// initialisation des variables de travail qui peuvent varier à chaque passage du while
// -- 1) sigma_barre_BH_R : initialisé sur la liste principal, mais ensuite peut évoluer sur liste secondaire
if (aucun_pt_inversion) {sigma_barre_BH_R.Inita(0.);def_equi_R=0.;}
else {sigma_barre_BH_R = *iatens; // la contrainte de référence
def_equi_R = *iadef_equi; }; // def équi au pt de référence
delta_sigma_barre_BH_Rat = sigma_i_barre_BH - sigma_barre_BH_R;
// -- 2) centre et rayon de la première surface de coïncidence
if (centre_initial) {oc_BH_R.Inita(0.);}
else {oc_BH_R = *iaOi;};
delta_sigma_barre_BH_OiaR = sigma_barre_BH_R-oc_BH_R; // le tenseur rayon
// -- 3) calcul du rayon: la première fois le rayon est infini
if (aucun_pt_inversion) {Q_OiaR = ConstMath::tresgrand;}
else {Q_OiaR = sqrt(delta_sigma_barre_BH_OiaR.II());};
// -- détermination du type de gestion de la mémorisation discrète au premier passage
// restera constant pour tout le reste du traitement
// le choix est donc fait par rapport aux valeurs de départ
if (premier_passage)
{Tenseur3BH delta_sigma_oi_a_t_BH = sigma_i_barre_BH - oc_BH_R; // OA_t
double rayon_t = sqrt(delta_sigma_oi_a_t_BH.II());
if (rayon_t > niveau_bascule_fct_aide * Qzero)
bascule_fct_aide = true;
premier_passage = false;
};
// le calcul de la contrainte s'effectue par la résolution de l'équation différentielle
// du schéma constitutif en BH, et toutes les grandeurs sont relatives à BH
// bien voir que que ce n'est qu'une partie de l'équation, et que pour l'intégration de
// la dérivée de Jauman, il faut aussi la partie HB qui est différente, mais on a une symétrie
// formelle (cf théorie)
// sigma_point = 2*mu*D_barre + beta*phi*(delta_barre de t à R de Sigma)
// ---7 mai 2012 ---
// point nouveau: cette équation n'est valide "que" si phi est positif !!
// en effet, si phi est négatif, le sigma_point au lieu de saturé, a tendance a exploser (c'est normal car la tendance est inverse)
// méthode permettant le calcul de sigma à tdt par différente méthodes: linéarisation
// ou kutta
// en sortie calcul de :
// sigma_t_barre_tdt, delta_sigma_barre_tdt_BH, delta_sigma_barre_BH_Ratdt
// également les grandeurs: QdeltaSigmaRatdt, et wprime,wprime_point, calculées à tdt
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << " \nsigR_sur_principal= " << pt_sur_principal << ", oi_sur_principal= " << oi_sur_principal
<< " save_resul.modif= " << save_resul.modif
<< " \n nb_Oi= "<<save_resul.oc_BH_R.size() << " nb_sigR= "<<save_resul.sigma_barre_BH_R.size()
<< " || nb_Oi_sec= " << save_resul.oc_BH_t_a_tdt.size()
<< " nb_sigR_sec= " << save_resul.sigma_barre_BH_R_t_a_tdt.size()
<< " || wBase= " << wBase;
};
#endif
//----- fin débug
double phi_2_dt = 0.; // on initialise avec un trajet neutre par défaut
CalculContrainte_tdt(phi_2_dt,save_resul.indicateurs_resolution);
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\nCalculContrainte_tdt(phi_2_dt...";
cout << " phi_2_dt = " << setprecision(ParaGlob::NbdigdoEC()) << phi_2_dt
<< " || wBase= " << wBase
<< endl ;
};
#endif
//----- fin débug
// 2==== gestion de la mémoire discrète
Tenseur3BH delta_sigma_oi_a_tdt_BH = sigma_t_barre_tdt - oc_BH_R; // OA
double rayon_tdt = sqrt(delta_sigma_oi_a_tdt_BH.II());
double d_W_a_essai = 0.; // init
if (wprime != 0.) // cas d'un trajet non neutre
{d_W_a_essai = 2. * phi_2_dt / (wprime * wprime);};
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\n rayon_tdt = " << setprecision(ParaGlob::NbdigdoEC()) << rayon_tdt
<< " Q_OiaR= " << setprecision(ParaGlob::NbdigdoEC()) << Q_OiaR << endl ;
};
#endif
//----- fin débug
if (!bascule_fct_aide) // cas d'une gestion à l'aide des rayons
{ if ((rayon_tdt < Q_OiaR)&&(!force_fin_traitement))
// cas où le nouveau rayon est inférieur au rayon de référence (= infini si courbe de première charge)
{int pb_calcul_centre_ok = 0; // init pour une gestion locale du cas où le calcul du centre cercle pose pb,
if (phi_2_dt < 0) //===========================================================================
// ce qui correspond également au cas d_W_a_essai < O
// a priori on a détecté un point d'inversion
// le calcul effectué n'est pas valide et on doit refaire une itération en initialisant les grandeurs ad hoc
// ------------------ cas d'une inversion ----------
{// -- on vérifie la cohérence de la valeur de la fonction d'aide (qui n'a rien à voir ici
// et donc doit être inférieur au maxi)
if (!aucun_pt_inversion) // si on a déjà des pt d'inversion, on vérifie les niveaux de la fonction d'aide
if (W_a > *iafct)
{if ( (ParaGlob::NiveauImpression() > 5) || (Permet_affichage() > 5))
{cout << "\n warning dans l'algorithme de gestion de la memoire discrete, "
<< " bien que l'on ait detecte un point d'inversion, il se trouve que la fonction d'aide "
<< " est superieur au dernier maxi, ce qui signifie que le calcul de l'integrale de la puissance "
<< " non reversible (phi(t)) n'a pas ete correcte (c'est une erreur cumulee), du sans doute a des pas de temps trop grand, "
<< " le calcul aura peut-etre des pb si on gere avec la fct d'aide, essayer de le reprendre avec un pas de temps plus petit ! "
<< " \n W_a= " << W_a << " iafct= " << *iafct
<< "\n Hysteresis3D::Avancement_temporel(...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << flush;
};
};
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\ninversion " << endl ;
};
#endif
//----- fin débug
// -- calcul des centre de cercle
if (!aucun_pt_inversion) // s'il y a au moins déjà un point d'inversion valide on peut traiter
{Tenseur3BH sig0i_BH;
pb_calcul_centre_ok=CentreCercle(sig0i_BH,oc_BH_R,delta_sigma_barre_BH_OiaR
,delta_sigma_barre_BH_Rat);
if (!pb_calcul_centre_ok) // si le calcul a été ok
{save_resul.oc_BH_t_a_tdt.push_front(sig0i_BH);
iaOi = save_resul.oc_BH_t_a_tdt.begin(); // init du centre courant pour la suite
oi_sur_principal = false; // va être mis à jour au début de la prochaine boucle
centre_initial = false; // du while (!fin_traitement)
};
}
else // si auparavant il n'y avait pas de pt d'inversion, maintenant il y en a un
{aucun_pt_inversion = false; // on le signal pour la suite
// point d'inversion
wBase = 2; unSur_wBaseCarre = 0.25; //=1./(wBase*wBase);
defEqui_maxi = def_i_equi;
};
// -- s'il n'y a pas eu de pb de calcul de centre on met tout à jour ==> fonctionnement normal
if (!pb_calcul_centre_ok)
{ // gestion du paramètre "modif" de saveresult
bool inversion = true;
Gestion_para_Saveresult_Modif(pt_sur_principal,save_resul,inversion);
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\npas de probleme de calcul de centre " ;
};
#endif
//----- fin débug
// calcul du nouveau centre d'inversion et sauvegarde, sauf dans le cas du premier point
// d'inversion, pour lequel le centre reste encore le tenseur nul pour la suite
// ajout de la contrainte de référence = sigma at
save_resul.sigma_barre_BH_R_t_a_tdt.push_front(sigma_i_barre_BH);
save_resul.fct_aide_t_a_tdt.push_front(W_a);
iafct = save_resul.fct_aide_t_a_tdt.begin();
W_a=0.; delta_W_a = 0.; // on ré-initialise pour les futures coincidences éventuelles
iatens = save_resul.sigma_barre_BH_R_t_a_tdt.begin(); // pour l'init du début du while générale
pt_sur_principal = false; // on indique que maintenant on pointe sur la nouvelle liste
// on indique le point d'inversion pour les futurs traitements
sigma_barre_BH_R =save_resul.sigma_barre_BH_R_t_a_tdt.front();
// -- idem pour la déformation équivalente
save_resul.def_equi_t_a_tdt.push_front(def_i_equi);
iadef_equi = save_resul.def_equi_t_a_tdt.begin(); // pour l'init du début du while générale
// on indique la déformation équivalente d'inversion pour les futurs traitements
def_equi_R = save_resul.def_equi_t_a_tdt.front();
// on met à jour la def de début de calcul (valant t au début, puis tau= pt d'inver ensuite ) pour def_equi_atdt
def_i_equi = def_equi_R;
// le calcul d'énergie se fera ensuite dans le cas normale ou avec coïncidence
// car la valeur actuelle de sigma est erroné, et phi est négatif
fin_traitement = false; // -- il faut recalculer avec le nouveau point d'inversion
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << " fin_traitement = " << fin_traitement
<< " save_resul.modif= " << save_resul.modif
<< endl ;
};
#endif
//----- fin débug
};
// sinon on est dans le cas où il y a eu un pb dans le calcul du centre --> ce qui invalide le point d'inverion
// on indique qu'il faut traiter la suite comme si il n'y avait pas de point d'inversion
// ceci se fait au travers de l'indicateur: pb_calcul_centre_ok
};//-- fin du cas de l'inversion
// --- maintenant on traite le cas courant ou il n'y a pas de point d'inversion ---
if ((phi_2_dt >= 0) || pb_calcul_centre_ok)
//======================================================================================
// c-a-d si phi_2_dt = 0 : on se promène sur un cercle
// si phi_2_dt > 0 : progression normale
// si pb_calcul_centre_ok != 0 : on est dans un cas limite pour lequel il est préférable de ne pas
// introduire de point d'inversion
{ // --- cas d'une évolution normale sans inversion ni coincidence ---
// mais cette évolution peut-être la fin après une coincidence par exemple, donc
// on ne modifie pas save_resul.modif
fin_traitement = true;
// dans l'expression suivante, on utilise une intégration incrémentale ...
// dans l'expression suivante, on utilise une intégration incrémentale ...
// s'il y a eu un pb de calcul de centre, cela veut dire que phi_2_dt était légèrement
// négatif à la prec près, il ne faut pas le compter
if (pb_calcul_centre_ok) {delta_W_a = 0;}
else if (wprime != 0.) // cas d'un trajet non neutre
{ delta_W_a = 2. * phi_2_dt / (wprime * wprime);}
else {delta_W_a = 0.;};
W_a += delta_W_a;
save_resul.fonction_aide_tdt = W_a;
// -- uptdate des énergies
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_barre_epsBH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
/* defEqui_maxi = 0; // init
// pour la liste principale, la dernière valeur est nulle, c'est l'avant dernière qui est la bonne
if (save_resul.def_equi.size())
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
// pour la liste secondaire c'est directement la dernière valeur
if (save_resul.def_equi_t_a_tdt.size())
{ List_io <double>::reverse_iterator iil = save_resul.def_equi_t_a_tdt.rbegin();
defEqui_maxi = MaX(*iil,defEqui_maxi);
};*/
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\ncas courant sans point d'inversion " ;
cout << " fin_traitement = " << fin_traitement
<< " save_resul.modif= " << save_resul.modif
<< endl ;
};
#endif
//----- fin débug
};
} // -- fin du cas où le nouveau rayon est inférieur au rayon de référence
else if (!force_fin_traitement) // sinon cas d'une coincidence (rayon_tdt >= Q_OiaR )
{ // -- on calcul exactement le point de coïncidence
// auparavant on sauvegarde le delta eps pour connaître la partie concernée pour le
Tenseur3BH delta_eps_sur_deltaTau_BH = delta_barre_epsBH; // calcul d'énergie
double def_equi_R_ancien= def_equi_R; // sauvegarde qui ne sert à rien, car Coincidence ne change pas
// directement def_equi_R, seulement le pointeur iadef_equi (qui lui ne pointe plus en sortie sur une valeur = def_equi_R)
// mais c'est pour bien marquer le fait que à la sortie de la coïncidence, le pointeur iadef_equi de def_equi à changé
fin_traitement = Coincidence(bascule_fct_aide,unSur_wBaseCarre,gijHH,gijBB,save_resul
,W_a,iatens,iadef_equi
,iafct,pt_sur_principal,iaOi,oi_sur_principal,iatens_princ,iadef_equi_princ
,iaOi_princ,iafct_princ,rayon_tdt,false);
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\ncas d'une coïncidence ";
cout << " fin_traitement = " << fin_traitement
<< " save_resul.modif= " << save_resul.modif
<< " save_resul.nb_coincidence= " << save_resul.nb_coincidence
<< endl ;
};
#endif
//----- fin débug
// dans le cas d'un trajet strictement radial, on a deux coïncidences à suivre
// mais on laisse l'algorithme passer deux fois, car sinon il y a des pb dans le cas
// de grand incrément
// -- uptdate des énergies
// récup du delta eps concerné: delta_barre_epsBH est modifié dans Coïncidence, maintenant
// il contient le reste de la déformation
delta_eps_sur_deltaTau_BH -= delta_barre_epsBH;
// on recalcule la valeur de phi car ici on est après le calcul d'une coïncidence, la contrainte qu'il faut considérer est
// celle de la coïncidence, la deformation à considérer est delta_eps_sur_deltaTau_BH, il faut donc calculer le phi qui
// correspond à ces deux grandeurs.
delta_sigma_barre_BH_Ra_i = sigma_i_barre_BH - sigma_barre_BH_R;
double QdeltaSigmaRai = sqrt(delta_sigma_barre_BH_Ra_i.II());
phi_2_dt = (delta_sigma_barre_BH_Ra_i && delta_eps_sur_deltaTau_BH)
- QdeltaSigmaRai * QdeltaSigmaRai * wprime_point / (2.*xmu * wprime);
// si le phi est négatif, on le met à 0 pour limiter les ennuis dans les calculs d'énergies (ici phi ne sert
// ne sert que là par la suite), mais c'est quand même pas normal !! mais ça peut être due à une légère erreur
// au niveau de la coïncidence
if (phi_2_dt < 0.)
phi_2_dt = 0.;
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_eps_sur_deltaTau_BH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R_ancien,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
// on met à jour la def de début de calcul (valant t au début )
// il s'agit d'une grandeur scalaire (pas tensorielle) on peut donc reprendre la valeur qu'elle avait
// au moment du précédent pt d'inversion, ce qui évitera de cumuler des erreurs d'intégration
def_i_equi = def_equi_R_ancien; // def_equi_R n'a pas encore été modifié, il correspond à la précédente valeur d'inversion
// NB: 1)on pourrait également prendre def_equi_atdt, mais qui cumulle les erreurs d'integ entre les deux derniers pt d'integ
// 2) c'est la même formule que dans le cas d'une inversion, mais cela ne donne pas du tout le même résultat
}
else // cas où on force la fin du traitement: force_fin_traitement = true
{ fin_traitement = true;
// comme (rayon_tdt >= Q_OiaR ) on force la coincidence
double def_equi_R_ancien= def_equi_R; // sauvegarde qui ne sert à rien, car Coincidence ne change pas
// directement def_equi_R, seulement le pointeur iadef_equi (qui lui ne pointe plus en sortie sur une valeur = def_equi_R)
// mais c'est pour bien marquer le fait que à la sortie de la coïncidence, le pointeur iadef_equi de def_equi à changé
Coincidence(bascule_fct_aide,unSur_wBaseCarre,gijHH,gijBB,save_resul,W_a,iatens,iadef_equi
,iafct,pt_sur_principal,iaOi,oi_sur_principal,iatens_princ,iadef_equi_princ
,iaOi_princ,iafct_princ,rayon_tdt,true);
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\non force la fin du traitement et la coincidence ";
cout << " fin_traitement = " << fin_traitement
<< " save_resul.modif= " << save_resul.modif
<< endl ;
};
#endif
//----- fin débug
// si le phi est négatif, on le met à 0 pour limiter les ennuis dans les calculs d'énergies (ici phi ne sert
// ne sert que là par la suite)
if (phi_2_dt < 0.)
phi_2_dt = 0.;
// -- uptdate des énergies
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_barre_epsBH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R_ancien,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
/* defEqui_maxi = 0; // init
// pour la liste principale, la dernière valeur est nulle, c'est l'avant dernière qui est la bonne
if (save_resul.def_equi.size())
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
// pour la liste secondaire c'est directement la dernière valeur
if (save_resul.def_equi_t_a_tdt.size())
{ List_io <double>::reverse_iterator iil = save_resul.def_equi_t_a_tdt.rbegin();
defEqui_maxi = MaX(*iil,defEqui_maxi);
};*/
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;
};
// on met à jour la def de début de calcul (valant t au début )
// il s'agit d'une grandeur scalaire (pas tensorielle) on peut donc reprendre la valeur qu'elle avait
// au moment du précédent pt d'inversion, ce qui évitera de cumuler des erreurs d'intégration
def_i_equi = def_equi_R_ancien; // def_equi_R n'a pas encore été modifié, il correspond à la précédente valeur d'inversion
// NB: 1)on pourrait également prendre def_equi_atdt, mais qui cumulle les erreurs d'integ entre les deux derniers pt d'integ
// 2) c'est la même formule que dans le cas d'une inversion, mais cela ne donne pas du tout le même résultat
};
}
// --- fin de la gestion par rapport au rayon
else // sinon cas d'une gestion avec la fonction d'aide
{ int pb_calcul_centre_ok = 0; // init pour une gestion locale du cas où le calcul du centre cercle pose pb,
if (((phase_coincidence==0) && (d_W_a_essai < 0.)) && (!force_fin_traitement))
{ // on a un point d'inversion
// -- on vérifie la cohérence de la valeur de la fonction d'aide
if (!aucun_pt_inversion) // si on a déjà des pt d'inversion, on vérifie les niveaux de la fonction d'aide
if (W_a > *iafct)
{cout << "\n erreur dans l'algorithme de gestion de la memoire discrete, "
<< " bien que l'on ait detecte un point d'inversion, il se trouve que la fonction d'aide "
<< " est superieur au dernier maxi, ce qui signifie que le calcul de l'integrale de la puissance "
<< " non reversible (phi(t)) n'a pas ete correcte (c'est une erreur cumulee), du sans doute a des pas de temps trop grand, "
<< " il n'est pas possible de continuer le calcul, essayer de le reprendre avec un pas de temps plus petit ! "
<< " \n W_a= " << W_a << " iafct= " << *iafct
<< "\n Hysteresis3D::Avancement_temporel(...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << flush;
Sortie(1);
};
// -- calcul des centre de cercle
if (!aucun_pt_inversion) // s'il y a au moins déjà un point d'inversion valide on peut traiter
{Tenseur3BH sig0i_BH;
pb_calcul_centre_ok=CentreCercle(sig0i_BH,oc_BH_R,delta_sigma_barre_BH_OiaR
,delta_sigma_barre_BH_Rat);
if (!pb_calcul_centre_ok) // si le calcul a été ok
{save_resul.oc_BH_t_a_tdt.push_front(sig0i_BH);
iaOi = save_resul.oc_BH_t_a_tdt.begin(); // init du centre courant pour la suite
oi_sur_principal = false; // va être mis à jour au début de la prochaine boucle
centre_initial = false; // du while (!fin_traitement)
};
}
else // si auparavant il n'y avait pas de pt d'inversion, maintenant il y en a un
{aucun_pt_inversion = false; // on le signal pour la suite
// point d'inversion
wBase = 2; unSur_wBaseCarre = 0.25; //=1./(wBase*wBase);
defEqui_maxi = def_i_equi;
};
// -- s'il n'y a pas eu de pb de calcul de centre on met tout à jour ==> fonctionnement normal
if (!pb_calcul_centre_ok)
{ // calcul du nouveau centre d'inversion et sauvegarde, sauf dans le cas du premier point
// d'inversion, pour lequel le centre reste encore le tenseur nul pour la suite
// gestion du paramètre "modif" de saveresult
bool inversion = true;
Gestion_para_Saveresult_Modif(pt_sur_principal,save_resul,inversion);
// ajout de la contrainte de référence = sigma at
save_resul.sigma_barre_BH_R_t_a_tdt.push_front(sigma_i_barre_BH);
// on ajoute le W_a et non le W_a_essai, car ce dernier n'est pas correcte
// par contre le W_a est de dernier maxi correcte
save_resul.fct_aide_t_a_tdt.push_front(W_a);
W_a=0.; delta_W_a = 0.; // on ré-initialise pour les futures coincidences éventuelles
iatens = save_resul.sigma_barre_BH_R_t_a_tdt.begin(); // pour l'init du début du while générale
iafct = save_resul.fct_aide_t_a_tdt.begin();
pt_sur_principal = false; // on indique que maintenant on pointe sur la nouvelle liste
// on indique le point d'inversion pour les futurs traitements
sigma_barre_BH_R =save_resul.sigma_barre_BH_R_t_a_tdt.front();
// -- idem pour la déformation équivalente
save_resul.def_equi_t_a_tdt.push_front(def_i_equi);
iadef_equi = save_resul.def_equi_t_a_tdt.begin(); // pour l'init du début du while générale
// on indique la déformation équivalente d'inversion pour les futurs traitements
def_equi_R = save_resul.def_equi_t_a_tdt.front();
// on met à jour la def de début de calcul (valant t au début, puis tau= pt d'inver ensuite ) pour def_equi_atdt
def_i_equi = def_equi_R;
// le calcul d'énergie se fera ensuite dans le cas normale ou avec coïncidence
// car la valeur actuelle de sigma est erroné, et phi est négatif
fin_traitement = false; // -- il faut recalculer avec le nouveau point d'inversion
};
// sinon on est dans le cas où il y a eu un pb dans le calcul du centre --> ce qui invalide le point d'inverion
// on indique qu'il faut traiter la suite comme si il n'y avait pas de point d'inversion
// ceci se fait au travers de l'indicateur: pb_calcul_centre_ok
};//-- fin du cas de l'inversion
//-------------------------------------------------
// arrivée ici on peu éventuellement calculer une valeur de la fonction d'aide correcte
// dans l'expression suivante, on utilise une intégration incrémentale ...
// s'il y a eu un pb de calcul de centre, cela veut dire que phi_2_dt était légèrement
// négatif à la prec près, il ne faut pas le compter
if (pb_calcul_centre_ok) {delta_W_a = 0;}
else { delta_W_a = d_W_a_essai;};
if (phase_coincidence != 1)
W_a += delta_W_a;
if (((phase_coincidence==1) || (delta_W_a > 0.)) || force_fin_traitement)
{if (W_a > *iafct) // on regarde si on est en coïncidence
phase_coincidence=1;
if (((phase_coincidence==0)&&(W_a <= *iafct)) && (!force_fin_traitement))// cas normal après plusieurs inversion
//======================================================================================
// c-a-d si phi_2_dt = 0 : on se promène sur un cercle
// si phi_2_dt > 0 : progression normale
// si pb_calcul_centre_ok != 0 : on est dans un cas limite pour lequel il est préférable de ne pas
// introduire de point d'inversion
{ // --- cas d'une évolution normale sans inversion ni coincidence ---
// mais cette évolution peut-être la fin après une coincidence par exemple, donc
// on ne modifie pas save_resul.modif
fin_traitement = true;
save_resul.fonction_aide_tdt = W_a;
// -- uptdate des énergies
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_barre_epsBH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
}
else if ((phase_coincidence==1) && (!force_fin_traitement))
//======================================================================================
// cas où on est en coïncidence: on gère toutes les coïncidence en même temps c-a-d courbe secondaire
// ou retour sur la courbe principale
{ // -- on calcul exactement le point de coïncidence
// auparavant on sauvegarde le delta eps pour connaître la partie concernée pour le
Tenseur3BH delta_eps_sur_deltaTau_BH = delta_barre_epsBH; // calcul d'énergie
double def_equi_R_ancien= def_equi_R; // sauvegarde qui ne sert à rien, car Coincidence ne change pas
// directement def_equi_R, seulement le pointeur iadef_equi (qui lui ne pointe plus en sortie
// sur une valeur = def_equi_R)
// mais c'est pour bien marquer le fait que à la sortie de la coïncidence,
// le pointeur iadef_equi de def_equi à changé
double ratio_deformation_pour_coincidence=0;
bool force_coincidence = false; // init par défaut
if (phase_coincidence ==1) // si on suit une phase de coincidence qui vient d'être repéré, à la boucle précédente
force_coincidence = true; // on force au deuxième tour la coincidence
//--- debug
//-- fin debug
bool coincidence_exacte = Coincidence(bascule_fct_aide,unSur_wBaseCarre,gijHH,gijBB
,save_resul,W_a
,iatens,iadef_equi,iafct,pt_sur_principal,iaOi,oi_sur_principal,iatens_princ
,iadef_equi_princ,ratio_deformation_pour_coincidence,iaOi_princ,iafct_princ,delta_W_a,force_coincidence);
// si la coïncidence est parfaite, dans ce cas seulement elle a été validée dans l'algo Coïncidence
// et on peut updater les énergies, sinon on refait un passage avec une déformation diminuée pour
// obtenir une coïncidence exacte
if (coincidence_exacte)
{ // -- cas d'une coïncidence validée
// dans le cas d'un trajet strictement radial, on a deux coïncidences à suivre
// mais on laisse l'algorithme passer deux fois, car sinon il y a des pb dans le cas
// de grand incrément
// -- uptdate des énergies
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_barre_epsBH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R_ancien,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;};
// on met à jour la def de début de calcul (valant t au début )
// il s'agit d'une grandeur scalaire (pas tensorielle) on peut donc reprendre la valeur qu'elle avait
// au moment du précédent pt d'inversion, ce qui évitera de cumuler des erreurs d'intégration
def_i_equi = def_equi_R_ancien; // def_equi_R n'a pas encore été modifié, il correspond à la précédente valeur d'inversion
// NB: 1)on pourrait également prendre def_equi_atdt, mais qui cumulle les erreurs d'integ entre les deux derniers pt d'integ
// 2) c'est la même formule que dans le cas d'une inversion, mais cela ne donne pas du tout le même résultat
// Mise en place de la déformation restante pour le calcul qui suit
delta_epsBH_totale -= delta_epsBH; delta_epsBH = delta_epsBH_totale;
delta_barre_epsBH_totale -= delta_barre_epsBH; delta_barre_epsBH = delta_barre_epsBH_totale;
// idem pour la contrainte de départ
sigma_i_barre_BH = sigma_t_barre_tdt;
// ratio_deformation_en_cours += ratio_multiplicatif_coincidence;
// ratio_multiplicatif_coincidence = 1.;
phase_coincidence = 0; // on réinitialise pour les autres passages
}
else
{ // -- cas non valide, on prépare pour une passe suivante
phase_coincidence = 1;
// ratio_multiplicatif_coincidence *= ratio_deformation_pour_coincidence;
// if (ratio_deformation_en_cours + ratio_multiplicatif_coincidence > 1.)
// // on ne peut pas dépasser la déformation imposée on limite donc
// ratio_multiplicatif_coincidence = 1.-ratio_deformation_en_cours;
delta_barre_epsBH *= ratio_deformation_pour_coincidence;
delta_epsBH *= ratio_deformation_pour_coincidence;
}
}
else // cas où on force la fin du traitement: force_fin_traitement = true
{ // ici comme on force une coïncidence exacte, il n'y a pas de calcul de point intermédiaire
// donc on reprend l'appel du cas des rayons, mais c'est équivalent à l'autre appel de Coincidence
// avec la fonction d'aide
fin_traitement = true;
// comme (rayon_tdt >= Q_OiaR ) on force la coincidence
double def_equi_R_ancien= def_equi_R; // sauvegarde qui ne sert à rien, car Coincidence ne change pas
// directement def_equi_R, seulement le pointeur iadef_equi (qui lui ne pointe plus en sortie sur une valeur = def_equi_R)
// mais c'est pour bien marquer le fait que à la sortie de la coïncidence, le pointeur iadef_equi de def_equi à changé
Coincidence(bascule_fct_aide,unSur_wBaseCarre,gijHH,gijBB,save_resul,W_a,iatens,iadef_equi
,iafct,pt_sur_principal,iaOi,oi_sur_principal,iatens_princ,iadef_equi_princ
,iaOi_princ,iafct_princ,rayon_tdt,true);
// si le phi est négatif, on le met à 0 pour limiter les ennuis dans les calculs d'énergies (ici phi ne sert
// ne sert que là par la suite)
if (phi_2_dt < 0.)
phi_2_dt = 0.;
// -- uptdate des énergies
UpdateEnergieHyste(energ,sigma_i_barre_BH,sigma_t_barre_tdt,delta_sigma_barre_tdt_BH
,delta_sigma_barre_BH_Ratdt,phi_2_dt,delta_barre_epsBH
,QdeltaSigmaRatdt,wprime,wprime_point,trajet_neutre,def_equi_R_ancien,def_i_equi,def_equi_atdt);
if (aucun_pt_inversion) { defEqui_maxi = def_equi_atdt;} // si sur la première charge on prend la valeur courante
else // on a des pt d'inversion, on prend le maxi des listes principales ou secondaires
// non c'est pas bon
{ List_io <double>::reverse_iterator iil = save_resul.def_equi.rbegin();iil++;defEqui_maxi = *iil;
};
// on met à jour la def de début de calcul (valant t au début )
// il s'agit d'une grandeur scalaire (pas tensorielle) on peut donc reprendre la valeur qu'elle avait
// au moment du précédent pt d'inversion, ce qui évitera de cumuler des erreurs d'intégration
def_i_equi = def_equi_R_ancien; // def_equi_R n'a pas encore été modifié, il correspond à la précédente valeur d'inversion
// NB: 1)on pourrait également prendre def_equi_atdt, mais qui cumulle les erreurs d'integ entre les deux derniers pt d'integ
// 2) c'est la même formule que dans le cas d'une inversion, mais cela ne donne pas du tout le même résultat
};
};
};
// calcul de la contrainte de retour si le traitement est fini
// et mise à jour a doc
if (fin_traitement)
{save_resul.sigma_barre_BH_tdt = sigma_t_barre_tdt;
save_resul.wBase_tdt = wBase;
save_resul.def_equi_atdt = def_equi_atdt;
switch (cas)
{case 1:
{ // cas de la dérivée de jauman
Tenseur_ns3HH sig1HH(gijHH * sigma_t_barre_tdt);
sigHH = 0.5*(sig1HH+sig1HH.Transpose()); // jauman
break;
}
case 2:
{ // pas de symétrisation du tenseur
sigHH = gijHH * sigma_t_barre_tdt;
break;
}
default:
cout << "\n erreur: cas= " << cas << " non prevu pour le type de derivee de la contrainte ";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::Avancement_temporel(...)" << endl;
Sortie(1);
};
//--------débug- traçage
#ifdef MISE_AU_POINT
if (Permet_affichage() == -77)
{ cout << "\n$$$ === fin de l'algo d'avancement : calcul de la contrainte " << endl ;
};
#endif
//----- fin débug
};
// on regarde si l'on n'a pas dépassé le nombre de boucle maxi permis: ce qui permet
// d'éviter les boucles infinies
nb_coin_inver++;
if (nb_coin_inver > Abs(nb_maxInvCoinSurUnPas))
{ // dans ce cas cela signifie qu'il y a pb et on arrête en générant éventuellement
// une interruption d'erreur de convergence dans une loi de comportement
if (((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
{cout << "\n warning dans le calcul de la contrainte a t+dt, le nombre de coincidence et/ou"
<< " d'inversion (" << nb_coin_inver << ") est superieur a la limite fixee: = "
<< nb_maxInvCoinSurUnPas ;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << flush;
};
// débug---------
// Verif_coincidence(delta_epsBB,gijHH,cas,save_resul,sigHH,energ_t,energ,true);
// Sortie(1);
// fin débug -------------
if (save_resul.nb_coincidence == 0)
{ // on est dans un cas particulier où l'algo fait du sur-place: un coup il trouve une coïncidence
// puis le coup après il trouve une inversion --> il revient au même endroit --> boucle infini
// dans ce cas on décide de manière arbitraire a imposer la coïncidence ce qui garantie la cohérence de la
// succession des rayons on contraire d'imposer l'inversion, qui conduira à un rayon incohérent (ce qui conduit
// normalement tout de suite après à une coïncidence)
force_fin_traitement = true;
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
cout << " on est dans le cas d'aller-retour identiques !! on impose la coincidence " << endl;
}
else // on regarde s'il faut imposer la valeur finale obtenue ou générer une erreur
{ if (nb_maxInvCoinSurUnPas > 0)
{ throw ErrNonConvergence_loiDeComportement();break;} // envoie d'un signal a traiter en dehors
else
{ force_fin_traitement = true;
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
cout << " on impose la coincidence " << endl;
}; // cas où on impose coûte que coûte (résultat pas sûr !!)
};
};
};// -- fin du While (!fin_traitement)
};
// initialisation éventuelle des variables thermo-dépendantes
void Hysteresis3D::Init_thermo_dependance()
{ // cas d'une thermo dépendance, on calcul les grandeurs en fonction de la température
if (xnp_temperature != NULL) xnp = xnp_lue = xnp_temperature->Valeur(*temperature);
if (Qzero_temperature != NULL) Qzero = Qzero_lue = Qzero_temperature->Valeur(*temperature);
if (xmu_temperature != NULL) xmu = xmu_lue = xmu_temperature->Valeur(*temperature);
//--- pour le debug
//cout << "\n np=" << xnp << " Q0=" << Qzero << " xmu=" << xmu << " T=" << *temperature;
//--- fin debug
};
// méthode permettant le calcul de sigma à tdt par différente méthodes: linéarisation
// ou kutta
// en sortie calcul de :
// sigma_t_barre_tdt, delta_sigma_barre_tdt_BH, delta_sigma_barre_BH_Ratdt
// également les grandeurs: QdeltaSigmaRatdt, et wprime,wprime_point, calculées à tdt
// ramène en retour la valeur de phi_2_dt
void Hysteresis3D::CalculContrainte_tdt(double & phi_2_dt,Tableau<double>& indicateurs_resolution)
{ // le calcul de la contrainte s'effectue par la résolution de l'équation différentielle
// du schéma constitutif en BH, et toutes les grandeurs sont relatives à BH
// bien voir que que ce n'est qu'une partie de l'équation, et que pour l'intégration de
// la dérivée de Jauman, il faut aussi la partie HB qui est différente, mais on a une symétrie
// formelle (cf théorie)
// sigma_point = 2*mu*D_barre + beta*phi*(delta_barre de t à R de Sigma)
if ((sortie_post)&&(indicateurs_resolution.Taille()!= 5)) // dimensionnement éventuelle de la sortie d'indicateurs
indicateurs_resolution.Change_taille(5);
calcul_dResi_dsig=false; // on indique que pour l'instant la matrice tangente n'est pas calculée
// comme la matrice n'est pas forcément définie positive on utilise GAUSS avec MatLapack
der_at_racine.Change_Choix_resolution(GAUSS,RIEN_PRECONDITIONNEMENT);
bool passage_par_newton = false; // permettra de savoir si on est passé par du newton dans le cas d'un basculement de méthode
//-- choix de la méthode
switch (type_resolution_equa_constitutive)
{case 1: // cas de la linéarisation de l'équation
{// ----- pour ce faire on appelle une methode de recherche de zero
val_initiale.Zero(); // on démarre la recherche à la valeur à t
racine.Zero(); // init du résultat à 0.
der_at_racine.Initialise(0.); // init de la matrice dérivée à 0.
// on met à jour éventuellement le tableau d'indicateurs
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs
bool conver = false; // init par défaut
try // on met le bloc sous surveillance
{
conver=alg_zero.Newton_raphson
(*this,&Hysteresis3D::Residu_constitutif,&Hysteresis3D::Mat_tangente_constitutif
,val_initiale,racine,der_at_racine,nb_incr_total,nb_iter_total
,maxi_delta_var_sig_sur_iter_pour_Newton);
}
catch (ErrSortieFinale)
// cas d'une direction voulue vers la sortie
// on relance l'interuption pour le niveau supérieur
{ ErrSortieFinale toto;
throw (toto);
}
catch ( ... ) //(ErrNonConvergence_Newton erreur)
{ double absracinemax=racine.Max_val_abs();
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n non convergence 2 sur l'algo de la resolution du schema constitutif"
<< " abs_racine_max " << absracinemax;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::CalculContrainte_tdt(.." << endl;
};
LibereTenseur();
LibereTenseurQ();
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(1)+=nb_incr_total;indicateurs_resolution(2)+=nb_iter_total;
////---- debug
// cout << "\n Hysteresis3D::CalculContrainte_tdt: indicateurs_resolution(1)= "<< indicateurs_resolution(1)
// << " indicateurs_resolution(2)=" << indicateurs_resolution(2)
// << " nb_incr_total "<< nb_incr_total << " nb_iter_total "<< nb_iter_total<< endl;
////---- fin debug
};
// if (!conver)
double absracinemax=racine.Max_val_abs();
if ((!conver) || (!isfinite(absracinemax)) || (isnan(absracinemax)) )
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n non convergence sur l'algo de la resolution du schema constitutif"
<< " abs_racine_max " << absracinemax;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::CalculContrainte_tdt(.." << endl;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
// récup de la solution
for (int ig=1;ig<=9;ig++)
delta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=racine(ig);
sigma_t_barre_tdt = sigma_i_barre_BH + delta_sigma_barre_tdt_BH;
//---- debug
if ((ParaGlob::NiveauImpression() > 5)|| (Permet_affichage() > 5))
// on vérifie que l'amplitude de la contrainte transmise, n'est pas supérieure à la saturation
{ double sigma_tau_II = sigma_tauBH.II();
if ( sigma_tau_II > Qzero*Qzero)
cout << "\n sigma_tau_II= "<< sigma_tau_II << " Hysteresis3D::CalculContrainte_tdt" << endl;
};
//---- fin debug
// ici il n'est pas nécessaire de calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs sont calculées à l'intérieur de la boucle de Newton, et
// pour t+dt donc pas de pb
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
passage_par_newton = true; // c'est vrai compte tenu de la méthode
//modif : 11 juin 2014
// on vérifie que l'amplitude de la contrainte calculée
{double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur10 fatale dans l'algo de la resolution du schema constitutif"
<< " concernant le niveau de saturation de la contrainte "
<< "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase);
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::CalculContrainte_tdt() (..." << endl;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
};
break;
}
case 2: // cas d'une résolution par intégration explicite par du kutta
// si cela ne converge pas on bascule sur de la linéarisation
{//initialisation des variables de calcul
for (int ig=1;ig<=9;ig++)
sig_initiale(ig)=sigma_i_barre_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
double tdeb=0.,tfi=1.;
// calcul de la dérivée initiale
int erreur=0; //init d'une erreur de calcul de Sigma_point
Sigma_point(tdeb,sig_initiale,dersig_initiale,erreur);
//// --- debug ---
//cout << "\n Hysteresis3D::CalculContrainte_tdt avant kutta"
// << "\n sig_initiale= ";sig_initiale.Affiche();
//cout << "\n dersig_initiale= "; dersig_initiale.Affiche();
//cout << endl; double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
//// --- fin debug ---
if (erreur) // cas où le calcul de la dérivée initiale n'est pas possible, on ne peut pas aller plus loin
{ if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur0 fatale dans l'algo de la resolution du schema constitutif"
<< " au niveau du calcul de la derivee initiale "
<< "\n QdeltaSigma =" << sqrt(delta_sigma_barre_R_a_tauBH.II())
<< " au lieu de "<< (Qzero*depassement_Q0*wBase);
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
cout << "\n Hysteresis3D::CalculContrainte_tdt() (..." << endl;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
double dernierTemps=0.,dernierdeltat=0.; // valeurs de retour
int nombreAppelF=0,nb_step=0; // " "
double erreur_maxi_global=0.; // "
// appel de la fonction kutta
int conver=alg_edp.Pilotage_kutta
(cas_kutta,*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale
,tdeb,tfi,erreurAbsolue,erreurRelative
,sig_finale,dersig_finale,dernierTemps,dernierdeltat
,nombreAppelF,nb_step,erreur_maxi_global);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(3)+=nombreAppelF;indicateurs_resolution(4)+=nb_step;
indicateurs_resolution(5)+=erreur_maxi_global;
};
// gestion de l'erreur de retour
// if ((conver != 2) || (sig_finale.Max_val_abs() > ConstMath::tresgrand))
// --- debug piloté ---
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt "
<< "nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
<< erreur_maxi_global << endl;
// --- fin debug piloté---
double abssigmax=sig_finale.Max_val_abs();
if ((conver != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) )
{// dans le cas où le Runge ne marche pas on essaie avec la première méthode
// linéarisation de l'équation
// ----- pour ce faire on appelle une methode de recherche de zero
val_initiale.Zero(); // on démarre la recherche à la valeur à t
racine.Zero(); // init du résultat à 0.
der_at_racine.Initialise(0.); // init de la matrice dérivée à 0.
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
bool converge=alg_zero.Newton_raphson
(*this,&Hysteresis3D::Residu_constitutif,&Hysteresis3D::Mat_tangente_constitutif
,val_initiale,racine,der_at_racine,nb_incr_total,nb_iter_total
,maxi_delta_var_sig_sur_iter_pour_Newton);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(1)+=nb_incr_total;indicateurs_resolution(2)+=nb_iter_total;};
double absracinemax=racine.Max_val_abs();
if ((converge) && (isfinite(absracinemax)) && (!isnan(absracinemax)))
{ // on a convergé, donc on termine le calcul et on sort du switch
// récup de la solution
for (int ig=1;ig<=9;ig++)
delta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=racine(ig);
sigma_t_barre_tdt = sigma_i_barre_BH + delta_sigma_barre_tdt_BH;
// ici il n'est pas nécessaire de calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs sont calculées à l'intérieur de la boucle de Newton, et
// pour t+dt donc pas de pb
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
passage_par_newton = true; // on indique donc que l'on est passé par du newton
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
{ cout << "\n probleme dans la resolution de l'equation constitutive avec Runge Kutta";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << flush;
if (conver != 2)
alg_edp.Affiche_Explication_erreur_RG(conver);
if (!isfinite(abssigmax))
cout << " abssigmax n'est pas fini = " << abssigmax ;
if (isnan(abssigmax))
cout << " abssigmax = nan = " << abssigmax ;
if (Permet_affichage() > 2)
{ cout << "\n abs_racine_max " << absracinemax;}
if (Permet_affichage() > 4)
{cout << " (2) utilisation avec succes de la linearisation ";};
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt (..."<<endl;
};
// puis on met conver à 2 pour signaler que pour la suite que ça a convergé
conver=2;
break;
}
else // sinon on n'a pas convergé également avec la linéarisation
// on indique à toute fin utile que la première n'a pas convergé au cas ou cela n'aurait pas été noté
{ if (conver == 2)
conver = 0 ;
};
};
// arrivé ici cela signifie que: soit kutta a convergé -> conver=2,
// soit kutta n'a pas convergé et la méthode de linéarisation n'a pas également convergé -> conver != 2
// --- si on n'a pas convergé:
if (conver !=2) // cas d'une non convergence
{ // on appel du kutta adoc sans gestion d'erreur !!
double deltat=tfi-tdeb;
switch (cas_kutta)
{ case 3:
{ alg_edp.Runge_Kutta_step23(*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale,tdeb,deltat,sig_finale,estime_erreur);
break;
}
case 4:
{ alg_edp.Runge_Kutta_step34(*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale,tdeb,deltat,sig_finale,estime_erreur);
break;
}
case 5:
{ alg_edp.Runge_Kutta_step45(*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale,tdeb,deltat,sig_finale,estime_erreur);
break;
}
default:
cout << "\n erreur , cas Runge kutta non prevu ! "
<< "\n Hysteresis3D::CalculContrainte_tdt(..";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();
Sortie(1);
};
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
{cout << "\n probleme dans la resolution de l'equation constitutive avec Runge Kutta";
alg_edp.Affiche_Explication_erreur_RG(conver);
cout << ", appel direct de kutta-> erreur estimee= " << estime_erreur(1)
<< "\n Hysteresis3D::CalculContrainte_tdt (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
// Sortie(1);
// pour le debug
// if ((Dabs(estime_erreur(1)) > 10) || (Dabs(sig_finale(1)) > 10))
// alg_edp.Runge_Kutta_step45(*this,& Hysteresis3D::Sigma_point,sig_initiale,dersig_initiale
// ,tdeb,deltat,sig_finale,estime_erreur);
};
double abssigmax=sig_finale.Max_val_abs();
if ((!isfinite(abssigmax)) || (isnan(abssigmax)) )
// dans le cas où la valeur de sig_finale est infinie, ce n'est pas la peine d'aller plus loin
{
cout << "\n erreur , l'appel directe de Kutta donne une valeur infinie de contrainte ! "
<< "\n Hysteresis3D::CalculContrainte_tdt(..";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
// on génère une exception
throw ErrNonConvergence_loiDeComportement();
Sortie(1);
};
}
// -- arrivée ici, cela veut dire que: 1) soit le RG de départ a marché correctement,
// 2) soit la linéarisation a marché correctement, 3) soit si les deux autres n'ont pas marché,
// on a eu un appel directe à un Rg d'un ordre donné, avec un résultat non contrôlé
else if (!passage_par_newton)// sinon cela veut dire que c'est le résultat avec Runge que l'on exploite
{// récup des résultats
for (int ig=1;ig<=9;ig++)
sigma_t_barre_tdt.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=sig_finale(ig);
delta_sigma_barre_tdt_BH = sigma_t_barre_tdt - sigma_i_barre_BH;
// ici on doit calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs ne sont pas calculées au temps final !! dans la méthode de Runge-Kutta
// d'ailleurs elles ne sont même pas calculées en temps que grandeurs globales !!
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
QdeltaSigmaRatdt = sqrt(delta_sigma_barre_BH_Ratdt.II());
};
// le dernier cas possible avec convergence est celui du passage par newton, et dans ce cas
// la sauvegarde a déjà été faite
//modif : 11 juin 2014
// on vérifie que l'amplitude de la contrainte calculée
{double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur11 fatale dans l'algo de la resolution du schema constitutif"
<< " concernant le niveau de saturation de la contrainte "
<< "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
};
break;
}
case 3: // cas d'une résolution par intégration explicite par du kutta
// mais ici si ça ne converge pas on génère une exception c'est tout , on ne cherche pas
// a utiliser une autre méthode de secours
{//initialisation des variables de calcul
for (int ig=1;ig<=9;ig++)
sig_initiale(ig)=sigma_i_barre_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
double tdeb=0.,tfi=1.;
int erreur=0; //init d'une erreur de calcul de Sigma_point
// calcul de la dérivée initiale
Sigma_point(tdeb,sig_initiale,dersig_initiale,erreur);
if (erreur) // cas où le calcul de la dérivée initiale n'est pas possible, on ne peut pas aller plus loin
{ if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur1 fatale dans l'algo de la resolution du schema constitutif"
<< " au niveau du calcul de la derivee initiale "
<< "\n QdeltaSigma =" << sqrt(delta_sigma_barre_R_a_tauBH.II()) << " au lieu de "<< Qzero
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
double dernierTemps=0.,dernierdeltat=0.; // valeurs de retour
int nombreAppelF=0,nb_step=0; // " "
double erreur_maxi_global=0.; // "
// appel de la fonction kutta
int conver=alg_edp.Pilotage_kutta
(cas_kutta,*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale
,tdeb,tfi,erreurAbsolue,erreurRelative
,sig_finale,dersig_finale,dernierTemps,dernierdeltat
,nombreAppelF,nb_step,erreur_maxi_global);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(3)+=nombreAppelF;indicateurs_resolution(4)+=nb_step;
indicateurs_resolution(5)+=erreur_maxi_global;
};
// --- debug piloté ---
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt "
<< "nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
<< erreur_maxi_global << endl;
// --- fin debug piloté---
// gestion de l'erreur de retour
// if ((conver != 2) || (sig_finale.Max_val_abs() > ConstMath::tresgrand))
double abssigmax=sig_finale.Max_val_abs();
if ((conver != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) )
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n non convergence sur l'algo de la resolution du schema constitutif"
<< "\n Hysteresis3D::CalculContrainte_tdt(.." ;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
// récup des résultats
for (int ig=1;ig<=9;ig++)
sigma_t_barre_tdt.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=sig_finale(ig);
delta_sigma_barre_tdt_BH = sigma_t_barre_tdt - sigma_i_barre_BH;
// ici on doit calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs ne sont pas calculées au temps final !! dans la méthode de Runge-Kutta
// d'ailleurs elles ne sont même pas calculées en temps que grandeurs globales !!
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
QdeltaSigmaRatdt = sqrt(delta_sigma_barre_BH_Ratdt.II());
//modif : 11 juin 2014
// on vérifie que l'amplitude de la contrainte calculée
{if ( QdeltaSigmaRatdt > (Qzero*depassement_Q0*wBase))
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n erreur12 fatale dans l'algo de la resolution du schema constitutif"
<< " concernant le niveau de saturation de la contrainte "
<< "\n QdeltaSigma =" << QdeltaSigmaRatdt << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
};
break;
}
case 4: // cas d'une résolution par intégration explicite par du kutta
{//initialisation des variables de calcul
for (int ig=1;ig<=9;ig++)
sig_initiale(ig)=sigma_i_barre_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
double tdeb=0.,tfi=1.;
// calcul de la dérivée initiale
int erreur=0; //init d'une erreur de calcul de Sigma_point
Sigma_point(tdeb,sig_initiale,dersig_initiale,erreur);
if (erreur) // cas où le calcul de la dérivée initiale n'est pas possible, on ne peut pas aller plus loin
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n erreur2 fatale dans l'algo de la resolution du schema constitutif"
<< " au niveau du calcul de la derivee initiale "
<< "\n QdeltaSigma =" << sqrt(delta_sigma_barre_R_a_tauBH.II()) << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
double dernierTemps=0.,dernierdeltat=0.; // valeurs de retour
int nombreAppelF=0,nb_step=0; // " "
double erreur_maxi_global=0.; // "
// appel de la fonction kutta
int conver=alg_edp.Pilotage_kutta
(cas_kutta,*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale
,tdeb,tfi,erreurAbsolue,erreurRelative
,sig_finale,dersig_finale,dernierTemps,dernierdeltat
,nombreAppelF,nb_step,erreur_maxi_global);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(3)+=nombreAppelF;indicateurs_resolution(4)+=nb_step;
indicateurs_resolution(5)+=erreur_maxi_global;
};
// --- debug piloté ---
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
{cout << "\n Hysteresis3D::CalculContrainte_tdt "
<< "nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
<< erreur_maxi_global;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature(); cout << flush;
};
// --- fin debug piloté---
// gestion de l'erreur de retour
// if ((conver != 2) || (sig_finale.Max_val_abs() > ConstMath::tresgrand))
double abssigmax=sig_finale.Max_val_abs();
if ((conver != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) )
{// dans le cas où le Runge ne marche pas on essaie avec la première méthode
// linéarisation de l'équation
// ----- pour ce faire on appelle une methode de recherche de zero
val_initiale.Zero(); // on démarre la recherche à la valeur à t
racine.Zero(); // init du résultat à 0.
der_at_racine.Initialise(0.); // init de la matrice dérivée à 0.
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
bool converge=alg_zero.Newton_raphson
(*this,&Hysteresis3D::Residu_constitutif,&Hysteresis3D::Mat_tangente_constitutif
,val_initiale,racine,der_at_racine,nb_incr_total,nb_iter_total
,maxi_delta_var_sig_sur_iter_pour_Newton);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(1)+=nb_incr_total;indicateurs_resolution(2)+=nb_iter_total;};
double absracinemax=racine.Max_val_abs();
if ((converge) && (isfinite(absracinemax)) && (!isnan(absracinemax)))
{ // on a convergé, donc on termine le calcul et on sort du switch
// récup de la solution
for (int ig=1;ig<=9;ig++)
delta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=racine(ig);
sigma_t_barre_tdt = sigma_i_barre_BH + delta_sigma_barre_tdt_BH;
// ici il n'est pas nécessaire de calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs sont calculées à l'intérieur de la boucle de Newton, et
// pour t+dt donc pas de pb
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
passage_par_newton = true; // on indique donc que l'on est passé par du newton
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 2)) || (Permet_affichage() > 2))
{ if (Permet_affichage() > 4)
{cout << " -> probleme dans la resolution de l'equation constitutive avec Runge Kutta";
alg_edp.Affiche_Explication_erreur_RG(conver);
cout << ", (1) utilisation avec succes de la linearisation ";
cout << "\n abs_racine_max " << absracinemax;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt (..."<<endl;
};
// puis on met conver à 2 pour signaler que pour la suite que ça a convergé
conver=2;
break;
}
else
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 2)) || (Permet_affichage() > 2))
{cout << "\n non convergence sur l'algo de la resolution du schema constitutif"
<< " abs_racine_max " << absracinemax << " conver= " << conver << " abssigmax= " << abssigmax;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 7)) || (Permet_affichage() > 7))
cout << "\n Hysteresis3D::CalculContrainte_tdt(.." << endl;
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
}
else // sinon cela veut dire que le calcul avec Runge est correcte on sauvegarde les résutats
{// récup des résultats
for (int ig=1;ig<=9;ig++)
sigma_t_barre_tdt.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=sig_finale(ig);
delta_sigma_barre_tdt_BH = sigma_t_barre_tdt - sigma_i_barre_BH;
// ici on doit calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs ne sont pas calculées au temps final !! dans la méthode de Runge-Kutta
// d'ailleurs elles ne sont même pas calculées en temps que grandeurs globales !!
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
QdeltaSigmaRatdt = sqrt(delta_sigma_barre_BH_Ratdt.II());
};
//modif : 11 juin 2014
// on vérifie que l'amplitude de la contrainte calculée
{double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur13 fatale dans l'algo de la resolution du schema constitutif"
<< " concernant le niveau de saturation de la contrainte "
<< "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (..." ;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
};
break;
}
case 5: case 6:// cas d'une résolution par intégration explicite par du kutta
// l'idée est ici de diminuer la précision jusqu'à un résultat si on ne converge pas normalement
{//initialisation des variables de calcul
for (int ig=1;ig<=9;ig++)
sig_initiale(ig)=sigma_i_barre_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
double tdeb=0.,tfi=1.;
// calcul de la dérivée initiale
int erreur=0; //init d'une erreur de calcul de Sigma_point
Sigma_point(tdeb,sig_initiale,dersig_initiale,erreur);
if (erreur) // cas où le calcul de la dérivée initiale n'est pas possible, on ne peut pas aller plus loin
{ if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur3 fatale dans l'algo de la resolution du schema constitutif"
<< " au niveau du calcul de la derivee initiale "
<< "\n QdeltaSigma =" << sqrt(delta_sigma_barre_R_a_tauBH.II()) << " au lieu de "
<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
double dernierTemps=0.,dernierdeltat=0.; // valeurs de retour
int nombreAppelF=0,nb_step=0; // " "
double erreur_maxi_global=0.; // "
// appel de la fonction kutta
int conver=alg_edp.Pilotage_kutta
(cas_kutta,*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale
,tdeb,tfi,erreurAbsolue,erreurRelative
,sig_finale,dersig_finale,dernierTemps,dernierdeltat
,nombreAppelF,nb_step,erreur_maxi_global);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(3)+=nombreAppelF;indicateurs_resolution(4)+=nb_step;
indicateurs_resolution(5)+=erreur_maxi_global;
};
// --- debug piloté ---
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt "
<< "nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
<< erreur_maxi_global << endl;
// --- fin debug piloté---
// gestion de l'erreur de retour
// if ((conver != 2) || (sig_finale.Max_val_abs() > ConstMath::tresgrand))
double abssigmax=sig_finale.Max_val_abs();
if ((conver != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) )
{// dans le cas où le Runge ne marche pas on essaie avec la première méthode
// linéarisation de l'équation
// ----- pour ce faire on appelle une methode de recherche de zero
val_initiale.Zero(); // on démarre la recherche à la valeur à t
racine.Zero(); // init du résultat à 0.
der_at_racine.Initialise(0.); // init de la matrice dérivée à 0.
int nb_incr_total,nb_iter_total; // variables intermédiaires d'indicateurs
// 1== résolution de l'équation constitutive d'avancement discrétisée en euler implicite
bool converge=alg_zero.Newton_raphson
(*this,&Hysteresis3D::Residu_constitutif,&Hysteresis3D::Mat_tangente_constitutif
,val_initiale,racine,der_at_racine,nb_incr_total,nb_iter_total
,maxi_delta_var_sig_sur_iter_pour_Newton);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(1)+=nb_incr_total;indicateurs_resolution(2)+=nb_iter_total;};
// if (converge)
double absracinemax=racine.Max_val_abs();
if ((converge) && (isfinite(absracinemax)) && (!isnan(absracinemax)))
{ // on a convergé, donc on termine le calcul et on sort du switch
// récup de la solution
for (int ig=1;ig<=9;ig++)
delta_sigma_barre_tdt_BH.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=racine(ig);
sigma_t_barre_tdt = sigma_i_barre_BH + delta_sigma_barre_tdt_BH;
// ici il n'est pas nécessaire de calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs sont calculées à l'intérieur de la boucle de Newton, et
// pour t+dt donc pas de pb
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
passage_par_newton = true; // on indique donc que l'on est passé par du newton
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 2)) || (Permet_affichage() > 2))
{ cout << "\n estime_erreur= " << estime_erreur(1);
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
if (Permet_affichage() > 4)
{cout << " -> probleme dans la resolution de l'equation constitutive avec Runge Kutta";
alg_edp.Affiche_Explication_erreur_RG(conver);
cout << ", (3) utilisation avec succes de la linearisation ";
};
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt (..."<<endl;
};
// puis on met conver à 2 pour signaler que pour la suite que ça a convergé
conver=2;
break;
}
else // sinon on n'a pas convergé également avec la linéarisation
// on indique à toute fin utile que la première n'a pas convergé au cas ou cela n'aurait pas été noté
{ if (conver == 2)
conver = 0 ;
};
};
// arrivé ici cela signifie que: soit kutta a convergé -> conver=2,
// soit kutta n'a pas convergé et la méthode de linéarisation n'a pas également convergé -> conver != 2
if (conver !=2) // cas d'une non convergence
{ // l'idée est de diminuer la précision jusqu'à une solution
int conver_interne = 0;
double erreurAsolue_inter=erreurAbsolue;
double erreurRelative_inter = erreurRelative;
int nb_boucle=1;
double abssigmax0; // init
do
{ erreurAsolue_inter *=10;
erreurRelative_inter *=10;
nb_boucle ++;
for (int ig=1;ig<=9;ig++)
sig_initiale(ig)=sigma_i_barre_BH(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig));
double tdeb=0.,tfi=1.;
// calcul de la dérivée initiale
int erreur=0; //init d'une erreur de calcul de Sigma_point
Sigma_point(tdeb,sig_initiale,dersig_initiale,erreur);
if (erreur) // cas où le calcul de la dérivée initiale n'est pas possible, on ne peut pas aller plus loin
{ if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur4 fatale dans l'algo de la resolution du schema constitutif"
<< " au niveau du calcul de la derivee initiale "
<< "\n QdeltaSigma =" << sqrt(delta_sigma_barre_R_a_tauBH.II()) << " au lieu de "<< Qzero
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
double dernierTemps=0.,dernierdeltat=0.; // valeurs de retour
int nombreAppelF=0,nb_step=0; // " "
erreur_maxi_global=0.;
// appel de la fonction kutta
conver_interne=alg_edp.Pilotage_kutta
(cas_kutta,*this,& Hysteresis3D::Sigma_point,& Hysteresis3D::Verif_integrite_Sigma
,sig_initiale,dersig_initiale
,tdeb,tfi,erreurAsolue_inter,erreurRelative_inter
,sig_finale,dersig_finale,dernierTemps,dernierdeltat
,nombreAppelF,nb_step,erreur_maxi_global);
if(sortie_post) // sauvegarde éventuelle des indicateurs
{indicateurs_resolution(3)+=nombreAppelF;indicateurs_resolution(4)+=nb_step;
indicateurs_resolution(5)+=erreur_maxi_global;
};
// --- debug piloté ---
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n Hysteresis3D::CalculContrainte_tdt "
<< "nombreAppelF= " << nombreAppelF << " nb_step= " << nb_step << " erreur_maxi_global= "
<< erreur_maxi_global << endl;
// --- fin debug piloté---
if (nb_boucle > 10) // si en * par 10^10 on n'a pas réussi on arrête
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 0))
{cout << "\n non convergence extreme !! sur l'algo de la resolution du schema constitutif"
<< "\n Hysteresis3D::CalculContrainte_tdt(.." ;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
abssigmax=sig_finale.Max_val_abs();
}
while ((conver_interne != 2) || (!isfinite(abssigmax)) || (isnan(abssigmax)) );
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
{cout << "\n probleme dans la resolution de l'equation constitutive avec Runge Kutta";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
alg_edp.Affiche_Explication_erreur_RG(conver);
cout << ", decroissance de la precision -> erreur estimee= "
<< erreur_maxi_global << " nb cycle= " << nb_boucle
<< "\n Hysteresis3D::CalculContrainte_tdt (..."<< endl;
};
}
else if (!passage_par_newton)// sinon cela veut dire que le calcul avec Runge est correcte on sauvegarde les résutats
{// récup des résultats
for (int ig=1;ig<=9;ig++)
sigma_t_barre_tdt.Coor(Tenseur3BH::idx_i(ig),Tenseur3BH::idx_j(ig))=sig_finale(ig);
delta_sigma_barre_tdt_BH = sigma_t_barre_tdt - sigma_i_barre_BH;
// ici on doit calculer QdeltaSigmaRatdt, et wprime,wprime_point
// car ces grandeurs ne sont pas calculées au temps final !! dans la méthode de Runge-Kutta
// d'ailleurs elles ne sont même pas calculées en temps que grandeurs globales !!
delta_sigma_barre_BH_Ratdt = sigma_t_barre_tdt - sigma_barre_BH_R;
QdeltaSigmaRatdt = sqrt(delta_sigma_barre_BH_Ratdt.II());
};
// le dernier cas possible avec convergence est celui du passage par newton, et dans ce cas
// la sauvegarde a déjà été faite
//modif : 11 juin 2014
// on vérifie que l'amplitude de la contrainte calculée
{double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{if ((ParaGlob::NiveauImpression() > 3)|| (Permet_affichage() > 0))
{cout << "\n erreur14 fatale dans l'algo de la resolution du schema constitutif"
<< " concernant le niveau de saturation de la contrainte "
<< "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< "\n Hysteresis3D::CalculContrainte_tdt() (...";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();break;
};
};
break;
}
};
//--- // fin du switch sur les différentes méthodes pour calculer la contraintes à tdt
// --- on calcul certaines grandeurs globales et locales
//------ debug------
//cout << "\n dd " << delta_sigma_barre_BH_Ratdt.MaxiComposante() << ", "
// << " fini ? " << isfinite(delta_sigma_barre_BH_Ratdt.MaxiComposante())
// << " isnan . " << isnan(delta_sigma_barre_BH_Ratdt.MaxiComposante());
//cout << "\n delta_sigma_barre_BH_Ratdt=== ";
//delta_sigma_barre_BH_Ratdt.Ecriture(cout);
//if ((!isfinite(delta_sigma_barre_BH_Ratdt.MaxiComposante()))||(isnan(delta_sigma_barre_BH_Ratdt.MaxiComposante())))
// { cout << " delta_sigma_barre_BH_Ratdt= ";
// delta_sigma_barre_BH_Ratdt.Ecriture(cout);
// };
//----- fin debug -----
if ((type_resolution_equa_constitutive != 1)&& (!passage_par_newton))
{ // sauf le cas 1, tous les autres c'est des kutta on doit calculer wprime,wprime_point
// car ces grandeurs ne sont pas calculées au temps final !! dans la méthode de Runge-Kutta
// d'ailleurs elles ne sont même pas calculées en temps que grandeurs globales !!
Cal_wprime(QdeltaSigmaRatdt,delta_sigma_barre_BH_Ratdt,Q_OiaR,delta_sigma_barre_BH_OiaR
,wBase,delta_sigma_barre_tdt_BH,wprime,wprime_point,trajet_neutre);
// --- si dépendance de la phase de sigma0i_tdt (et non delta sigma) mise à jour des para matériaux
if (avec_phaseDeltaSig)
{xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
ParaMateriauxAvecPhaseDeltaSig(xnp,delta_sigma_barre_BH_OiaR,delta_sigma_barre_BH_Ratdt,xmu,Qzero);
};
};
// --<< calcul de phi >>---
if (trajet_neutre) // cas où l'on n'a pas un trajet neutre
{ phi_2_dt = 0.;} // pas de variation sur un trajet neutre
else
{ phi_2_dt = (delta_sigma_barre_BH_Ratdt && delta_barre_epsBH)
- QdeltaSigmaRatdt * QdeltaSigmaRatdt * wprime_point / (2.*xmu * wprime);
//------ debug------
//if ((!isfinite(phi_2_dt))||(isnan(phi_2_dt)))
// { cout << "\n";
// delta_sigma_barre_BH_Ratdt.Ecriture(cout);
// delta_barre_epsBH.Ecriture(cout);
// cout << " q= " << QdeltaSigmaRatdt;
//// Sortie(1);
// };
//// if (phi_2_dt < 0.) cout << "\n phi_2_dt = " << phi_2_dt;
// cout << " " << phi_2_dt;
//----- fin debug -----
};
// --- si dépendance à la déformation équivalente on calcul le xnp correspondant à un phi = 0
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigmaRatdt,phi_2_dt,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
};
// calcul de l'expression permettant d'obtenir la dérivée temporelle de la contrainte
// en fait il s'agit de l'équation constitutive
// utilisée dans la résolution explicite (runge par exemple) de l'équation constitutive
// erreur : indique si le calcul est valide =0 dans ce cas
// sinon (diff de 0) indique que les valeurs calculées ne sont pas licite
// =1: la norme de sigma est supérieure à la valeur limite de saturation
Vecteur& Hysteresis3D::Sigma_point(const double & tau, const Vecteur & sigma_tau, Vecteur& sig_point,int& erreur)
{
double titi= tau; // sert à rien, c'est pour taire le compilo car tau ne sert pas directement
// récup de la contrainte à tau
for (int i=1;i<=9;i++)
sigma_tauBH.Coor(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i)) = sigma_tau(i);
//modif : 1 juin 2014
// non on fait la vérif sur le delta cf. plus bas
// // on vérifie que l'amplitude de la contrainte transmise, n'est pas supérieure à la saturation
// double sigma_tau_II = sigma_tauBH.II();
// if ( sigma_tau_II > Qzero*Qzero)
// {erreur = 1;
// //--- pour le debug
// if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
// cout << "\n sigma_tau_II =" << sigma_tau_II << " au lieu de "<< Qzero*Qzero
// << " Hysteresis3D::Sigma_point " << endl ;
// //--- fin debug
// }
// else // sinon on continue
// { erreur = 0;
//--- pour le debug
//cout << "\n tt np=" << xnp << " Q0=" << Qzero << " xmu=" << xmu << " T=" << *temperature;
//--- fin debug
// variation de sigma de R à tau
delta_sigma_barre_R_a_tauBH = sigma_tauBH - sigma_barre_BH_R; // ne sert que dans Sigma_point
delta_sigma_barre_t_a_tauBH = sigma_tauBH - sigma_i_barre_BH; // ne sert que dans Sigma_point
// calcul de QdeltaSigma: on prend la valeur absolue car dans les petits nombres on peut avoir des presques 0 !!
// négatifs qui conduisent à une racine infinie !!
double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
//modif : 1 juin 2014
// on vérifie que l'amplitude de la contrainte transmise, n'est pas supérieure à la saturation
// on fait la vérification sur le delta, car si on est sur une branche non initiale, on peut très bien
// dépasser le Qzero, localement, mais ce sera invalidé ensuite avec l'algo de coincidence
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{erreur = 1;
//--- pour le debug
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< " Hysteresis3D::Sigma_point " << endl ;
//--- fin debug
}
else // sinon on continue
{ erreur = 0;
// -- calculs relatifs aux angles de phases : calcul de -> wprime,wprime_point,trajet_neutre
Cal_wprime(QdeltaSigma,delta_sigma_barre_R_a_tauBH,Q_OiaR,delta_sigma_barre_BH_OiaR
,wBase,delta_sigma_barre_t_a_tauBH,wprime,wprime_point,trajet_neutre);
// --- si dépendance de la phase de sigma0i_tdt (et non delta sigma) mise à jour des para matériaux
if (avec_phaseDeltaSig)
{xnp = xnp_lue; xmu = xmu_lue; Qzero = Qzero_lue;
// calcul de xnp, xmu et Qzero
ParaMateriauxAvecPhaseDeltaSig(xnp,delta_sigma_barre_BH_OiaR,delta_sigma_barre_R_a_tauBH,xmu,Qzero);
};
double phitau = (delta_sigma_barre_R_a_tauBH && delta_barre_epsBH) ; // init partie radial // -- modif 16 juin 2012 --
if (!trajet_neutre) // -- modif 16 juin 2012 --
phitau -= QdeltaSigma * QdeltaSigma * wprime_point / (2. * xmu * wprime); // -- modif 16 juin 2012 --
// -- modif 7 mai 2012 ---
// dans le cas où le phidt est négatif, l'équation constitutive n'est plus valide, dans ce cas on considère
// que phi est nulle, c-a-d que l'on évolue suivant un trajet neutre ce qui n'est sans doute pas l'idéal, mais permet d'éviter l'explosion
// -- calcul de phidt
// if ((phitau < 0) && force_phi_zero_si_negatif)
if (phitau < 0) // -- modif 9 fev 2015 --
{if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 8)) || (Permet_affichage() > 8) )
cout << "\n phidt= " << phitau << "\n Hysteresis3D::Sigma_point(..." << endl;
if ( Dabs(phitau) < force_phi_zero_si_negatif) // -- modif 9 fev 2015 --
{ if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
// if (MaX(ParaGlob::NiveauImpression(),Permet_affichage()) >= 5)
{ cout << "\n attention on utilise une valeur de phi negative dans pour le calcul de l'equation constitutive "
<< " phitau= " << phitau
<< "\n Hysteresis3D::Sigma_point(..." ;
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
phitau = 0.;trajet_neutre = true;
};
};
// fin modif modif 7 mai 2012 ---
if (trajet_neutre) // -- modif 16 juin 2012 --
{ // si c'est un trajet neutre, l'équation constitutive est beaucoup plus simple: sigma_point = 2 mu D_barre
// variables intermédiaires pour les tests
betaphideltasigHB.Inita(0.);
deuxmudeltaepsHB = (2. * xmu ) * delta_barre_epsBH;
// formule pour un trajet neutre : sigma_pointBH = 2. * xmu * delta_barre_epsBH ;
sigma_pointBH = deuxmudeltaepsHB;
// --- si dépendance à la déformation équivalente on calcul le xnp correspondant à un phi = 0
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
double phitau = 0.;
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
ParaMateriauxAvecDefEqui(xnp,QdeltaSigma,phitau,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
}
else
{ // cas d'un trajet non neutre
// modif 7 mai 2012 --- on ne recalcule plus le phi qui a été calculé plus haut pour savoir s'il était négatif
// // --- calcul de phi
// double phitau = (delta_sigma_barre_R_a_tauBH && delta_barre_epsBH)
// - QdeltaSigma * QdeltaSigma * wprime_point / (2. * xmu * wprime);
// --- si dépendance à la déformation équivalente
if (avec_defEqui)
{ if (!avec_phaseDeltaSig && !avec_phaseEps) xnp = xnp_lue; // sinon ça déjà été fait
if (Qzero_defEqui!=NULL) Qzero = Qzero_lue;
// calcul de xnp (qui est le seul paramètre de retour de la méthode)
ParaMateriauxAvecDefEqui(xnp,QdeltaSigma,phitau,wprime,def_equi_R,trajet_neutre,def_i_equi,defEqui_maxi);
};
// --- calcul de Beta
double unsurwprimeQ0_puiss_np = 1./pow(wprime*Qzero,xnp);
double beta=0.; // init dans le cas où ne le calcul pas après
if (QdeltaSigma >= ConstMath::petit)
// on ne calcul beta que si la norme de QdeltaSigma est significative
{if (xnp == 2.) { beta = - 2. * xmu * unsurwprimeQ0_puiss_np;}
else {beta = - 2. * xmu * unsurwprimeQ0_puiss_np * pow(QdeltaSigma,xnp-2.);};
};
// -- calcul de la dérivée temporelle de la contrainte
// on considère que D est constant = delta_barre_epsBH/deltat et comme deltat = 1
// ==> = delta_barre_epsBH
// variables intermédiaires pour les tests
betaphideltasigHB = beta * phitau * delta_sigma_barre_R_a_tauBH;
deuxmudeltaepsHB = (2. * xmu ) * delta_barre_epsBH;
// formule normale : sigma_pointBH = 2. * xmu * delta_barre_epsBH + beta * phitau * delta_sigma_barre_R_a_tauBH;
sigma_pointBH = deuxmudeltaepsHB + betaphideltasigHB;
}; // fin du test sur trajet_neutre
// si pb : a faire sur toutes les composantes: limitations des dérivées: spécifiques à la loi d'évolution
// on limite la variation de la dérivée de la contrainte
/* for (int i=1;i<=3;i++) for (int j=1;j<=3;j++)
if (deuxmudeltaepsHB(i,j) > 0.)
{// cas d'une contrainte positive et normalement la dérivée doit évoluer entre 2mu et 0 (saturation)
if (sigma_pointBH(i,j) < 0. ) sigma_pointBH(i,j) = 0.;
if (sigma_pointBH(i,j) > deuxmudeltaepsHB(i,j)) sigma_pointBH(i,j) = deuxmudeltaepsHB(i,j);
}
else
{// cas d'une contrainte négative et normalement la dérivée doit évoluer entre -2mu et 0 (saturation)
if (sigma_pointBH(i,j) < deuxmudeltaepsHB(i,j) ) sigma_pointBH(i,j) = deuxmudeltaepsHB(i,j);
if (sigma_pointBH(i,j) > 0.) sigma_pointBH(i,j) = 0.;
}; */
// si pb : a faire sur toutes les composantes: limitations des dérivées: spécifiques à la loi d'évolution
// on limite la variation de la dérivée de la contrainte au niveau de la dérivée à l'origine
// en fait cela introduit une erreur systématique "dramatique !!" sur le résultat qui est alors erroné !!!
// car il y a accumulation, et il n'y a pas de détection de cette erreur
// donc au lieu de regarder si l'on est juste supérieur, on met une petite marge ???
// non pas bon non plus, donc on supprime !!! à voir par la suite
// sans doute que s'il y a une erreur il faut récupérer une exception à un autre endroit
if (type_resolution_equa_constitutive==6) // cas exploratoire
{ double marge = 100.;
//// for (int i=1;i<=3;i++) for (int j=1;j<=3;j++)
//// if (Dabs(sigma_pointBH(i,j)) > marge*Dabs(deuxmudeltaepsHB(i,j))) sigma_pointBH(i,j) = deuxmudeltaepsHB(i,j);
// on tente une autre stratégie: on regarde l'intensité et on limite, parcontre on garde la même direction que celle calculée
// calcul de l'intensité de cisaillement de la vitesse de déformation
double deuxmuQdeltaeps = sqrt(deuxmudeltaepsHB.II());
// on n'intervient que si deuxmuQdeltaeps a une valeur non nulle
if (deuxmuQdeltaeps > ConstMath::petit)
if (QdeltaSigma > marge * deuxmuQdeltaeps) // normalement pb
{sigma_pointBH *= marge*deuxmuQdeltaeps/QdeltaSigma;
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 3)) || (Permet_affichage() > 3))
{cout << "\n limitation de sigma_point ";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
};
};
};
// retour de la dérivée temporelle de la contrainte
for (int i=1;i<=9;i++)
sig_point(i) = sigma_pointBH(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i));
};
// retour de la dérivée, qui n'a été calculée que si l'erreur = 0
return sig_point;
};
// vérification de l'intégrité du sigma calculé
// erreur : =0: le calcul est licite, si diff de 0, indique qu'il y a eu une erreur
// =1: la norme de sigma est supérieure à la valeur limite de saturation
void Hysteresis3D::Verif_integrite_Sigma(const double & , const Vecteur & sigma_tau,int & erreur)
{ // récup de la contrainte à tau
for (int i=1;i<=9;i++)
sigma_tauBH.Coor(Tenseur3BH::idx_i(i),Tenseur3BH::idx_j(i)) = sigma_tau(i);
//modif : 1 juin 2014
// non on fait la vérif sur le delta cf. plus bas
// // on vérifie que l'amplitude de la contrainte transmise, n'est pas supérieure à la saturation
// double sigma_tau_II = sigma_tauBH.II();
// if ( sigma_tau_II > Qzero*Qzero)
// {erreur = 1;
// //--- pour le debug
// if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
// cout << "\n sigma_tau_II =" << sigma_tau_II << " au lieu de "<< Qzero*Qzero
// << " Hysteresis3D::Sigma_point " << endl ;
// //--- fin debug
// }
// else // sinon on continue
// { erreur = 0;
//--- pour le debug
//cout << "\n tt np=" << xnp << " Q0=" << Qzero << " xmu=" << xmu << " T=" << *temperature;
//--- fin debug
// variation de sigma de R à tau
delta_sigma_barre_R_a_tauBH = sigma_tauBH - sigma_barre_BH_R; // ne sert que dans Sigma_point
delta_sigma_barre_t_a_tauBH = sigma_tauBH - sigma_i_barre_BH; // ne sert que dans Sigma_point
// calcul de QdeltaSigma: on prend la valeur absolue car dans les petits nombres on peut avoir des presques 0 !!
// négatifs qui conduisent à une racine infinie !!
double QdeltaSigma = sqrt(delta_sigma_barre_R_a_tauBH.II());
//modif : 1 juin 2014
// on vérifie que l'amplitude de la contrainte transmise, n'est pas supérieure à la saturation
// on fait la vérification sur le delta, car si on est sur une branche non initiale, on peut très bien
// dépasser le Qzero, localement, mais ce sera invalidé ensuite avec l'algo de coincidence
if ( QdeltaSigma > (Qzero*depassement_Q0*wBase))
{erreur = 1;
//--- pour le debug
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
cout << "\n QdeltaSigma =" << QdeltaSigma << " au lieu de "<< (Qzero*depassement_Q0*wBase)
<< " Hysteresis3D::Sigma_point " << endl ;
//--- fin debug
}
else // sinon on continue
{ erreur = 0;
};
};
// update des différentes énergies sur le pas de temps ou la partie de pas de temps effectué
// et calcul de defEqui finalisée
void Hysteresis3D::UpdateEnergieHyste(EnergieMeca & energ
,const Tenseur3BH & sigma_deb_BH,const Tenseur3BH & sigma_fin_BH
,const Tenseur3BH & delta_sigma_sur_tau_BH
,const Tenseur3BH & delta_sigma_R_tau_BH
,const double& phi_2_dt
,const Tenseur3BH & delta_eps_sur_deltaTau_BH,double& QdeltaSigmaRatdt
,const double& wprime,const double& w_prime_point,const bool& trajet_neutre
,const double& def_equi_R,const double& def_i_equi, double& def_equi)
{ // delta tau = 1 ici, en fait c'est un paramètre formel
// double delta_ener_interne = - 0.5*((sigma_deb_BH + sigma_fin_BH) && delta_eps_sur_deltaTau_BH);
double delta_ener_interne = - (sigma_fin_BH && delta_eps_sur_deltaTau_BH);
// -------- débug au cas où -----------
//if (phi_2_dt < 0)
// cout << "\n attention, phi_2_dt = " << phi_2_dt << " est negatif ??, normalement, a l'issue d'une convergence"
// << " phi est positif ou nul , a regarder en debug "
// << "\n Hysteresis3D::UpdateEnergieHyste(.... ";
// ------- fin débug --------
if (trajet_neutre)
{// -- calcul du delta énergie interne
// a priori ici tout est élastique: phi = 0, tau_C=0,
// -- calcul du taux fondamental C (formule thèse Mayssa Chache p. 71: formule 2.51, avec les formules
// 2.52, )
// calcul de la déformation équivalente
def_equi = def_i_equi ;
// -- delta énergies : on considère un tau C constant sur l'incrément de temps ainsi que phi
double delta_energie_elastique = - delta_ener_interne ;
double delta_energie_frotteurs = 0.;
EnergieMeca delta_ener(delta_energie_elastique,delta_energie_frotteurs,0.);
energ += delta_ener;
}
else
{// -- calcul du delta énergie interne
// -- calcul du taux fondamental C (formule thèse Mayssa Chache p. 71: formule 2.51, avec les formules
// 2.52, )
double unsurwprime = 1./wprime;
// si QdeltaSigmaRatdt est très petit on considère qu'il n'y a qu'un calcul élastique, pas de dissipation
// on plus simple on considère que la def équivalente ne bouge pas
if (QdeltaSigmaRatdt >= ConstMath::petit )
{ double unsurQdeltaSigma=1./QdeltaSigmaRatdt;
def_equi = def_i_equi + unsurwprime * phi_2_dt * unsurQdeltaSigma;
double def_equi_Ratdt = def_equi-def_equi_R;
// calcul de QpointDeltaSigma
double QpointDeltaSigma = unsurQdeltaSigma * (delta_sigma_R_tau_BH && delta_sigma_sur_tau_BH);
// calcul du tau_C qui représente en fait : delta_R^tdt eps : sigma_point
double tau_C = (wprime * QpointDeltaSigma - w_prime_point * QdeltaSigmaRatdt) * def_equi_Ratdt;
// -- delta énergies : on considère un tau C constant sur l'incrément de temps ainsi que phi
double delta_energie_elastique = - delta_ener_interne - unsurwprime * phi_2_dt + unsurwprime * tau_C;
double delta_energie_frotteurs = unsurwprime * ( phi_2_dt - tau_C);
// si l'énergie des frotteurs est négative, on considère que c'est due aux différentes imprécisions,
// comme je ne vois pas de solution, donc
// on la met à 0, et on modifie le tau_C en conséquence, et donc
// on recalcule l'énergie élastique en conséquence, ce qui conduit, tout calcul fait à un trajet
// purement élastique ( finalement idem que neutre ??)
if (delta_energie_frotteurs < 0.)
{ delta_energie_frotteurs = 0.;
delta_energie_elastique = - delta_ener_interne;
}
//-----pour le debug
// if (delta_energie_frotteurs < 0.)
// cout << "\n (1) delta_energie_frotteurs= " << delta_energie_frotteurs << endl;
// ----- fin débug
// si l'énergie frotteur est négative, on considère que c'est due à une erreur d'arrondie, on met 0 à la place
// if (delta_energie_frotteurs < 0.)
// delta_energie_frotteurs = 0.;
EnergieMeca delta_ener(delta_energie_elastique,delta_energie_frotteurs,0.);
energ += delta_ener;
}
else
{ // cas où l'accroissement de sigma est trop faible donc considéré nul
// on a sigma_point = delta_sigma/delta_t, avec ici delta_t=1 donc delta_sigma = 0 => sigma_point=0
// comme en fait : tau_C= delta_R^(t+deltat) eps : sigma_point, on a tau_C = 0
// on considère donc tau_C = 0
double delta_energie_elastique = - delta_ener_interne - unsurwprime * phi_2_dt ;
double delta_energie_frotteurs = unsurwprime * ( phi_2_dt );
//-----pour le debug
if ( ((Permet_affichage()==0) && (ParaGlob::NiveauImpression() > 5)) || (Permet_affichage() > 5))
if (delta_energie_frotteurs < 0)
cout << "\n (2) delta_energie_frotteurs= " << delta_energie_frotteurs << endl;
// ----- fin débug
EnergieMeca delta_ener(delta_energie_elastique,delta_energie_frotteurs,0.);
energ += delta_ener;
};
//-------- ancien calcul en commentaire -------
// double unsurQdeltaSigma= ConstMath::grand; // on limite la valeur par exemple pour le démarrage
// if (QdeltaSigmaRatdt >= ConstMath::petit) unsurQdeltaSigma=1./QdeltaSigmaRatdt;
// // calcul de la déformation équivalente
// def_equi = def_equi_R + unsurwprime * phi_2_dt * unsurQdeltaSigma;
// // calcul de QpointDeltaSigma
// double QpointDeltaSigma = unsurQdeltaSigma * (delta_sigma_R_tau_BH && delta_sigma_sur_tau_BH);
// calcul du tau_C qui représente en fait : delta_R^tdt eps : sigma_point
// double tau_C = (wprime * QpointDeltaSigma - w_prime_point * QdeltaSigmaRatdt) * def_equi;
// -- delta énergies : on considère un tau C constant sur l'incrément de temps ainsi que phi
// double delta_energie_elastique = - delta_ener_interne - unsurwprime * phi_2_dt + unsurwprime * tau_C;
// double delta_energie_frotteurs = unsurwprime * ( phi_2_dt - tau_C);
// EnergieMeca delta_ener(delta_energie_elastique,delta_energie_frotteurs,0.);
// energ += delta_ener;
//-------- fin ancien calcul en commentaire -------
};
};
// vérif de la coïncidence: prog de mise au point
// premiere_fois: comme il y a une récursion, pour arrêter la boucle infinie
void Hysteresis3D::Verif_coincidence(const Tenseur3BB & delta_epsBB,const Tenseur3HH & gijHH
,const Tenseur3BB & gijBB,int cas,SaveResulHysteresis3D & save_resul
,Tenseur3HH & sigHH,const EnergieMeca & energ_t,EnergieMeca & energ
,bool premiere_fois)
{
// l'objectif est ici de vérifier que l'on a bien la position de la nouvelle contrainte cohérente avec
// le rayon de référence
// --- 1ere étape, récupérer les infos de position de référence qui vont-être enregistrées
Tenseur3BH sigBH_de_ref; Tenseur3BH centreBH_de_ref; // init à 0 par défaut
int aucun_pt_inv=false;
switch (save_resul.modif)
{ case 0: // rien ne change sur le pas en terme de coincidence et d'inversion
{ if(save_resul.sigma_barre_BH_R.begin() != save_resul.sigma_barre_BH_R.end())
{sigBH_de_ref = *(save_resul.sigma_barre_BH_R.begin());}
else aucun_pt_inv=true;
if(save_resul.oc_BH_R.begin() != save_resul.oc_BH_R.end())
centreBH_de_ref = *(save_resul.oc_BH_R.begin());
break;
}
case 1: // cas où l'on a une ou plusieurs coincidences
{ // a chaque coincidence il faudra supprimer 1 pt de ref et un centre de cercle
// sauf si l'on arrive au centre nul ou au point de référence null
List_io <Tenseur3BH>::iterator itens;List_io <Tenseur3BH>::iterator ioc_i;
itens = save_resul.sigma_barre_BH_R.begin(); ioc_i = save_resul.oc_BH_R.begin();
for (int i=1;i<=save_resul.nb_coincidence;i++)
{ if (itens != save_resul.sigma_barre_BH_R.end()) // si itens == sigma_barre_BH_R.end(), cela signifie
itens++; // que la référence est le tenseur nulle, on arrête de dépiler
if (ioc_i != save_resul.oc_BH_R.end()) // si ioc_i == oc_BH_R.end(), cela signifie que le centre de référence
ioc_i++; // est le tenseur nulle
};
if(itens != save_resul.sigma_barre_BH_R.end())
{sigBH_de_ref = *(itens);}
else aucun_pt_inv=true;
if (ioc_i != save_resul.oc_BH_R.end())
centreBH_de_ref = *(ioc_i);
break;
}
case 2: // cas où l'on a une ou plusieurs inversions
{ // on traite les centres différement des points d'inversions
// --- cas des centres ---
if (save_resul.oc_BH_t_a_tdt.size() != 0)
{centreBH_de_ref = *(save_resul.oc_BH_t_a_tdt.begin());} // on récupère le premier
else if (save_resul.oc_BH_R.size() != 0)
{centreBH_de_ref = *(save_resul.oc_BH_R.begin());}; // on récupère le premier
// sinon tous les centres sont nuls on utilise le centre de départ initialisé à 0
// --- cas des ref ---
if (save_resul.sigma_barre_BH_R_t_a_tdt.size() != 0)
{sigBH_de_ref = *(save_resul.sigma_barre_BH_R_t_a_tdt.begin());}
else if (save_resul.sigma_barre_BH_R.size() != 0)
{sigBH_de_ref = *(save_resul.sigma_barre_BH_R.begin());}
else aucun_pt_inv=true;
break;
}
case 3: // cas où l'on a une ou plusieurs coincidence(s) et inversion (s)
{ // on traite les centres différement des points d'inversions
// --- cas des centres ---
if (save_resul.oc_BH_t_a_tdt.size() != 0) // cas on ajoutera des inversions
{centreBH_de_ref = *(save_resul.oc_BH_t_a_tdt.begin());} // on récupère le premier
else // cas où on a déjà une coincidence et pas d'inversion
{ List_io <Tenseur3BH>::iterator ioc_i = save_resul.oc_BH_R.begin();
for (int i=1;i<=save_resul.nb_coincidence;i++)
if (ioc_i != save_resul.oc_BH_R.end()) // si ioc_i == oc_BH_R.end(), cela signifie que le centre de référence
ioc_i++; // est le tenseur nulle
if (ioc_i != save_resul.oc_BH_R.end())
centreBH_de_ref = *(ioc_i);
};
// --- cas des références ----
if (save_resul.sigma_barre_BH_R_t_a_tdt.size() != 0)
{sigBH_de_ref = *(save_resul.sigma_barre_BH_R_t_a_tdt.begin());}
else // cas où on a déjà une coincidence et pas d'inversion
{ List_io <Tenseur3BH>::iterator itens = save_resul.sigma_barre_BH_R.begin();
for (int i=1;i<=save_resul.nb_coincidence;i++)
if (itens != save_resul.sigma_barre_BH_R.end()) // si itens == sigma_barre_BH_R.end(), cela signifie
itens++; // que la référence est le tenseur nulle, on arrête de dépiler
if(itens != save_resul.sigma_barre_BH_R.end())
{sigBH_de_ref = *(itens);}
else aucun_pt_inv=true;
};
break;
}
default:
cout << "\n erreur modif= " << save_resul.modif
<< "\n Hysteresis3D::Verif_coincidence(... ";
// on génère une exception
throw ErrNonConvergence_loiDeComportement();
Sortie(1);
}
// --- calcul du rayon de Oi à R sigBH_de_ref
Tenseur3BH ddelta_sigma_barre_BH_OiaR = sigBH_de_ref - centreBH_de_ref; // le tenseur rayon
// calcul du rayon: la première fois le rayon est infini
double QQ_OiaR=0.;
if (aucun_pt_inv) {QQ_OiaR = ConstMath::tresgrand;}
else {QQ_OiaR = sqrt(ddelta_sigma_barre_BH_OiaR.II());};
// --- calcul du nouveau rayon ----
Tenseur3BH delta_sigma_oi_a_tdt_BH = save_resul.sigma_barre_BH_tdt - centreBH_de_ref; // OA
double rayon_tdt = sqrt(delta_sigma_oi_a_tdt_BH.II());
// ---- vérif ---
if (rayon_tdt > QQ_OiaR) // cas d'un inchoérence
{ cout << "\n *********** inchoerence de coincidence ";
if (Ptintmeca_en_cours() != NULL) Ptintmeca_en_cours()->Signature();cout << flush;
// re-appel de l'algo pour passer en débug dedans
// initialisation des variables de travail
save_resul.Init_debut_calcul();
// initialisation éventuelle des variables thermo-dépendantes
Init_thermo_dependance();
// vérif de l'emboitement
save_resul.Verif_centre_reference(Permet_affichage());
// re-calcul pour vérif pas à pas
Avancement_temporel(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ);
if (premiere_fois)
{premiere_fois = false;
Verif_coincidence(delta_epsBB,gijHH,gijBB,cas,save_resul,sigHH,energ_t,energ,premiere_fois);
};
// on génère une exception
throw ErrNonConvergence_loiDeComportement();
Sortie(1);
};
};
// vérif de la cohérence des centres et références: les rayons associés doivent être de taille
// décroissante
void Hysteresis3D::SaveResulHysteresis3D::Verif_centre_reference(const int &permet_affichage)
{ // on va balayer les différents centres et points de références, pour construire les différents rayons
// qui devront être de tailles croissantes à partir du premier
double rayon_precedent = 0.; List_io <double> les_rayons;
List_io <Tenseur3BH>::iterator itens,itens_fin = sigma_barre_BH_R.end();
List_io <Tenseur3BH>::iterator ioc_i,ioc_i_fin = oc_BH_R.end();
for (itens=sigma_barre_BH_R.begin(), ioc_i = oc_BH_R.begin();
itens != itens_fin; itens++,ioc_i++)
{double rayon = 0;
if (ioc_i != ioc_i_fin)
{ Tenseur3BH dsigmaBH = *itens - *ioc_i;
rayon = sqrt(dsigmaBH.II());
}
else
{ Tenseur3BH dsigmaBH = *itens;
rayon = sqrt(dsigmaBH.II());
}
les_rayons.push_front(rayon);
if (rayon >= rayon_precedent)
{ rayon_precedent = rayon;}
else
{ cout << "\n ---- ******* attention la croissance des rayons n'est pas verifiee !! " ;
if ( ((permet_affichage==0) && (ParaGlob::NiveauImpression() > 5)) || (permet_affichage > 5))
{// les listes
cout << "\n save_resul.sigma_barre_BH_R_t_a_tdt= " << sigma_barre_BH_R_t_a_tdt;
cout << "\n save_resul.sigma_barre_BH_R= " << sigma_barre_BH_R;
cout << "\n save_resul.oc_BH_t_a_tdt= " << oc_BH_t_a_tdt;
cout << "\n save_resul.oc_BH_R= " << oc_BH_R;
cout << "\n les rayons= " << les_rayons;
// on vide le buffer
cout << endl;
};
// Sortie(1);
};
};
};